From afddf73c48d12515d44d11e959ac6d995fdbe61f Mon Sep 17 00:00:00 2001 From: Scala Steward <43047562+scala-steward@users.noreply.github.com> Date: Sun, 21 Apr 2024 02:55:49 +0200 Subject: [PATCH] Update scalafmt-core to 3.8.1 (#5501) * Update scalafmt-core to 3.8.1 * Update .scalafmt.conf settings to be factory default settings * Fix typo * scalafmt * Empty commit to re-run CI * Revert some scalafmt back to original scalafmt.conf --------- Co-authored-by: Chris Stewart --- .scalafmt.conf | 40 +- .../org/bitcoins/commons/DLCStatusTest.scala | 279 +-- .../bitcoins/commons/SerializedPSBTTest.scala | 31 +- .../commons/config/AppConfigTest.scala | 12 +- .../commons/json/AppServerCliJsonTest.scala | 6 +- .../json/DLCAcceptJsonSerializerTest.scala | 3 +- .../json/SpendingInfoDbSerializerTest.scala | 3 +- .../commons/util/ServerArgParserTest.scala | 2 +- .../bitcoins/commons/config/AppConfig.scala | 60 +- .../commons/config/AppConfigFactory.scala | 13 +- .../org/bitcoins/commons/file/FileUtil.scala | 40 +- .../jsonmodels/BitcoinSServerInfo.scala | 17 +- .../commons/jsonmodels/SerializedPSBT.scala | 39 +- .../jsonmodels/SerializedTransaction.scala | 79 +- .../bitcoind/BlockchainResult.scala | 116 +- .../jsonmodels/bitcoind/NetworkResult.scala | 44 +- .../jsonmodels/bitcoind/OtherResult.scala | 47 +- .../bitcoind/RawTransactionResult.scala | 42 +- .../commons/jsonmodels/bitcoind/RpcOpts.scala | 31 +- .../jsonmodels/bitcoind/RpcPsbtResult.scala | 4 +- .../jsonmodels/bitcoind/WalletResult.scala | 96 +- .../cli/ContractDescriptorParser.scala | 26 +- .../clightning/CLightningJsonModels.scala | 12 +- .../jsonmodels/eclair/EclairModels.scala | 101 +- .../commons/jsonmodels/lnd/LndModels.scala | 4 +- .../commons/jsonmodels/ws/WsModels.scala | 43 +- .../org/bitcoins/commons/rpc/Command.scala | 563 +++--- .../commons/serializers/JsonReaders.scala | 404 +++-- .../commons/serializers/JsonSerializers.scala | 173 +- .../commons/serializers/JsonWriters.scala | 63 +- .../commons/serializers/Picklers.scala | 358 ++-- .../commons/serializers/SerializerUtil.scala | 12 +- .../commons/serializers/WsPicklers.scala | 113 +- .../bitcoins/commons/util/DatadirParser.scala | 29 +- .../bitcoins/commons/util/DatadirUtil.scala | 10 +- .../commons/util/NativeProcessFactory.scala | 8 +- .../commons/util/ServerArgParser.scala | 21 +- .../src/main/scala/org/bitcoins/cli/Cli.scala | 3 +- .../scala/org/bitcoins/cli/CliReaders.scala | 29 +- .../scala/org/bitcoins/cli/ConsoleCli.scala | 655 ++++--- .../oracle/server/OracleRoutesSpec.scala | 278 +-- .../bitcoins/oracle/server/OracleRoutes.scala | 82 +- .../oracle/server/OracleServerMain.scala | 42 +- .../oracle/server/ServerJsonModels.scala | 126 +- .../org/bitcoins/scripts/ScanBitcoind.scala | 46 +- .../org/bitcoins/scripts/ZipDatadir.scala | 13 +- .../akkahttpupickle/UpickleSupport.scala | 18 +- .../server/routes/BitcoinSRunner.scala | 15 +- .../bitcoins/server/routes/CORSHandler.scala | 19 +- .../bitcoins/server/routes/CommonRoutes.scala | 4 +- .../bitcoins/server/routes/HttpError.scala | 5 +- .../org/bitcoins/server/routes/Server.scala | 35 +- .../server/util/AppConfigMarker.scala | 12 +- .../bitcoins/server/util/BitcoinSApp.scala | 4 +- .../bitcoins/server/util/ServerBindings.scala | 4 +- .../BitcoinSServerMainBitcoindTest.scala | 17 +- .../BitcoinSServerMainBitcoindTorTest.scala | 8 +- .../server/BitcoindRpcAppConfigTest.scala | 3 +- .../bitcoins/server/CallBackUtilTest.scala | 8 +- .../bitcoins/server/CommonRoutesSpec.scala | 3 +- .../org/bitcoins/server/DLCRoutesSpec.scala | 31 +- .../DLCWalletBitcoindBackendLoaderTest.scala | 19 +- .../org/bitcoins/server/RoutesSpec.scala | 1029 +++++++---- .../org/bitcoins/server/ServerRunTest.scala | 14 +- .../bitcoins/server/WalletRoutesSpec.scala | 33 +- .../org/bitcoins/server/WebsocketTests.scala | 205 ++- .../org/bitcoins/wallet/MockWalletApi.scala | 7 +- .../bitcoins/server/BitcoinSAppConfig.scala | 98 +- .../bitcoins/server/BitcoinSServerMain.scala | 217 ++- .../server/BitcoindRpcBackendUtil.scala | 259 +-- .../org/bitcoins/server/ChainRoutes.scala | 7 +- .../org/bitcoins/server/CoreRoutes.scala | 6 +- .../scala/org/bitcoins/server/DLCRoutes.scala | 33 +- .../bitcoins/server/DLCWalletLoaderApi.scala | 127 +- .../bitcoins/server/ServerJsonModels.scala | 64 +- .../org/bitcoins/server/WalletRoutes.scala | 274 +-- .../server/WalletZmqSubscribers.scala | 4 +- .../server/bitcoind/BitcoindSyncState.scala | 11 +- .../util/BitcoindPollingCancellabe.scala | 7 +- .../bitcoins/server/util/CallbackUtil.scala | 29 +- .../org/bitcoins/server/util/ChainUtil.scala | 7 +- .../util/WalletHolderWithLoaderApi.scala | 8 +- .../bitcoins/server/util/WebsocketUtil.scala | 55 +- .../org/bitcoins/asyncutil/AsyncUtil.scala | 132 +- .../org/bitcoins/bench/core/BlockBench.scala | 2 +- .../bitcoins/bench/eclair/EclairBench.scala | 60 +- .../bitcoins/bench/eclair/PaymentLog.scala | 41 +- .../bitcoins/rpc/BitcoindInstanceTest.scala | 22 +- .../org/bitcoins/rpc/TestRpcUtilTest.scala | 22 +- .../rpc/common/BlockchainRpcTest.scala | 12 +- .../bitcoins/rpc/common/MempoolRpcTest.scala | 16 +- .../bitcoins/rpc/common/MessageRpcTest.scala | 6 +- .../bitcoins/rpc/common/MiningRpcTest.scala | 13 +- .../rpc/common/MultiWalletRpcTest.scala | 54 +- .../bitcoins/rpc/common/MultisigRpcTest.scala | 14 +- .../rpc/common/RawTransactionRpcTest.scala | 38 +- .../org/bitcoins/rpc/common/UTXORpcTest.scala | 6 +- .../bitcoins/rpc/common/WalletRpcTest.scala | 123 +- .../rpc/config/BitcoindConfigTest.scala | 6 +- .../org/bitcoins/rpc/v18/PsbtRpcTest.scala | 28 +- .../rpc/v22/BitcoindV22RpcClientTest.scala | 51 +- .../rpc/v23/BitcoindV23RpcClientTest.scala | 3 +- .../rpc/v24/BitcoindV24RpcClientTest.scala | 57 +- .../org/bitcoins/rpc/BitcoindException.scala | 40 +- .../rpc/client/common/BitcoindRpcClient.scala | 139 +- .../rpc/client/common/BlockchainRpc.scala | 169 +- .../bitcoins/rpc/client/common/Client.scala | 152 +- .../rpc/client/common/DescriptorRpc.scala | 32 +- .../rpc/client/common/MempoolRpc.scala | 95 +- .../rpc/client/common/MessageRpc.scala | 21 +- .../rpc/client/common/MiningRpc.scala | 32 +- .../rpc/client/common/MultisigRpc.scala | 52 +- .../bitcoins/rpc/client/common/NodeRpc.scala | 15 +- .../bitcoins/rpc/client/common/P2PRpc.scala | 24 +- .../bitcoins/rpc/client/common/PsbtRpc.scala | 41 +- .../rpc/client/common/RawTransactionRpc.scala | 60 +- .../rpc/client/common/TransactionRpc.scala | 69 +- .../bitcoins/rpc/client/common/UTXORpc.scala | 39 +- .../bitcoins/rpc/client/common/UtilRpc.scala | 18 +- .../rpc/client/common/WalletRpc.scala | 307 ++-- .../rpc/client/v18/V18AssortedRpc.scala | 18 +- .../rpc/client/v20/V20AssortedRpc.scala | 12 +- .../rpc/client/v20/V20MultisigRpc.scala | 44 +- .../rpc/client/v22/BitcoindV22RpcClient.scala | 23 +- .../rpc/client/v22/TestMempoolAcceptRpc.scala | 7 +- .../rpc/client/v22/V22AssortedRpc.scala | 16 +- .../rpc/client/v23/BitcoindV23RpcClient.scala | 23 +- .../rpc/client/v24/BitcoindV24RpcClient.scala | 46 +- .../rpc/config/BitcoindAuthCredentials.scala | 48 +- .../bitcoins/rpc/config/BitcoindConfig.scala | 139 +- .../rpc/config/BitcoindInstance.scala | 101 +- .../rpc/config/BitcoindRpcAppConfig.scala | 62 +- .../org/bitcoins/rpc/config/ZmqConfig.scala | 33 +- .../util/AppConfigFactoryActorSystem.scala | 3 +- .../rpc/util/BitcoindStreamUtil.scala | 12 +- .../scala/org/bitcoins/rpc/util/RpcUtil.scala | 3 +- .../bitcoins/chain/ChainCallbacksTest.scala | 21 +- .../BitcoindChainHandlerViaZmqTest.scala | 11 +- .../chain/blockchain/BlockchainTest.scala | 26 +- .../blockchain/ChainHandlerCachedTest.scala | 77 +- .../chain/blockchain/ChainHandlerTest.scala | 354 ++-- .../blockchain/MainnetChainHandlerTest.scala | 128 +- .../chain/blockchain/sync/ChainSyncTest.scala | 50 +- .../blockchain/sync/FilterSyncTest.scala | 14 +- .../chain/config/ChainAppConfigTest.scala | 11 +- .../chain/models/BlockHeaderDAOTest.scala | 105 +- .../models/ChainStateDescriptorDAOTest.scala | 37 +- .../chain/models/CompactFilterDAOTest.scala | 3 +- .../models/CompactFilterHeaderDAOTest.scala | 6 +- .../bitcoins/chain/pow/BitcoinPowTest.scala | 30 +- .../chain/validation/TipValidationTest.scala | 8 +- .../org/bitcoins/chain/ChainCallbacks.scala | 103 +- .../chain/blockchain/BaseBlockChain.scala | 146 +- .../chain/blockchain/Blockchain.scala | 6 +- .../chain/blockchain/BlockchainUpdate.scala | 41 +- .../chain/blockchain/ChainException.scala | 15 +- .../chain/blockchain/ChainHandler.scala | 604 ++++--- .../chain/blockchain/ChainHandlerCached.scala | 49 +- .../chain/blockchain/ConnectTipResult.scala | 34 +- .../chain/blockchain/sync/ChainSync.scala | 83 +- .../chain/blockchain/sync/FilterSync.scala | 142 +- .../sync/FilterWithHeaderHash.scala | 11 +- .../chain/config/ChainAppConfig.scala | 44 +- .../bitcoins/chain/db/ChainDbManagement.scala | 4 +- .../chain/models/BlockHeaderDAO.scala | 249 +-- .../models/ChainStateDescriptorDAO.scala | 67 +- .../chain/models/CompactFilterDAO.scala | 72 +- .../chain/models/CompactFilterHeaderDAO.scala | 94 +- .../scala/org/bitcoins/chain/pow/Pow.scala | 36 +- .../chain/validation/TipUpdateResult.scala | 18 +- .../chain/validation/TipValidation.scala | 62 +- .../rpc/CLightningChannelOpenerTest.scala | 51 +- .../rpc/CLightningClientPairTest.scala | 41 +- .../rpc/CLightningJsonModelParsingTest.scala | 6 +- .../rpc/CLightningRpcClientTest.scala | 3 +- .../clightning/rpc/CLightningRpcClient.scala | 134 +- .../rpc/CLightningUnixSocketHandler.scala | 28 +- .../rpc/config/CLightningConfig.scala | 96 +- .../rpc/config/CLightningInstanceLocal.scala | 13 +- .../org/bitcoins/core/api/CallbackTest.scala | 11 +- .../dlc/testgen/ConstRandAdaptorSign.scala | 9 +- .../core/dlc/testgen/DLCFeeTestVector.scala | 10 +- .../dlc/testgen/DLCFeeTestVectorGen.scala | 13 +- .../dlc/testgen/DLCParsingTestVector.scala | 200 ++- .../dlc/testgen/DLCParsingTestVectorGen.scala | 3 +- .../bitcoins/core/dlc/testgen/DLCTLVGen.scala | 258 +-- .../core/dlc/testgen/DLCTestVector.scala | 98 +- .../core/dlc/testgen/DLCTestVectorGen.scala | 7 +- .../bitcoins/core/dlc/testgen/DLCTxGen.scala | 140 +- .../core/dlc/testgen/DLCTxTestVectorGen.scala | 6 +- .../testgen/SchnorrSigPointTestVector.scala | 63 +- .../SchnorrSigPointTestVectorGen.scala | 21 +- .../core/dlc/testgen/TestVectorGen.scala | 13 +- .../statictest/DLCFeeTestVectorTest.scala | 16 +- .../SchnorrSigPointTestVectorTest.scala | 7 +- .../testgen/statictest/TestVectorUtil.scala | 8 +- .../core/p2p/InetAddressJVMTest.scala | 7 +- .../transaction/LargeTransactionTest.scala | 2 +- .../transaction/TaprootTestCase.scala | 67 +- .../protocol/transaction/TaprootTxTests.scala | 15 +- .../transaction/TaprootWalletTestCase.scala | 15 +- .../TaprootWalletTestVectors.scala | 11 +- .../bitcoins/core/bloom/BloomFilterTest.scala | 118 +- .../core/config/NetworkParametersTest.scala | 4 +- .../bitcoins/core/consensus/MerkleTest.scala | 204 ++- .../org/bitcoins/core/crypto/ExtKeySpec.scala | 28 +- .../org/bitcoins/core/crypto/ExtKeyTest.scala | 216 ++- .../bitcoins/core/crypto/ExtSignTest.scala | 8 +- .../core/crypto/MnemonicCodeTest.scala | 73 +- .../TransactionSignatureCheckerTest.scala | 530 +++--- .../TransactionSignatureCreatorSpec.scala | 120 +- .../TransactionSignatureCreatorTest.scala | 298 ++-- .../TransactionSignatureSerializerTest.scala | 606 ++++--- .../core/crypto/TxSigComponentTest.scala | 40 +- .../core/crypto/WIFEncodingTest.scala | 35 +- .../core/crypto/bip32/BIP32PathTest.scala | 58 +- .../core/currency/CurrencyUnitTest.scala | 3 +- .../dlc/DLCAdaptorPointComputerTest.scala | 41 +- .../bitcoins/core/dlc/DLCValidationTest.scala | 81 +- .../core/dlc/DisjointUnionDLCTest.scala | 36 +- .../org/bitcoins/core/dlc/EnumDLCTest.scala | 17 +- .../bitcoins/core/dlc/NumericDLCTest.scala | 59 +- .../org/bitcoins/core/dlc/SetupDLCTest.scala | 38 +- .../dlc/accounting/DLCAccountingTest.scala | 12 +- .../core/dlc/models/OracleInfoTest.scala | 10 +- .../bitcoins/core/gcs/BlockFilterTest.scala | 26 +- .../bitcoins/core/gcs/FilterTypeTest.scala | 3 +- .../scala/org/bitcoins/core/gcs/GCSTest.scala | 8 +- .../bitcoins/core/gcs/GolombFilterTest.scala | 15 +- .../org/bitcoins/core/hd/HDAccountTest.scala | 12 +- .../org/bitcoins/core/hd/HDPathTest.scala | 177 +- .../org/bitcoins/core/number/Int64Test.scala | 91 +- .../org/bitcoins/core/number/UInt16Test.scala | 3 +- .../org/bitcoins/core/number/UInt32Test.scala | 2 +- .../org/bitcoins/core/number/UInt64Test.scala | 42 +- .../p2p/CompactFilterHeadersMessageTest.scala | 108 +- .../core/p2p/FilterLoadMessageTest.scala | 36 +- .../core/p2p/GetHeadersMessageTest.scala | 3 +- .../core/p2p/MerkleBlockMessageTest.scala | 12 +- .../bitcoins/core/p2p/NetworkHeaderTest.scala | 19 +- .../core/p2p/NetworkMessageTest.scala | 15 +- .../core/p2p/NetworkPayloadTest.scala | 6 +- .../core/p2p/ServiceIdentifierTest.scala | 34 +- .../core/p2p/TypeIdentifierTest.scala | 4 +- .../core/p2p/VersionMessageTest.scala | 3 +- .../bitcoins/core/protocol/AddressTest.scala | 3 +- .../bitcoins/core/protocol/Bech32Test.scala | 100 +- .../bitcoins/core/protocol/Bech32mTest.scala | 147 +- .../core/protocol/BigSizeUIntTest.scala | 39 +- .../core/protocol/BitcoinAddressTest.scala | 18 +- .../core/protocol/CompactSizeUIntTest.scala | 37 +- .../protocol/blockchain/ChainParamsTest.scala | 144 +- .../blockchain/MerkleBlockTests.scala | 279 ++- .../blockchain/PartialMerkleTreeTests.scala | 334 ++-- .../protocol/dlc/AdditionTrieNodeTest.scala | 5 +- .../core/protocol/dlc/CETCalculatorTest.scala | 326 ++-- .../protocol/dlc/ContractDescriptorTest.scala | 43 +- .../protocol/dlc/ContractOraclePairTest.scala | 46 +- .../core/protocol/dlc/DLCMessageTest.scala | 23 +- .../protocol/dlc/DLCPayoutCurveTest.scala | 148 +- .../core/protocol/dlc/DLCUtilTest.scala | 15 +- .../protocol/dlc/RoundingIntervalsTest.scala | 15 +- .../protocol/ln/LnHumanReadablePartTest.scala | 36 +- .../protocol/ln/LnInvoiceSignatureTest.scala | 8 +- .../core/protocol/ln/LnInvoiceUnitTest.scala | 292 +-- .../ln/channel/ShortChannelIdTest.scala | 18 +- .../ln/currency/LnCurrencyUnitTest.scala | 7 +- .../ln/currency/MilliSatoshisTest.scala | 6 +- .../script/CLTVScriptPubKeyTest.scala | 26 +- .../protocol/script/CSVScriptPubKeyTest.scala | 26 +- .../script/ConditionalScriptPubKeyTest.scala | 6 +- .../ConditionalScriptSignatureTest.scala | 7 +- .../script/LockTimeScriptSignatureTest.scala | 3 +- .../MultiSignatureScriptPubKeyTest.scala | 16 +- .../MultiSignatureScriptSignatureTest.scala | 4 +- .../script/P2PKHScriptSignatureTest.scala | 15 +- .../script/P2PKScriptPubKeyTest.scala | 7 +- .../script/P2PKScriptSignatureTest.scala | 9 +- .../script/P2SHScriptSignatureTest.scala | 25 +- .../script/P2WSHWitnessSPKV0Test.scala | 8 +- .../script/ScriptPubKeyFactoryTest.scala | 2 +- .../protocol/script/ScriptPubKeyTest.scala | 34 +- .../script/ScriptSignatureFactoryTest.scala | 2 +- .../protocol/script/ScriptSignatureTest.scala | 77 +- .../protocol/script/ScriptWitnessSpec.scala | 6 +- .../protocol/script/TaprootWitnessTest.scala | 31 +- .../script/WitnessCommitmentTest.scala | 5 +- .../script/WitnessScriptPubKeySpec.scala | 8 +- .../descriptor/DescriptorChecksumTest.scala | 21 +- .../script/descriptor/DescriptorTest.scala | 49 +- .../script/descriptor/KeyExpressionTest.scala | 8 +- .../testprotocol/SignatureHashTestCase.scala | 20 +- .../protocol/tlv/EventDescriptorTest.scala | 65 +- .../core/protocol/tlv/LnMessageTest.scala | 23 +- .../bitcoins/core/protocol/tlv/TLVTest.scala | 14 +- .../transaction/TransactionInputTest.scala | 6 +- .../transaction/TransactionOutPointTest.scala | 6 +- .../transaction/TransactionTest.scala | 176 +- .../protocol/transaction/TxUtilTest.scala | 35 +- .../CoreTransactionTestCase.scala | 43 +- .../core/psbt/PSBTSerializerTest.scala | 59 +- .../org/bitcoins/core/psbt/PSBTTest.scala | 72 +- .../org/bitcoins/core/psbt/PSBTUnitTest.scala | 285 ++- .../script/ScriptProgramFactoryTest.scala | 3 +- .../core/script/ScriptProgramTest.scala | 14 +- .../ArithmeticInterpreterTest.scala | 309 ++-- .../bitwise/BitwiseInterpreterTest.scala | 66 +- .../BitwiseOperationsFactoryTest.scala | 3 +- .../BytesToPushOntoStackFactoryTest.scala | 9 +- .../constant/ConstantInterpreterTest.scala | 65 +- .../constant/ScriptNumberUtilTest.scala | 57 +- .../ControlOperationsInterpreterTest.scala | 362 ++-- .../script/crypto/CryptoInterpreterTest.scala | 135 +- ...CryptoSignatureEvaluationFactoryTest.scala | 13 +- .../script/flag/ScriptFlagFactoryTest.scala | 15 +- .../core/script/flag/ScriptFlagUtilTest.scala | 9 +- .../interpreter/ScriptInterpreterTest.scala | 89 +- .../testprotocol/CoreTestCase.scala | 103 +- .../ScriptPubKeyCoreTestCase.scala | 15 +- .../ScriptSignatureCoreTestCase.scala | 19 +- .../locktime/LockTimeInterpreterTest.scala | 252 ++- .../LocktimeOperationFactoryTest.scala | 3 +- .../script/splice/SpliceInterpreterTest.scala | 41 +- .../script/stack/StackInterpreterTest.scala | 504 ++++-- .../stack/StackOperationFactoryTest.scala | 3 +- .../serializers/RawSerializerHelperSpec.scala | 10 +- .../RawBlockHeaderSerializerTest.scala | 19 +- .../blockchain/RawBlockSerializerTest.scala | 30 +- .../RawMerkleBlockSerializerTest.scala | 241 ++- .../RawNetworkHeaderSerializerTest.scala | 6 +- .../RawAddrMessageSerializerTest.scala | 4 +- .../RawAddrV2MessageSerializerTest.scala | 108 +- ...ilterCheckPointMessageSerializerTest.scala | 19 +- ...ctFilterHeadersMessageSerializerTest.scala | 22 +- ...awCompactFilterMessageSerializerTest.scala | 16 +- .../RawFilterAddMessageSerializerTest.scala | 5 +- .../RawFilterLoadMessageSerializerTest.scala | 4 +- .../RawGetBlocksMessageSerializerTest.scala | 16 +- ...ilterCheckpointMessageSerializerTest.scala | 16 +- ...ctFilterHeadersMessageSerializerTest.scala | 11 +- ...tCompactFiltersMessageSerializerTest.scala | 12 +- .../RawGetDataMessageSerializerTest.scala | 16 +- .../RawGetHeadersMessageSerializerTest.scala | 4 +- .../RawHeadersMessageSerializerTest.scala | 36 +- .../RawInventoryMessageSerializerTest.scala | 4 +- .../messages/RawInventorySerializerTest.scala | 8 +- .../RawMerkleBlockMessageSerializerTest.scala | 38 +- .../RawNetworkIpAddressSerializerTest.scala | 4 +- .../RawNotFoundMessageSerializerTest.scala | 8 +- .../RawRejectMessageSerializerTest.scala | 5 +- .../RawTransactionMessageSerializerTest.scala | 7 +- .../RawVersionMessageSerializerTest.scala | 20 +- .../script/RawScriptPubKeyParserTest.scala | 26 +- .../script/RawScriptSignatureParserTest.scala | 49 +- .../serializers/script/ScriptParserTest.scala | 182 +- .../RawBaseTransactionParserTest.scala | 21 +- .../RawTransactionInputParserTest.scala | 42 +- .../RawTransactionOutPointParserTest.scala | 20 +- .../RawTransactionOutputParserTest.scala | 20 +- .../org/bitcoins/core/util/Base58Test.scala | 24 +- .../bitcoins/core/util/BinaryTreeTest.scala | 139 +- .../bitcoins/core/util/BitcoinSUtilSpec.scala | 12 +- .../bitcoins/core/util/BitcoinSUtilTest.scala | 22 +- .../core/util/BitcoinScriptUtilTest.scala | 163 +- .../bitcoins/core/util/FutureUtilTest.scala | 14 +- .../bitcoins/core/util/NetworkUtilTest.scala | 45 +- .../bitcoins/core/util/NumberUtilTest.scala | 28 +- .../core/util/OrderedNoncesTest.scala | 6 +- .../util/OrderedSchnorrSignaturesTest.scala | 12 +- .../core/util/ScriptProgramTestUtil.scala | 14 +- .../bitcoins/core/util/SortedVecTest.scala | 72 +- .../testprotocol/Base58ValidTestCase.scala | 20 +- .../core/util/testprotocol/ConfigParams.scala | 3 +- .../core/wallet/CoinSelectorTest.scala | 122 +- .../wallet/builder/RawTxFinalizerTest.scala | 137 +- .../core/wallet/builder/RawTxSignerTest.scala | 224 ++- ...ShufflingNonInteractiveFinalizerTest.scala | 156 +- .../StandardNonInteractiveFinalizerTest.scala | 127 +- .../core/wallet/fee/FeeUnitTest.scala | 43 +- .../core/wallet/signer/SignerTest.scala | 171 +- .../core/wallet/utxo/AddressTagTest.scala | 18 +- .../core/wallet/utxo/InputInfoTest.scala | 55 +- .../wallet/utxo/InputSigningInfoTest.scala | 62 +- .../core/wallet/utxo/TxoStateTest.scala | 6 +- .../bitcoins/core/compat/CompactPackage.scala | 11 +- .../org/bitcoins/core/api/Callback.scala | 18 +- .../bitcoins/core/api/CallbackConfig.scala | 3 +- .../core/api/asyncutil/AsyncUtilApi.scala | 4 +- .../bitcoins/core/api/chain/ChainApi.scala | 107 +- .../core/api/chain/ChainQueryApi.scala | 28 +- .../core/api/chain/FilterSyncMarker.scala | 14 +- .../core/api/chain/db/BlockHeaderDb.scala | 9 +- .../core/api/chain/db/CompactFilterDb.scala | 24 +- .../api/chain/db/CompactFilterHeaderDb.scala | 6 +- .../core/api/commons/InstanceFactory.scala | 7 +- .../bitcoins/core/api/db/DbRowAutoInc.scala | 9 +- .../core/api/dlc/node/DLCNodeApi.scala | 10 +- .../core/api/dlc/wallet/DLCWalletApi.scala | 106 +- .../core/api/dlc/wallet/db/DLCDb.scala | 12 +- .../dlc/wallet/db/IncomingDLCOfferDb.scala | 15 +- .../core/api/dlcoracle/DLCOracleApi.scala | 66 +- .../core/api/dlcoracle/OracleEvent.scala | 136 +- .../core/api/dlcoracle/db/EventDb.scala | 13 +- .../api/dlcoracle/db/EventOutcomeDb.scala | 6 +- .../core/api/dlcoracle/db/RValueDb.scala | 9 +- .../api/keymanager/KeyManagerCreateApi.scala | 47 +- .../org/bitcoins/core/api/node/NodeApi.scala | 3 +- .../org/bitcoins/core/api/node/Peer.scala | 6 +- .../core/api/node/PeerManagerApi.scala | 18 +- .../core/api/tor/Socks5ProxyParams.scala | 13 +- .../core/api/wallet/AddressInfo.scala | 7 +- .../core/api/wallet/CoinSelectionAlgo.scala | 30 +- .../core/api/wallet/CoinSelector.scala | 152 +- .../core/api/wallet/CoinSelectorUtxo.scala | 13 +- .../core/api/wallet/HDWalletApi.scala | 185 +- .../core/api/wallet/NeutrinoWalletApi.scala | 68 +- .../core/api/wallet/ProcessTxResult.scala | 3 +- .../bitcoins/core/api/wallet/WalletApi.scala | 201 ++- .../api/wallet/WalletStateDescriptor.scala | 3 +- .../core/api/wallet/db/AccountDb.scala | 10 +- .../core/api/wallet/db/AddressDb.scala | 42 +- .../core/api/wallet/db/AddressRecord.scala | 107 +- .../core/api/wallet/db/AddressTagDb.scala | 3 +- .../api/wallet/db/IncomingTransactionDb.scala | 10 +- .../api/wallet/db/OutgoingTransactionDb.scala | 28 +- .../core/api/wallet/db/ScriptPubKeyDb.scala | 4 +- .../core/api/wallet/db/SpendingInfoDb.scala | 115 +- .../core/api/wallet/db/TransactionDb.scala | 107 +- .../core/api/wallet/db/UTXORecord.scala | 20 +- .../org/bitcoins/core/bloom/BloomFilter.scala | 212 ++- .../org/bitcoins/core/bloom/BloomFlag.scala | 14 +- .../core/config/NetworkParameters.scala | 45 +- .../bitcoins/core/consensus/Consensus.scala | 3 +- .../org/bitcoins/core/consensus/Merkle.scala | 49 +- .../org/bitcoins/core/crypto/BIP39Seed.scala | 31 +- .../org/bitcoins/core/crypto/ChainCode.scala | 6 +- .../core/crypto/ECPrivateKeyUtil.scala | 40 +- .../org/bitcoins/core/crypto/ExtKey.scala | 170 +- .../bitcoins/core/crypto/ExtKeyVersion.scala | 68 +- .../org/bitcoins/core/crypto/ExtSign.scala | 17 +- .../bitcoins/core/crypto/MnemonicCode.scala | 59 +- .../crypto/TaprootSerializationOptions.scala | 17 +- .../crypto/TransactionSignatureChecker.scala | 270 +-- .../TransactionSignatureCheckerResult.scala | 38 +- .../crypto/TransactionSignatureCreator.scala | 123 +- .../TransactionSignatureSerializer.scala | 270 +-- .../bitcoins/core/crypto/TxSigComponent.scala | 229 ++- .../core/currency/CurrencyUnits.scala | 15 +- .../core/dlc/accounting/DLCAccounting.scala | 4 +- .../dlc/accounting/DLCWalletAccounting.scala | 7 +- .../dlc/accounting/PayoutAccounting.scala | 6 +- .../dlc/accounting/RateOfReturnUtil.scala | 7 +- .../org/bitcoins/core/gcs/BlockFilter.scala | 31 +- .../core/gcs/BlockFilterMatcher.scala | 15 +- .../org/bitcoins/core/gcs/FilterHeader.scala | 16 +- .../org/bitcoins/core/gcs/FilterType.scala | 9 +- .../scala/org/bitcoins/core/gcs/GCS.scala | 70 +- .../org/bitcoins/core/gcs/GolombFilter.scala | 15 +- .../org/bitcoins/core/hd/AddressType.scala | 4 +- .../org/bitcoins/core/hd/BIP32Path.scala | 60 +- .../org/bitcoins/core/hd/HDAccount.scala | 16 +- .../org/bitcoins/core/hd/HDAddress.scala | 16 +- .../scala/org/bitcoins/core/hd/HDChain.scala | 4 +- .../org/bitcoins/core/hd/HDChainType.scala | 20 +- .../scala/org/bitcoins/core/hd/HDCoin.scala | 6 +- .../org/bitcoins/core/hd/HDCoinType.scala | 14 +- .../scala/org/bitcoins/core/hd/HDPath.scala | 12 +- .../org/bitcoins/core/hd/HDPathFactory.scala | 46 +- .../org/bitcoins/core/hd/HDPurpose.scala | 35 +- .../org/bitcoins/core/hd/LegacyHDPath.scala | 6 +- .../org/bitcoins/core/hd/MultisigHDPath.scala | 6 +- .../bitcoins/core/hd/NestedSegWitHDPath.scala | 6 +- .../org/bitcoins/core/hd/SegWitHDPath.scala | 6 +- .../scala/org/bitcoins/core/hd/package.scala | 13 +- .../core/number/BasicArithmetic.scala | 21 +- .../bitcoins/core/number/NumberCache.scala | 17 +- .../org/bitcoins/core/number/NumberType.scala | 124 +- .../org/bitcoins/core/p2p/InetAddress.scala | 9 +- .../org/bitcoins/core/p2p/Inventory.scala | 11 +- .../org/bitcoins/core/p2p/NetworkHeader.scala | 58 +- .../bitcoins/core/p2p/NetworkIpAddress.scala | 62 +- .../bitcoins/core/p2p/NetworkMessage.scala | 24 +- .../bitcoins/core/p2p/NetworkPayload.scala | 781 ++++---- .../bitcoins/core/p2p/ProtocolVersion.scala | 79 +- .../bitcoins/core/p2p/ServiceIdentifier.scala | 132 +- .../bitcoins/core/p2p/TypeIdentifier.scala | 41 +- .../scala/org/bitcoins/core/package.scala | 12 +- .../org/bitcoins/core/policy/Policy.scala | 18 +- .../org/bitcoins/core/protocol/Address.scala | 177 +- .../core/protocol/AddressFactory.scala | 8 +- .../bitcoins/core/protocol/BigSizeUInt.scala | 9 +- .../bitcoins/core/protocol/BlockStamp.scala | 16 +- .../core/protocol/BtcHumanReadablePart.scala | 10 +- .../core/protocol/CompactSizeUInt.scala | 48 +- .../core/protocol/blockchain/Block.scala | 25 +- .../protocol/blockchain/BlockHeader.scala | 152 +- .../protocol/blockchain/ChainParams.scala | 258 ++- .../protocol/blockchain/MerkleBlock.scala | 57 +- .../blockchain/PartialMerkleTree.scala | 307 ++-- .../protocol/dlc/build/DLCCETBuilder.scala | 30 +- .../protocol/dlc/build/DLCTxBuilder.scala | 278 +-- .../protocol/dlc/compute/CETCalculator.scala | 451 +++-- .../dlc/compute/DLCAdaptorPointComputer.scala | 61 +- .../core/protocol/dlc/compute/DLCUtil.scala | 147 +- .../protocol/dlc/compute/SigningVersion.scala | 13 +- .../protocol/dlc/execution/DLCExecutor.scala | 93 +- .../protocol/dlc/execution/DLCOutcome.scala | 8 +- .../protocol/dlc/execution/SetupDLC.scala | 12 +- .../dlc/models/ContractDescriptor.scala | 56 +- .../models/ContractDescriptorTemplate.scala | 65 +- .../protocol/dlc/models/ContractInfo.scala | 187 +- .../dlc/models/ContractOraclePair.scala | 32 +- .../protocol/dlc/models/DLCFundingInput.scala | 74 +- .../core/protocol/dlc/models/DLCMessage.scala | 124 +- .../protocol/dlc/models/DLCPayoutCurve.scala | 227 ++- .../protocol/dlc/models/DLCPublicKeys.scala | 12 +- .../protocol/dlc/models/DLCSignatures.scala | 17 +- .../core/protocol/dlc/models/DLCState.scala | 66 +- .../core/protocol/dlc/models/DLCStatus.scala | 59 +- .../protocol/dlc/models/DLCTemplate.scala | 33 +- .../protocol/dlc/models/DLCTimeouts.scala | 12 +- .../core/protocol/dlc/models/OracleInfo.scala | 157 +- .../protocol/dlc/models/OracleOutcome.scala | 42 +- .../dlc/models/OracleSignatures.scala | 84 +- .../dlc/models/RoundingIntervals.scala | 81 +- .../core/protocol/dlc/sign/DLCTxSigner.scala | 267 +-- .../dlc/verify/DLCSignatureVerifier.scala | 73 +- .../protocol/ln/LnHumanReadablePart.scala | 49 +- .../bitcoins/core/protocol/ln/LnInvoice.scala | 176 +- .../core/protocol/ln/LnInvoiceSignature.scala | 23 +- .../bitcoins/core/protocol/ln/LnParams.scala | 13 +- .../bitcoins/core/protocol/ln/LnPolicy.scala | 9 +- .../core/protocol/ln/LnTagPrefix.scala | 27 +- .../core/protocol/ln/LnTaggedFields.scala | 61 +- .../bitcoins/core/protocol/ln/LnTags.scala | 25 +- .../core/protocol/ln/PaymentSecret.scala | 6 +- .../core/protocol/ln/channel/ChannelId.scala | 35 +- .../protocol/ln/channel/ChannelState.scala | 3 +- .../protocol/ln/channel/ShortChannelId.scala | 30 +- .../protocol/ln/currency/LnCurrencyUnit.scala | 82 +- .../protocol/ln/currency/LnMultiplier.scala | 5 +- .../protocol/ln/currency/MilliSatoshis.scala | 24 +- .../core/protocol/ln/fee/FeeBaseMSat.scala | 16 +- .../core/protocol/ln/node/Feature.scala | 49 +- .../core/protocol/ln/node/NodeId.scala | 5 +- .../core/protocol/ln/node/NodeUri.scala | 5 +- .../core/protocol/ln/routing/LnRoute.scala | 23 +- .../core/protocol/ln/routing/Route.scala | 8 +- .../core/protocol/ln/util/LnUtil.scala | 19 +- .../core/protocol/script/ControlBlock.scala | 32 +- .../core/protocol/script/Script.scala | 16 +- .../core/protocol/script/ScriptFactory.scala | 31 +- .../core/protocol/script/ScriptPubKey.scala | 587 +++--- .../protocol/script/ScriptSignature.scala | 253 +-- .../core/protocol/script/ScriptWitness.scala | 131 +- .../protocol/script/SignatureVersion.scala | 15 +- .../core/protocol/script/TapLeaf.scala | 9 +- .../core/protocol/script/WitnessVersion.scala | 69 +- .../script/descriptor/Descriptor.scala | 204 ++- .../descriptor/DescriptorExpression.scala | 180 +- .../descriptor/DescriptorIterator.scala | 34 +- .../script/descriptor/DescriptorType.scala | 6 +- .../descriptor/KeyOriginExpression.scala | 6 +- .../core/protocol/tlv/DLCOutcomeType.scala | 12 +- .../tlv/DLCSerializationVersion.scala | 25 +- .../core/protocol/tlv/LnMessage.scala | 16 +- .../org/bitcoins/core/protocol/tlv/TLV.scala | 416 +++-- .../core/protocol/tlv/ValueIterator.scala | 15 +- .../core/protocol/transaction/InputUtil.scala | 73 +- .../transaction/OutputReference.scala | 4 +- .../protocol/transaction/Transaction.scala | 138 +- .../transaction/TransactionConstants.scala | 22 +- .../transaction/TransactionInput.scala | 45 +- .../transaction/TransactionOutPoint.scala | 25 +- .../transaction/TransactionOutput.scala | 6 +- .../transaction/TransactionWitness.scala | 42 +- .../core/protocol/transaction/TxUtil.scala | 197 ++- .../scala/org/bitcoins/core/psbt/PSBT.scala | 564 +++--- .../org/bitcoins/core/psbt/PSBTKeyId.scala | 4 +- .../org/bitcoins/core/psbt/PSBTMap.scala | 374 ++-- .../org/bitcoins/core/psbt/PSBTRecord.scala | 268 ++- .../org/bitcoins/core/psbt/PSBTRole.scala | 12 +- .../core/script/ScriptOperationFactory.scala | 33 +- .../bitcoins/core/script/ScriptProgram.scala | 145 +- .../org/bitcoins/core/script/ScriptType.scala | 16 +- .../arithmetic/ArithmeticInterpreter.scala | 354 ++-- .../arithmetic/ArithmeticOperations.scala | 3 +- .../script/bitwise/BitwiseInterpreter.scala | 26 +- .../script/bitwise/BitwiseOperations.scala | 4 +- .../constant/BytesToPushOntoStack.scala | 10 +- .../script/constant/ConstantInterpreter.scala | 86 +- .../core/script/constant/Constants.scala | 109 +- .../script/constant/ScriptNumberUtil.scala | 60 +- .../constant/StackPushOperationFactory.scala | 48 +- .../script/control/ControlOperations.scala | 26 +- .../ControlOperationsInterpreter.scala | 89 +- .../script/crypto/CryptoInterpreter.scala | 365 ++-- .../core/script/crypto/CryptoOperations.scala | 36 +- .../CryptoSignatureEvaluationFactory.scala | 12 +- .../core/script/flag/ScriptFlagFactory.scala | 11 +- .../core/script/flag/ScriptFlagUtil.scala | 23 +- .../core/script/flag/ScriptFlags.scala | 79 +- .../interpreter/ScriptInterpreter.scala | 467 +++-- .../script/locktime/LockTimeInterpreter.scala | 141 +- .../script/locktime/LocktimeOperations.scala | 34 +- .../script/reserved/ReservedOperations.scala | 43 +- .../script/splice/SpliceInterpreter.scala | 19 +- .../core/script/stack/StackInterpreter.scala | 235 ++- .../core/script/stack/StackOperations.scala | 19 +- .../core/script/util/PreviousOutputMap.scala | 7 +- .../core/serializers/PicklerKeys.scala | 14 +- .../serializers/RawBitcoinSerializer.scala | 11 +- .../RawBitcoinSerializerHelper.scala | 25 +- .../blockchain/RawBlockHeaderSerializer.scala | 18 +- .../blockchain/RawBlockSerializer.scala | 15 +- .../blockchain/RawMerkleBlockSerializer.scala | 32 +- .../bloom/RawBloomFilterSerializer.scala | 9 +- .../p2p/RawNetworkIpAddressSerializer.scala | 6 +- .../p2p/RawNetworkMessageSerializer.scala | 5 +- .../headers/RawNetworkHeaderSerializer.scala | 22 +- .../messages/RawAddrMessageSerializer.scala | 33 +- ...actFilterCheckpointMessageSerializer.scala | 16 +- ...ompactFilterHeadersMessageSerializer.scala | 26 +- .../RawCompactFilterMessageSerializer.scala | 3 +- .../RawFilterAddMessageSerializer.scala | 6 +- .../RawFilterLoadMessageSerializer.scala | 6 +- .../RawGetBlocksMessageSerializer.scala | 36 +- ...actFilterCheckpointMessageSerializer.scala | 3 +- ...ompactFilterHeadersMessageSerializer.scala | 3 +- ...awGetCompactFiltersMessageSerializer.scala | 3 +- .../RawGetDataMessageSerializer.scala | 13 +- .../RawGetHeadersMessageSerializer.scala | 17 +- .../RawHeadersMessageSerializer.scala | 21 +- .../RawInventoryMessageSerializer.scala | 29 +- .../p2p/messages/RawInventorySerializer.scala | 3 +- .../RawMerkleBlockMessageSerializer.scala | 3 +- .../RawNotFoundMessageSerializer.scala | 30 +- .../messages/RawPingMessageSerializer.scala | 3 +- .../messages/RawRejectMessageSerializer.scala | 17 +- .../RawServiceIdentifierSerializer.scala | 9 +- .../RawTransactionMessageSerializer.scala | 6 +- .../RawTypeIdentifierSerializer.scala | 4 +- .../RawVersionMessageSerializer.scala | 20 +- .../script/RawScriptWitnessParser.scala | 18 +- .../serializers/script/ScriptParser.scala | 198 ++- .../RawTransactionInputParser.scala | 3 +- .../RawTransactionOutPointParser.scala | 11 +- .../RawTransactionOutputParser.scala | 7 +- .../RawTransactionWitnessParser.scala | 14 +- .../scala/org/bitcoins/core/util/Base58.scala | 49 +- .../scala/org/bitcoins/core/util/Bech32.scala | 143 +- .../org/bitcoins/core/util/BinaryTree.scala | 67 +- .../core/util/BitcoinScriptUtil.scala | 301 ++-- .../core/util/BlockHashWithConfs.scala | 7 +- .../org/bitcoins/core/util/BytesUtil.scala | 11 +- .../org/bitcoins/core/util/EnvUtil.scala | 5 +- .../org/bitcoins/core/util/FutureUtil.scala | 88 +- .../scala/org/bitcoins/core/util/HDUtil.scala | 6 +- .../org/bitcoins/core/util/Indexed.scala | 9 +- .../org/bitcoins/core/util/NetworkUtil.scala | 58 +- .../org/bitcoins/core/util/NumberUtil.scala | 140 +- .../org/bitcoins/core/util/StartStop.scala | 6 +- .../bitcoins/core/util/StartStopAsync.scala | 4 +- .../util/sorted/OrderedAnnouncements.scala | 14 +- .../sorted/OrderedDLCPayoutCurvePieces.scala | 13 +- .../core/util/sorted/OrderedNonces.scala | 3 +- .../sorted/OrderedSchnorrSignatures.scala | 13 +- .../core/util/sorted/OrderedTLVPoints.scala | 6 +- .../bitcoins/core/util/sorted/SortedVec.scala | 28 +- .../builder/FinalizedTxWithSigningInfo.scala | 7 +- .../core/wallet/builder/FundRawTxHelper.scala | 3 +- .../core/wallet/builder/RawTxBuilder.scala | 82 +- .../wallet/builder/RawTxBuilderResult.scala | 13 +- .../core/wallet/builder/RawTxFinalizer.scala | 247 +-- .../core/wallet/builder/RawTxSigner.scala | 112 +- .../core/wallet/builder/TxBuilderError.scala | 219 ++- .../bitcoins/core/wallet/fee/FeeUnit.scala | 134 +- .../KeyManagerInitializeError.scala | 7 +- .../keymanagement/KeyManagerParams.scala | 3 +- .../core/wallet/rescan/RescanState.scala | 85 +- .../core/wallet/signer/FundingInfo.scala | 24 +- .../bitcoins/core/wallet/signer/Signer.scala | 518 +++--- .../core/wallet/utxo/AddressTag.scala | 8 +- .../core/wallet/utxo/ConditionalPath.scala | 10 +- .../core/wallet/utxo/ExternalAddressTag.scala | 4 +- .../bitcoins/core/wallet/utxo/InputInfo.scala | 328 ++-- .../core/wallet/utxo/InputSigningInfo.scala | 33 +- .../core/wallet/utxo/InternalAddressTag.scala | 57 +- .../bitcoins/core/wallet/utxo/TxoState.scala | 29 +- .../org/bitcoins/crypto/SigningTest.scala | 39 +- .../org/bitcoins/crypto/AesCryptTest.scala | 110 +- .../crypto/BouncyCastleBIP340Test.scala | 55 +- .../BouncyCastleECAdaptorSignatureTest.scala | 155 +- .../crypto/BouncyCastleSecp256k1Test.scala | 95 +- .../bitcoins/crypto/SignWithEntropyTest.scala | 4 +- .../bitcoins/crypto/BIP340TestVectors.scala | 4 +- .../bitcoins/crypto/BitcoinSCryptoTest.scala | 14 +- .../bitcoins/crypto/CryptoGenerators.scala | 35 +- .../org/bitcoins/crypto/CryptoUtilTest.scala | 52 +- .../crypto/DERSignatureUtilTest.scala | 89 +- .../crypto/ECAdaptorSignatureTest.scala | 113 +- .../crypto/ECDigitalSignatureTest.scala | 28 +- .../bitcoins/crypto/ECPrivateKeyTest.scala | 31 +- .../org/bitcoins/crypto/ECPublicKeyTest.scala | 41 +- .../bitcoins/crypto/FieldElementTest.scala | 25 +- .../org/bitcoins/crypto/HashTypeTest.scala | 26 +- .../crypto/SchnorrDigitalSignatureTest.scala | 104 +- .../bitcoins/crypto/SchnorrNonceTest.scala | 19 +- .../crypto/SchnorrPublicKeyTest.scala | 19 +- .../scala/org/bitcoins/crypto/SignTest.scala | 16 +- .../org/bitcoins/crypto/SipHashTest.scala | 8 +- .../org/bitcoins/crypto/XOnlyPubKeyTest.scala | 19 +- .../org/bitcoins/crypto/musig/MuSigTest.scala | 299 ++-- .../crypto/BCryptoCryptoRuntime.scala | 82 +- .../org/bitcoins/crypto/CryptoJsUtil.scala | 12 +- .../org/bitcoins/crypto/facade/Buffer.scala | 1574 +++++++++++------ .../org/bitcoins/crypto/facade/PBKDF2.scala | 3 +- .../bitcoins/crypto/facade/SECP256k1.scala | 6 +- .../crypto/BouncyCastleCryptoParams.scala | 10 +- .../bitcoins/crypto/BouncyCastleUtil.scala | 74 +- .../crypto/BouncycastleCryptoRuntime.scala | 57 +- .../HMacDSAKCalculatorWithEntropy.scala | 15 +- .../crypto/LibSecp256k1CryptoRuntime.scala | 170 +- .../scala/org/bitcoins/crypto/PBKDF2.scala | 11 +- .../org/bitcoins/crypto/AdaptorUtil.scala | 95 +- .../scala/org/bitcoins/crypto/AesCrypt.scala | 145 +- .../org/bitcoins/crypto/CryptoBytesUtil.scala | 14 +- .../bitcoins/crypto/CryptoNumberUtil.scala | 10 +- .../org/bitcoins/crypto/CryptoParams.scala | 4 +- .../org/bitcoins/crypto/CryptoRuntime.scala | 123 +- .../org/bitcoins/crypto/CryptoUtil.scala | 78 +- .../bitcoins/crypto/DERSignatureUtil.scala | 123 +- .../scala/org/bitcoins/crypto/DLEQUtil.scala | 57 +- .../bitcoins/crypto/ECAdaptorSignature.scala | 9 +- .../bitcoins/crypto/ECDigitalSignature.scala | 131 +- .../scala/org/bitcoins/crypto/ECKey.scala | 127 +- .../scala/org/bitcoins/crypto/Factory.scala | 20 +- .../org/bitcoins/crypto/FieldElement.scala | 6 +- .../org/bitcoins/crypto/FiniteField.scala | 25 +- .../org/bitcoins/crypto/HashDigest.scala | 82 +- .../scala/org/bitcoins/crypto/HashType.scala | 84 +- .../org/bitcoins/crypto/MaskedToString.scala | 9 +- .../org/bitcoins/crypto/NetworkElement.scala | 5 +- .../crypto/SchnorrDigitalSignature.scala | 20 +- .../org/bitcoins/crypto/SchnorrNonce.scala | 14 +- .../bitcoins/crypto/SchnorrPublicKey.scala | 30 +- .../scala/org/bitcoins/crypto/SecpPoint.scala | 15 +- .../main/scala/org/bitcoins/crypto/Sign.scala | 130 +- .../org/bitcoins/crypto/SipHashKey.scala | 6 +- .../org/bitcoins/crypto/StringFactory.scala | 8 +- .../org/bitcoins/crypto/XOnlyPubKey.scala | 61 +- .../org/bitcoins/crypto/musig/KeySet.scala | 34 +- .../crypto/musig/MuSigNoncePriv.scala | 46 +- .../bitcoins/crypto/musig/MuSigNoncePub.scala | 18 +- .../crypto/musig/MuSigTweakContext.scala | 10 +- .../crypto/musig/MuSigTweakData.scala | 6 +- .../org/bitcoins/crypto/musig/MuSigUtil.scala | 77 +- .../crypto/musig/ParityMultiplier.scala | 16 +- .../crypto/musig/SigningSession.scala | 18 +- .../scala/org/bitcoins/db/DBConfigTest.scala | 28 +- .../org/bitcoins/db/DbManagementTest.scala | 46 +- .../src/main/scala/org/bitcoins/db/CRUD.scala | 100 +- .../scala/org/bitcoins/db/CRUDAction.scala | 80 +- .../scala/org/bitcoins/db/CRUDAutoInc.scala | 27 +- .../scala/org/bitcoins/db/DatadirUtil.scala | 12 +- .../scala/org/bitcoins/db/DbAppConfig.scala | 15 +- .../bitcoins/db/DbCommonsColumnMappers.scala | 136 +- .../scala/org/bitcoins/db/DbManagement.scala | 63 +- .../scala/org/bitcoins/db/HikariLogging.scala | 41 +- .../bitcoins/db/JdbcProfileComponent.scala | 13 +- .../scala/org/bitcoins/db/PostgresUtil.scala | 6 +- .../org/bitcoins/db/SQLiteTableInfo.scala | 6 +- .../scala/org/bitcoins/db/SQLiteUtil.scala | 26 +- .../scala/org/bitcoins/db/SlickUtil.scala | 6 +- .../bitcoins/db/models/MasterXPubDAO.scala | 78 +- .../bitcoins/db/util/DBMasterXPubApi.scala | 4 +- .../org/bitcoins/db/util/MasterXPubUtil.scala | 6 +- .../dlc/node/DLCConnectionHandlerTest.scala | 5 +- .../dlc/node/DLCNegotiationTest.scala | 82 +- .../org/bitcoins/dlc/node/DLCNodeTest.scala | 30 +- .../org/bitcoins/dlc/node/DLCServerTest.scala | 27 +- .../bitcoins/dlc/node/DLCServerTorTest.scala | 52 +- .../org/bitcoins/dlc/node/DLCClient.scala | 119 +- .../dlc/node/DLCConnectionHandler.scala | 48 +- .../bitcoins/dlc/node/DLCDataHandler.scala | 8 +- .../scala/org/bitcoins/dlc/node/DLCNode.scala | 105 +- .../bitcoins/dlc/node/DLCNodeCallbacks.scala | 171 +- .../org/bitcoins/dlc/node/DLCServer.scala | 64 +- .../dlc/node/config/DLCNodeAppConfig.scala | 21 +- .../oracle/AttestationVerificationTest.scala | 134 +- .../bitcoins/dlc/oracle/DLCOracleTest.scala | 590 +++--- .../config/DLCOracleAppConfigTest.scala | 16 +- .../dlc/oracle/storage/EventDAOTest.scala | 48 +- .../oracle/storage/EventOutcomeDAOTest.scala | 24 +- .../org/bitcoins/dlc/oracle/DLCOracle.scala | 274 +-- .../oracle/config/DLCOracleAppConfig.scala | 28 +- .../dlc/oracle/storage/EventDAO.scala | 56 +- .../dlc/oracle/storage/EventOutcomeDAO.scala | 39 +- .../dlc/oracle/storage/RValueDAO.scala | 10 +- .../dlc/oracle/util/EventDbUtil.scala | 32 +- .../DLCClientIntegrationTest.scala | 91 +- .../org/bitcoins/dlc/wallet/DLCDAOTest.scala | 37 +- .../DLCExecutionBitcoindBackendTest.scala | 20 +- .../dlc/wallet/DLCExecutionTest.scala | 166 +- .../DLCMultiOracleEnumExecutionTest.scala | 57 +- ...MultiOracleExactNumericExecutionTest.scala | 47 +- .../DLCMultiOracleNumericExecutionTest.scala | 58 +- .../dlc/wallet/DLCNumericExecutionTest.scala | 102 +- .../dlc/wallet/DLCWalletCallbackTest.scala | 40 +- .../dlc/wallet/IncomingDLCOfferDAOTest.scala | 25 +- .../dlc/wallet/MultiWalletDLCTest.scala | 27 +- .../bitcoins/dlc/wallet/RescanDLCTest.scala | 50 +- .../dlc/wallet/WalletDLCSetupTest.scala | 220 ++- .../internal/DLCDataManagementTest.scala | 6 +- .../bitcoins/dlc/wallet/DLCAppConfig.scala | 137 +- .../org/bitcoins/dlc/wallet/DLCWallet.scala | 1033 ++++++----- .../wallet/accounting/DLCAccountingDbs.scala | 9 +- .../DLCWalletCallbackStreamManager.scala | 45 +- .../wallet/callback/DLCWalletCallbacks.scala | 75 +- .../wallet/internal/DLCDataManagement.scala | 356 ++-- .../internal/DLCTransactionProcessing.scala | 177 +- .../internal/IncomingDLCOffersHandling.scala | 17 +- .../dlc/wallet/models/DLCAcceptDAO.scala | 60 +- .../dlc/wallet/models/DLCAcceptDb.scala | 9 +- .../wallet/models/DLCAnnouncementDAO.scala | 89 +- .../dlc/wallet/models/DLCAnnouncementDb.scala | 5 +- .../wallet/models/DLCCETSignaturesDAO.scala | 65 +- .../dlc/wallet/models/DLCContactDAO.scala | 22 +- .../wallet/models/DLCContractDataDAO.scala | 72 +- .../dlc/wallet/models/DLCContractDataDb.scala | 4 +- .../bitcoins/dlc/wallet/models/DLCDAO.scala | 122 +- .../dlc/wallet/models/DLCDbState.scala | 91 +- .../wallet/models/DLCFundingInputDAO.scala | 77 +- .../dlc/wallet/models/DLCFundingInputDb.scala | 3 +- .../dlc/wallet/models/DLCIdDaoUtil.scala | 53 +- .../dlc/wallet/models/DLCOfferDAO.scala | 55 +- .../dlc/wallet/models/DLCOfferDb.scala | 21 +- .../dlc/wallet/models/DLCRefundSigsDAO.scala | 56 +- .../dlc/wallet/models/DLCRefundSigsDb.scala | 3 +- .../dlc/wallet/models/DLCRemoteTxDAO.scala | 26 +- .../dlc/wallet/models/DLCWalletDAOs.scala | 3 +- .../wallet/models/IncomingDLCOfferDAO.scala | 39 +- .../models/IncomingDLCOfferDbHelper.scala | 3 +- .../dlc/wallet/models/InitializedAccept.scala | 24 +- .../models/OracleAnnouncementDataDAO.scala | 40 +- .../models/OracleAnnouncementDataDb.scala | 20 +- .../dlc/wallet/models/OracleNonceDAO.scala | 72 +- .../dlc/wallet/models/OracleNonceDb.scala | 21 +- .../dlc/wallet/util/DLCAcceptUtil.scala | 51 +- .../dlc/wallet/util/DLCActionBuilder.scala | 103 +- .../dlc/wallet/util/DLCStatusBuilder.scala | 74 +- .../bitcoins/dlc/wallet/util/DLCTxUtil.scala | 14 +- .../eclair/rpc/EclairRpcClientTest.scala | 351 ++-- .../bitcoins/eclair/rpc/api/EclairApi.scala | 121 +- .../eclair/rpc/client/EclairRpcClient.scala | 460 +++-- .../rpc/config/EclairAuthCredentials.scala | 73 +- .../eclair/rpc/config/EclairInstance.scala | 70 +- .../bitcoins/esplora/EsploraClientTest.scala | 45 +- .../org/bitcoins/esplora/EsploraClient.scala | 60 +- .../bitcoins/esplora/EsploraJsonModels.scala | 16 +- .../feeprovider/FeeRateProviderTest.scala | 3 +- .../feeprovider/BitGoFeeRateProvider.scala | 18 +- .../BitcoinerLiveFeeRateProvider.scala | 24 +- .../feeprovider/FallbackFeeRateApi.scala | 8 +- .../feeprovider/FeeProviderFactory.scala | 13 +- .../feeprovider/HttpFeeRateProvider.scala | 3 +- .../feeprovider/MempoolSpaceProvider.scala | 23 +- .../keymanager/WalletStorageTest.scala | 148 +- .../bip39/BIP39KeyManagerApiTest.scala | 284 +-- .../bip39/BIP39LockedKeyManagerApiTest.scala | 37 +- .../config/KeyManagerAppConfigTest.scala | 15 +- .../bitcoins/keymanager/util/HdUtilTest.scala | 92 +- .../keymanager/EncryptedMnemonic.scala | 12 +- .../bitcoins/keymanager/WalletStorage.scala | 184 +- .../keymanager/bip39/BIP39KeyManager.scala | 130 +- .../bip39/BIP39LockedKeyManager.scala | 37 +- .../config/KeyManagerAppConfig.scala | 95 +- .../lnd/rpc/LndRpcClientPairTest.scala | 182 +- .../bitcoins/lnd/rpc/LndRpcClientTest.scala | 10 +- .../org/bitcoins/lnd/rpc/LndRpcClient.scala | 426 +++-- .../scala/org/bitcoins/lnd/rpc/LndUtils.scala | 30 +- .../bitcoins/lnd/rpc/config/LndConfig.scala | 64 +- .../bitcoins/lnd/rpc/config/LndInstance.scala | 24 +- .../lnd/rpc/internal/LndRouterClient.scala | 59 +- .../org/bitcoins/lnurl/LnURLClientTest.scala | 15 +- .../main/scala/org/bitcoins/lnurl/LnURL.scala | 6 +- .../org/bitcoins/lnurl/LnURLClient.scala | 30 +- .../bitcoins/lnurl/json/LnURLJsonModels.scala | 20 +- .../org/bitcoins/lnurl/json/LnURLTag.scala | 6 +- .../node/BroadcastTransactionTest.scala | 26 +- .../bitcoins/node/DisconnectedPeerTest.scala | 6 +- .../org/bitcoins/node/NeutrinoNodeTest.scala | 144 +- ...NeutrinoNodeWithUncachedBitcoindTest.scala | 43 +- .../node/NeutrinoNodeWithWalletTest.scala | 65 +- .../org/bitcoins/node/PeerManagerTest.scala | 21 +- .../node/networking/ReConnectionTest.scala | 40 +- .../peer/DataMessageHandlerTest.scala | 77 +- .../org/bitcoins/node/NeutrinoNode.scala | 76 +- .../main/scala/org/bitcoins/node/Node.scala | 52 +- .../org/bitcoins/node/NodeCallbacks.scala | 148 +- .../scala/org/bitcoins/node/NodeState.scala | 77 +- .../org/bitcoins/node/NodeStreamMessage.scala | 4 +- .../scala/org/bitcoins/node/PeerData.scala | 21 +- .../scala/org/bitcoins/node/PeerFinder.scala | 102 +- .../scala/org/bitcoins/node/PeerManager.scala | 529 +++--- .../callback/NodeCallbackStreamManager.scala | 102 +- .../bitcoins/node/config/NodeAppConfig.scala | 71 +- .../models/BroadcastAbleTransactionDAO.scala | 38 +- .../node/models/NodeStateDescriptorDAO.scala | 39 +- .../org/bitcoins/node/models/PeerDAO.scala | 47 +- .../peer/ControlMessageHandler.scala | 26 +- .../networking/peer/DataMessageHandler.scala | 391 ++-- .../node/networking/peer/PeerConnection.scala | 137 +- .../networking/peer/PeerMessageSender.scala | 43 +- .../bitcoins/node/util/BitcoinSNodeUtil.scala | 12 +- .../node/util/PeerMessageSenderApi.scala | 36 +- .../org/bitcoins/testkitcore/Implicits.scala | 11 +- .../testkitcore/chain/ChainTestUtil.scala | 67 +- .../testkitcore/dlc/DLCFeeTestUtil.scala | 90 +- .../bitcoins/testkitcore/dlc/DLCTest.scala | 518 +++--- .../testkitcore/dlc/DLCTestUtil.scala | 23 +- .../testkitcore/dlc/TestDLCClient.scala | 171 +- .../testkitcore/gen/AddressGenerator.scala | 15 +- .../gen/BlockchainElementsGenerator.scala | 81 +- .../gen/BloomFilterGenerators.scala | 3 +- .../testkitcore/gen/CreditingTxGen.scala | 113 +- .../testkitcore/gen/CryptoGenerators.scala | 43 +- .../gen/CurrencyUnitGenerator.scala | 4 +- .../bitcoins/testkitcore/gen/FeeUnitGen.scala | 30 +- .../testkitcore/gen/HDGenerators.scala | 30 +- .../testkitcore/gen/LnMessageGen.scala | 14 +- .../testkitcore/gen/MerkleGenerators.scala | 57 +- .../testkitcore/gen/NumberGenerator.scala | 13 +- .../testkitcore/gen/PSBTGenerators.scala | 100 +- .../testkitcore/gen/ScriptGenerators.scala | 599 ++++--- .../testkitcore/gen/StringGenerators.scala | 12 +- .../org/bitcoins/testkitcore/gen/TLVGen.scala | 154 +- .../gen/TransactionGenerators.scala | 619 ++++--- .../testkitcore/gen/WitnessGenerators.scala | 206 ++- .../testkitcore/gen/ln/LnInvoiceGen.scala | 44 +- .../testkitcore/gen/ln/LnRouteGen.scala | 14 +- .../gen/p2p/ControlMessageGenerator.scala | 36 +- .../gen/p2p/DataMessageGenerator.scala | 26 +- .../testkitcore/gen/p2p/P2PGenerator.scala | 6 +- .../testkitcore/node/P2PMessageTestUtil.scala | 30 +- .../testkitcore/util/BaseAsyncTest.scala | 97 +- .../testkitcore/util/BitcoinSUnitTest.scala | 23 +- .../bitcoins/testkitcore/util/BytesUtil.scala | 10 +- .../testkitcore/util/OracleTestUtil.scala | 9 +- .../bitcoins/testkitcore/util/TestUtil.scala | 77 +- .../util/TransactionTestUtil.scala | 225 +-- .../testkitcore/wallet/WalletTestUtil.scala | 63 +- .../testkit/BitcoinSTestAppConfig.scala | 67 +- .../testkit/async/TestAsyncUtil.scala | 55 +- .../testkit/chain/BlockHeaderHelper.scala | 100 +- .../testkit/chain/ChainDbUnitTest.scala | 12 +- .../testkit/chain/ChainUnitTest.scala | 424 +++-- .../testkit/chain/MockChainQueryApi.scala | 23 +- .../org/bitcoins/testkit/chain/SyncUtil.scala | 103 +- .../fixture/BitcoindChainHandlerViaRpc.scala | 10 +- .../fixture/BitcoindChainHandlerViaZmq.scala | 6 +- .../testkit/chain/fixture/ChainFixture.scala | 22 +- .../chain/fixture/ChainFixtureHelper.scala | 6 +- .../chain/fixture/ChainFixtureTag.scala | 9 +- .../fixture/ChainWithBitcoindUnitTest.scala | 3 +- .../testkit/chain/models/ReorgFixture.scala | 16 +- .../clightning/CLightningRpcTestClient.scala | 39 +- .../clightning/CLightningRpcTestUtil.scala | 126 +- .../org/bitcoins/testkit/db/DbTestUtil.scala | 19 +- .../testkit/db/TestAppConfigFixture.scala | 3 +- .../bitcoins/testkit/db/TestDAOFixture.scala | 16 +- .../testkit/dlc/BitcoinSDLCNodeTest.scala | 19 +- .../eclair/rpc/EclairRpcTestUtil.scala | 455 +++-- .../fixtures/BitcoinSAppConfigFixture.scala | 29 +- .../testkit/fixtures/BitcoinSFixture.scala | 74 +- .../testkit/fixtures/CLightningFixture.scala | 7 +- .../testkit/fixtures/DLCDAOFixture.scala | 9 +- .../fixtures/DLCOracleDAOFixture.scala | 3 +- .../testkit/fixtures/LndFixture.scala | 8 +- .../testkit/fixtures/NodeDAOFixture.scala | 9 +- .../testkit/fixtures/WalletDAOFixture.scala | 43 +- .../keymanager/KeyManagerApiUnitTest.scala | 4 +- .../keymanager/KeyManagerTestUtil.scala | 8 +- .../testkit/lnd/LndRpcTestClient.scala | 46 +- .../bitcoins/testkit/lnd/LndRpcTestUtil.scala | 143 +- .../bitcoins/testkit/node/BaseNodeTest.scala | 63 +- .../bitcoins/testkit/node/MockNodeApi.scala | 6 +- .../node/NodeFundedWalletBitcoind.scala | 14 +- .../bitcoins/testkit/node/NodeTestUtil.scala | 130 +- .../node/NodeTestWithCachedBitcoind.scala | 121 +- .../bitcoins/testkit/node/NodeUnitTest.scala | 318 ++-- .../fixture/NodeConnectedWithBitcoind.scala | 15 +- .../testkit/oracle/OracleTestUtil.scala | 5 +- .../testkit/rpc/BitcoindFixtures.scala | 50 +- .../testkit/rpc/BitcoindRpcTestUtil.scala | 472 +++-- .../bitcoins/testkit/rpc/CachedBitcoind.scala | 80 +- .../BitcoinSServerMainBitcoindFixture.scala | 21 +- .../server/BitcoinSServerMainUtil.scala | 14 +- .../testkit/server/ServerWithBitcoind.scala | 3 +- .../testkit/server/WalletLoaderFixtures.scala | 13 +- .../org/bitcoins/testkit/tor/CachedTor.scala | 5 +- .../testkit/util/BitcoinSAsyncTest.scala | 22 +- .../testkit/util/BitcoindRpcTest.scala | 11 +- .../testkit/util/BitcoindRpcTestClient.scala | 33 +- .../org/bitcoins/testkit/util/BytesUtil.scala | 10 +- .../testkit/util/EclairRpcTestClient.scala | 51 +- .../org/bitcoins/testkit/util/FileUtil.scala | 10 +- .../org/bitcoins/testkit/util/PekkoUtil.scala | 5 +- .../bitcoins/testkit/util/RpcBinaryUtil.scala | 4 +- .../bitcoins/testkit/util/ScalaTestUtil.scala | 8 +- .../testkit/util/TestkitBinaries.scala | 6 +- .../org/bitcoins/testkit/util/TorUtil.scala | 18 +- .../testkit/wallet/BaseWalletTest.scala | 6 +- .../wallet/BitcoinSDualWalletTest.scala | 96 +- .../testkit/wallet/BitcoinSWalletTest.scala | 259 +-- .../BitcoinSWalletTestCachedBitcoind.scala | 68 +- .../testkit/wallet/DLCWalletUtil.scala | 198 ++- .../wallet/DualWalletTestCachedBitcoind.scala | 84 +- .../testkit/wallet/FundWalletUtil.scala | 84 +- .../wallet/WalletAppConfigWithBitcoind.scala | 3 +- .../WalletAppConfigWithBitcoindFixtures.scala | 6 +- .../testkit/wallet/WalletTestUtil.scala | 169 +- .../testkit/wallet/WalletWithBitcoind.scala | 8 +- .../scala/org/bitcoins/util/ListUtil.scala | 3 +- .../testkit/util/ScalaTestUtilTest.scala | 2 +- .../tor/Socks5ClientTransportSpec.scala | 12 +- .../bitcoins/tor/TorProtocolHandlerSpec.scala | 121 +- .../bitcoins/tor/Socks5ClientTransport.scala | 102 +- .../org/bitcoins/tor/Socks5Connection.scala | 146 +- .../scala/org/bitcoins/tor/TorCallbacks.scala | 3 +- .../org/bitcoins/tor/TorController.scala | 50 +- .../org/bitcoins/tor/TorProtocolHandler.scala | 93 +- .../org/bitcoins/tor/client/TorClient.scala | 67 +- .../bitcoins/tor/config/TorAppConfig.scala | 91 +- .../bitcoins/wallet/AddressHandlingTest.scala | 24 +- .../bitcoins/wallet/AddressLabelTest.scala | 16 +- .../wallet/AddressTagIntegrationTest.scala | 37 +- .../bitcoins/wallet/BitcoindBackendTest.scala | 41 +- .../wallet/BitcoindBlockPollingTest.scala | 38 +- .../wallet/BitcoindZMQBackendTest.scala | 12 +- .../bitcoins/wallet/CoinSelectorTest.scala | 55 +- .../wallet/ComputeContractIdTest.scala | 7 +- .../wallet/FundTransactionHandlingTest.scala | 158 +- .../org/bitcoins/wallet/MultiWalletTest.scala | 6 +- .../bitcoins/wallet/ProcessBlockTest.scala | 51 +- .../wallet/ProcessTransactionTest.scala | 32 +- .../bitcoins/wallet/RescanHandlingTest.scala | 281 +-- .../bitcoins/wallet/TrezorAddressTest.scala | 57 +- .../bitcoins/wallet/UTXOHandlingTest.scala | 155 +- .../bitcoins/wallet/UTXOLifeCycleTest.scala | 224 ++- .../bitcoins/wallet/WalletAppConfigTest.scala | 9 +- .../bitcoins/wallet/WalletCallbackTest.scala | 6 +- .../wallet/WalletIntegrationTest.scala | 27 +- .../bitcoins/wallet/WalletSendingTest.scala | 112 +- .../org/bitcoins/wallet/WalletUnitTest.scala | 72 +- .../wallet/models/AddressDAOTest.scala | 68 +- .../wallet/models/AddressTagDAOTest.scala | 15 +- .../models/IncomingTransactionDAOTest.scala | 12 +- .../models/OutgoingTransactionDAOTest.scala | 9 +- .../wallet/models/ScriptPubKeyDAOTest.scala | 18 +- .../wallet/models/SpendingInfoDAOTest.scala | 113 +- .../bitcoins/wallet/sync/WalletSyncTest.scala | 14 +- .../bitcoins/wallet/util/GetAddresses.scala | 25 +- .../scala/org/bitcoins/wallet/Wallet.scala | 427 +++-- .../org/bitcoins/wallet/WalletHolder.scala | 675 ++++--- .../WalletCallbackStreamManager.scala | 78 +- .../wallet/callback/WalletCallbacks.scala | 148 +- .../wallet/config/WalletAppConfig.scala | 128 +- .../wallet/internal/AccountHandling.scala | 15 +- .../wallet/internal/AddressHandling.scala | 193 +- .../wallet/internal/AddressRequest.scala | 3 +- .../internal/FundTransactionHandling.scala | 121 +- .../wallet/internal/RescanHandling.scala | 366 ++-- .../internal/TransactionProcessing.scala | 338 ++-- .../wallet/internal/UtxoHandling.scala | 184 +- .../bitcoins/wallet/models/AccountDAO.scala | 39 +- .../bitcoins/wallet/models/AddressDAO.scala | 139 +- .../wallet/models/AddressTagDAO.scala | 77 +- .../models/IncomingTransactionDAO.scala | 29 +- .../models/OutgoingTransactionDAO.scala | 59 +- .../wallet/models/ScriptPubKeyDAO.scala | 34 +- .../wallet/models/SpendingInfoDAO.scala | 436 ++--- .../wallet/models/TransactionDAO.scala | 61 +- .../models/WalletStateDescriptorDAO.scala | 53 +- .../org/bitcoins/wallet/sync/WalletSync.scala | 36 +- .../migration/V15__compute_spk_hashes.scala | 6 +- .../migration/V14__compute_spk_hashes.scala | 6 +- .../org/bitcoins/zmq/ZMQNotification.scala | 4 +- .../org/bitcoins/zmq/ZMQSubscriber.scala | 25 +- .../org/bitcoins/zmq/ZMQSubscriberTest.scala | 10 +- 1090 files changed, 46186 insertions(+), 30144 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 7bc309f8ce..9d185e2b98 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,14 +1,6 @@ -version = "2.7.5" +version = "3.8.1" # See Documentation at https://scalameta.org/scalafmt/#Configuration -trailingCommas = never -maxColumn = 80 -lineEndings = preserve -docstrings = ScalaDoc -continuationIndent { - callSite = 2 - defnSite = 4 -} - +runner.dialect=scala213 align = some align { openParenDefnSite = false @@ -16,32 +8,6 @@ align { } danglingParentheses { - callSite = false + callSite = false defnSite = false } - -newlines { - alwaysBeforeTopLevelStatements = true - sometimesBeforeColonInMethodReturnType = false - alwaysBeforeCurlyBraceLambdaParams = false -} - -assumeStandardLibraryStripMargin = true - -rewrite.rules = [ - SortModifiers, - RedundantParens, - SortImports -] - -binPack.literalArgumentLists = true - -project { - excludeFilters = [ - .bloop, - .metals, - target - ] -} - -# Consider Rewrite Rules diff --git a/app-commons-test/src/test/scala/org/bitcoins/commons/DLCStatusTest.scala b/app-commons-test/src/test/scala/org/bitcoins/commons/DLCStatusTest.scala index 3ca41be8ac..a8e56989dc 100644 --- a/app-commons-test/src/test/scala/org/bitcoins/commons/DLCStatusTest.scala +++ b/app-commons-test/src/test/scala/org/bitcoins/commons/DLCStatusTest.scala @@ -49,163 +49,186 @@ class DLCStatusTest extends BitcoinSJvmTest { assert(status.state == DLCState.Offered) assert(read[DLCStatus](write(status)) == status) - assert(read[DLCStatus]( - write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status) + assert( + read[DLCStatus]( + write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW) + ) == status + ) } } it must "have json symmetry in DLCStatus.Accepted" in { - forAllParallel(NumberGenerator.bool, - TLVGen.dlcOfferTLV, - NumberGenerator.bytevector) { - case (isInit, offerTLV, contractId) => - val offer = DLCOffer.fromTLV(offerTLV) + forAllParallel( + NumberGenerator.bool, + TLVGen.dlcOfferTLV, + NumberGenerator.bytevector + ) { case (isInit, offerTLV, contractId) => + val offer = DLCOffer.fromTLV(offerTLV) - val totalCollateral = offer.contractInfo.totalCollateral + val totalCollateral = offer.contractInfo.totalCollateral - // random testnet address - val payoutAddress = - Some( - PayoutAddress(BitcoinAddress.fromString( - "tb1q4ps6c9ewa7uca5v39fakykq9q6hpgjkxje8gve"), - true)) - - val contact = Option.empty[String] - - val status = - DLCStatus.Accepted( - Sha256Digest.empty, - isInit, - TimeUtil.now, - offer.tempContractId, - contractId, - offer.contractInfo, - offer.timeouts, - offer.feeRate, - totalCollateral, - offer.collateral, - payoutAddress, - contact + // random testnet address + val payoutAddress = + Some( + PayoutAddress( + BitcoinAddress.fromString( + "tb1q4ps6c9ewa7uca5v39fakykq9q6hpgjkxje8gve" + ), + true ) + ) - assert(status.state == DLCState.Accepted) - assert(read[DLCStatus](write(status)) == status) - assert(read[DLCStatus]( - write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status) + val contact = Option.empty[String] + + val status = + DLCStatus.Accepted( + Sha256Digest.empty, + isInit, + TimeUtil.now, + offer.tempContractId, + contractId, + offer.contractInfo, + offer.timeouts, + offer.feeRate, + totalCollateral, + offer.collateral, + payoutAddress, + contact + ) + + assert(status.state == DLCState.Accepted) + assert(read[DLCStatus](write(status)) == status) + assert( + read[DLCStatus]( + write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW) + ) == status + ) } } it must "have json symmetry in DLCStatus.Signed" in { - forAllParallel(NumberGenerator.bool, - TLVGen.dlcOfferTLV, - NumberGenerator.bytevector, - CryptoGenerators.doubleSha256DigestBE) { - case (isInit, offerTLV, contractId, txId) => - val offer = DLCOffer.fromTLV(offerTLV) + forAllParallel( + NumberGenerator.bool, + TLVGen.dlcOfferTLV, + NumberGenerator.bytevector, + CryptoGenerators.doubleSha256DigestBE + ) { case (isInit, offerTLV, contractId, txId) => + val offer = DLCOffer.fromTLV(offerTLV) - val totalCollateral = offer.contractInfo.totalCollateral + val totalCollateral = offer.contractInfo.totalCollateral - val payoutAddress = Option.empty[PayoutAddress] + val payoutAddress = Option.empty[PayoutAddress] - val contact = Option.empty[String] + val contact = Option.empty[String] - val status = - DLCStatus.Signed( - Sha256Digest.empty, - isInit, - TimeUtil.now, - offer.tempContractId, - contractId, - offer.contractInfo, - offer.timeouts, - offer.feeRate, - totalCollateral, - offer.collateral, - txId, - payoutAddress, - contact - ) + val status = + DLCStatus.Signed( + Sha256Digest.empty, + isInit, + TimeUtil.now, + offer.tempContractId, + contractId, + offer.contractInfo, + offer.timeouts, + offer.feeRate, + totalCollateral, + offer.collateral, + txId, + payoutAddress, + contact + ) - assert(status.state == DLCState.Signed) - assert(read[DLCStatus](write(status)) == status) - assert(read[DLCStatus]( - write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status) + assert(status.state == DLCState.Signed) + assert(read[DLCStatus](write(status)) == status) + assert( + read[DLCStatus]( + write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW) + ) == status + ) } } it must "have json symmetry in DLCStatus.Broadcasted" in { - forAllParallel(NumberGenerator.bool, - TLVGen.dlcOfferTLV, - NumberGenerator.bytevector, - CryptoGenerators.doubleSha256DigestBE) { - case (isInit, offerTLV, contractId, fundingTxId) => - val offer = DLCOffer.fromTLV(offerTLV) + forAllParallel( + NumberGenerator.bool, + TLVGen.dlcOfferTLV, + NumberGenerator.bytevector, + CryptoGenerators.doubleSha256DigestBE + ) { case (isInit, offerTLV, contractId, fundingTxId) => + val offer = DLCOffer.fromTLV(offerTLV) - val totalCollateral = offer.contractInfo.totalCollateral + val totalCollateral = offer.contractInfo.totalCollateral - val payoutAddress = Option.empty[PayoutAddress] + val payoutAddress = Option.empty[PayoutAddress] - val contact = Option.empty[String] + val contact = Option.empty[String] - val status = - DLCStatus.Broadcasted( - Sha256Digest.empty, - isInit, - TimeUtil.now, - offer.tempContractId, - contractId, - offer.contractInfo, - offer.timeouts, - offer.feeRate, - totalCollateral, - offer.collateral, - fundingTxId, - payoutAddress, - contact - ) + val status = + DLCStatus.Broadcasted( + Sha256Digest.empty, + isInit, + TimeUtil.now, + offer.tempContractId, + contractId, + offer.contractInfo, + offer.timeouts, + offer.feeRate, + totalCollateral, + offer.collateral, + fundingTxId, + payoutAddress, + contact + ) - assert(status.state == DLCState.Broadcasted) - assert(read[DLCStatus](write(status)) == status) - assert(read[DLCStatus]( - write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status) + assert(status.state == DLCState.Broadcasted) + assert(read[DLCStatus](write(status)) == status) + assert( + read[DLCStatus]( + write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW) + ) == status + ) } } it must "have json symmetry in DLCStatus.Confirmed" in { - forAllParallel(NumberGenerator.bool, - TLVGen.dlcOfferTLV, - NumberGenerator.bytevector, - CryptoGenerators.doubleSha256DigestBE) { - case (isInit, offerTLV, contractId, fundingTxId) => - val offer = DLCOffer.fromTLV(offerTLV) + forAllParallel( + NumberGenerator.bool, + TLVGen.dlcOfferTLV, + NumberGenerator.bytevector, + CryptoGenerators.doubleSha256DigestBE + ) { case (isInit, offerTLV, contractId, fundingTxId) => + val offer = DLCOffer.fromTLV(offerTLV) - val totalCollateral = offer.contractInfo.totalCollateral + val totalCollateral = offer.contractInfo.totalCollateral - val payoutAddress = Option.empty[PayoutAddress] + val payoutAddress = Option.empty[PayoutAddress] - val contact = Option.empty[String] + val contact = Option.empty[String] - val status = - DLCStatus.Confirmed( - Sha256Digest.empty, - isInit, - TimeUtil.now, - offer.tempContractId, - contractId, - offer.contractInfo, - offer.timeouts, - offer.feeRate, - totalCollateral, - offer.collateral, - fundingTxId, - payoutAddress, - contact - ) + val status = + DLCStatus.Confirmed( + Sha256Digest.empty, + isInit, + TimeUtil.now, + offer.tempContractId, + contractId, + offer.contractInfo, + offer.timeouts, + offer.feeRate, + totalCollateral, + offer.collateral, + fundingTxId, + payoutAddress, + contact + ) - assert(status.state == DLCState.Confirmed) - assert(read[DLCStatus](write(status)) == status) - assert(read[DLCStatus]( - write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status) + assert(status.state == DLCState.Confirmed) + assert(read[DLCStatus](write(status)) == status) + assert( + read[DLCStatus]( + write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW) + ) == status + ) } } @@ -260,7 +283,9 @@ class DLCStatusTest extends BitcoinSJvmTest { assert(read[DLCStatus](write(status)) == status) assert( read[DLCStatus]( - write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status) + write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW) + ) == status + ) } } @@ -317,7 +342,9 @@ class DLCStatusTest extends BitcoinSJvmTest { assert(read[DLCStatus](write(status)) == status) assert( read[DLCStatus]( - write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status) + write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW) + ) == status + ) } } @@ -368,7 +395,9 @@ class DLCStatusTest extends BitcoinSJvmTest { assert(read[DLCStatus](write(status)) == status) assert( read[DLCStatus]( - write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW)) == status) + write(status.asInstanceOf[DLCStatus])(Picklers.dlcStatusW) + ) == status + ) } } } diff --git a/app-commons-test/src/test/scala/org/bitcoins/commons/SerializedPSBTTest.scala b/app-commons-test/src/test/scala/org/bitcoins/commons/SerializedPSBTTest.scala index d651a04b69..020dd2f7f5 100644 --- a/app-commons-test/src/test/scala/org/bitcoins/commons/SerializedPSBTTest.scala +++ b/app-commons-test/src/test/scala/org/bitcoins/commons/SerializedPSBTTest.scala @@ -13,7 +13,8 @@ class SerializedPSBTTest extends BitcoinSUnitTest { it must "correctly decode a psbt" in { val psbt = PSBT.fromBase64( - "cHNidP9Fq2AoiZroZUZZ7/Fl0n4dcF8zKWfpD3QzRcAm1QTxUQzzGnHjM5xU+xYUvYSPokH86tLWHVVmhrOQE2d//fPeu6Px6r0LW2DbYkBubiYldhPvO50/3M0wHtHncJ6w/UmdpFVMt/z1iQfbH9U4bq6iLS930BnOiRlc0KX8DQmDnKFdTdiyceBPOmWKSJT+cR1RIQabSiKY6plO4jkSbZ2yFGMBAP3dAgIAAAABG2Z29d/AhiGmmjjrgO9p0LwwYozRbr404YcnQQ+LTQMEAAAAAAAAAAADGQVGPusCAAD9vwFjVyEDkIsYrb9OJzC2oJUtRDntXxhNo7cZeByTHPkuJeCnAmshA4B9R4qr45hWk4fD3F+0um+wJVmP8kFRyXWflgEYKi61IQMLERF8Yx7x85yRmZyD7888+GENPbV2xACyxsAbEJoZpCEDLfkiP2NbzOWOTrM5qIiGFWLDrAYEoYj+6B/p474XWbQhAuNDwvhwWxJHuG/S7CS/bsk/wr8pR9LzCm8eEEqoQ58NIQPlPMn3Y69Fovcn4cexpU9r1whI0yWZ1OwvYHlsngyAyCECyGo6/HPABsWFUwjKuE+mG57duFkwbk17rug85rd0MCohA8ObOSpT1WPHeKKjc3MwDtFM8xr+LRlrDETYazNJhawyIQNqTHMWXX5dNDAuY71BaXfFF8yoHEaQDnDyNudqgfuMQSEC410iVARHWVmvKpcQUFJJx/H41G2/9sJ5jvRnyYIXwQIhA4APXyr35MW/4PPuMRtYg+caUGFqk+12x9wW+JFxHqnwIQMiS1b6HfL93efBgysG0PrlMPwA7eKMSFexdnOGHhOQP1yuZwXdzsmnALF1dqkUCzczWAtdSewwYE3SNlcLhnxJInGIrGjelDmdMwkAABYAFO26WaDgWxcVeSe4lfoysDTitaKJp/r3t2YNAAC4Y1IhA6WEMWgMOWjUk1FZvxYDTRvyVZKDWeCKsBvgJruAngCOIQKeg5DPhM1ghA26JAP1gvhyZ7K/Z2ttavmOd7AyFv2OyyEDjgniAeDz5qiX/5tyDxMJcyMN4yRoYXZwfFgT9x6iKqghAxmojRQWODhnuwBaEtxJHK9AlJXUkPjIOs4o08raE5zfVK5nBF6KYiOxdSEDvbxvoF42LUei1lcblCHsUzeXo7Wr1zKxw5agIRZVWqysaAAAAAAAAQMEggAAAAAAA6jMPk3fqYXY2pAV+YsGMMB2CAwXDBpwMObcmgEz8M0NO07ZYF60Sf8jj0zms7HOPzU3tBtRMROIXzyZreEJOfmqBIZKk6tg78xgjIW8mR+WuQAA") + "cHNidP9Fq2AoiZroZUZZ7/Fl0n4dcF8zKWfpD3QzRcAm1QTxUQzzGnHjM5xU+xYUvYSPokH86tLWHVVmhrOQE2d//fPeu6Px6r0LW2DbYkBubiYldhPvO50/3M0wHtHncJ6w/UmdpFVMt/z1iQfbH9U4bq6iLS930BnOiRlc0KX8DQmDnKFdTdiyceBPOmWKSJT+cR1RIQabSiKY6plO4jkSbZ2yFGMBAP3dAgIAAAABG2Z29d/AhiGmmjjrgO9p0LwwYozRbr404YcnQQ+LTQMEAAAAAAAAAAADGQVGPusCAAD9vwFjVyEDkIsYrb9OJzC2oJUtRDntXxhNo7cZeByTHPkuJeCnAmshA4B9R4qr45hWk4fD3F+0um+wJVmP8kFRyXWflgEYKi61IQMLERF8Yx7x85yRmZyD7888+GENPbV2xACyxsAbEJoZpCEDLfkiP2NbzOWOTrM5qIiGFWLDrAYEoYj+6B/p474XWbQhAuNDwvhwWxJHuG/S7CS/bsk/wr8pR9LzCm8eEEqoQ58NIQPlPMn3Y69Fovcn4cexpU9r1whI0yWZ1OwvYHlsngyAyCECyGo6/HPABsWFUwjKuE+mG57duFkwbk17rug85rd0MCohA8ObOSpT1WPHeKKjc3MwDtFM8xr+LRlrDETYazNJhawyIQNqTHMWXX5dNDAuY71BaXfFF8yoHEaQDnDyNudqgfuMQSEC410iVARHWVmvKpcQUFJJx/H41G2/9sJ5jvRnyYIXwQIhA4APXyr35MW/4PPuMRtYg+caUGFqk+12x9wW+JFxHqnwIQMiS1b6HfL93efBgysG0PrlMPwA7eKMSFexdnOGHhOQP1yuZwXdzsmnALF1dqkUCzczWAtdSewwYE3SNlcLhnxJInGIrGjelDmdMwkAABYAFO26WaDgWxcVeSe4lfoysDTitaKJp/r3t2YNAAC4Y1IhA6WEMWgMOWjUk1FZvxYDTRvyVZKDWeCKsBvgJruAngCOIQKeg5DPhM1ghA26JAP1gvhyZ7K/Z2ttavmOd7AyFv2OyyEDjgniAeDz5qiX/5tyDxMJcyMN4yRoYXZwfFgT9x6iKqghAxmojRQWODhnuwBaEtxJHK9AlJXUkPjIOs4o08raE5zfVK5nBF6KYiOxdSEDvbxvoF42LUei1lcblCHsUzeXo7Wr1zKxw5agIRZVWqysaAAAAAAAAQMEggAAAAAAA6jMPk3fqYXY2pAV+YsGMMB2CAwXDBpwMObcmgEz8M0NO07ZYF60Sf8jj0zms7HOPzU3tBtRMROIXzyZreEJOfmqBIZKk6tg78xgjIW8mR+WuQAA" + ) val tx = psbt.transaction val decoded = SerializedPSBT.decodePSBT(psbt) @@ -21,10 +22,13 @@ class SerializedPSBTTest extends BitcoinSUnitTest { assert(decoded.global.tx == SerializedTransaction.decodeRawTransaction(tx)) assert(decoded.global.version == UInt32.zero) assert( - decoded.global.unknowns == Vector(GlobalPSBTRecord.Unknown( - hex"ab6028899ae8654659eff165d27e1d705f332967e90f743345c026d504f1510cf31a71e3339c54fb1614bd848fa241fcead2d61d556686b39013677ffdf3debba3f1eabd0b", - hex"60db62406e6e26257613ef3b9d3fdccd301ed1e7709eb0fd499da4554cb7fcf58907db1fd5386eaea22d2f77d019ce89195cd0a5fc0d09839ca15d4dd8b271e04f3a658a4894fe711d5121069b4a2298ea994ee239126d9db21463" - ))) + decoded.global.unknowns == Vector( + GlobalPSBTRecord.Unknown( + hex"ab6028899ae8654659eff165d27e1d705f332967e90f743345c026d504f1510cf31a71e3339c54fb1614bd848fa241fcead2d61d556686b39013677ffdf3debba3f1eabd0b", + hex"60db62406e6e26257613ef3b9d3fdccd301ed1e7709eb0fd499da4554cb7fcf58907db1fd5386eaea22d2f77d019ce89195cd0a5fc0d09839ca15d4dd8b271e04f3a658a4894fe711d5121069b4a2298ea994ee239126d9db21463" + ) + ) + ) assert(decoded.inputs.size == 1) assert(decoded.inputs.head.bip32Paths.isEmpty) @@ -39,7 +43,8 @@ class SerializedPSBTTest extends BitcoinSUnitTest { assert(decoded.inputs.head.unknowns.isEmpty) assert( decoded.inputs.head.sigHashType - .contains(HashType.sigHashNoneAnyoneCanPay)) + .contains(HashType.sigHashNoneAnyoneCanPay) + ) assert(decoded.outputs.size == 3) assert(decoded.outputs.head.bip32Paths.isEmpty) @@ -50,10 +55,13 @@ class SerializedPSBTTest extends BitcoinSUnitTest { assert(decoded.outputs(1).redeemScript.isEmpty) assert(decoded.outputs(1).witScript.isEmpty) assert( - decoded.outputs(1).unknowns == Vector(OutputPSBTRecord.Unknown( - hex"a8cc3e", - hex"dfa985d8da9015f98b0630c076080c170c1a7030e6dc9a0133f0cd0d3b4ed9605eb449ff238f4ce6b3b1ce3f3537b41b513113885f3c99ade10939f9aa04864a93ab60efcc608c85bc991f96b9" - ))) + decoded.outputs(1).unknowns == Vector( + OutputPSBTRecord.Unknown( + hex"a8cc3e", + hex"dfa985d8da9015f98b0630c076080c170c1a7030e6dc9a0133f0cd0d3b4ed9605eb449ff238f4ce6b3b1ce3f3537b41b513113885f3c99ade10939f9aa04864a93ab60efcc608c85bc991f96b9" + ) + ) + ) assert(decoded.outputs.last.bip32Paths.isEmpty) assert(decoded.outputs.last.redeemScript.isEmpty) assert(decoded.outputs.last.witScript.isEmpty) @@ -61,7 +69,8 @@ class SerializedPSBTTest extends BitcoinSUnitTest { it must "correctly decode a finalized psbt" in { val psbt = PSBT.fromBase64( - "cHNidP8BAP1FAQIAAAABGYuEj8rH1dQ8DYG/wIJoOmA07cMG3qUA2joduT39u3QBAAAAAEhEAAAGZi6ggGgAAAAqBOhp5BGydSEDT4d2r4kKjBDT7N3xtlQRvQOoZMDnvl9kcu+Yz0N+zOWsB9sJYW0AAAAmaiSqIantmOy8chX8u/gjrWjoJwzItqupL01TN2d15WGchnbpGlW08zmpugUAAAcEuQUHI7J1tyGqaVkFAABJZCEDd0QjA5VNPMrHshsJ5ToPa6aXjJClUKFubu0Z3qUgGCmsZyEDCXN1QPwcYCN+5PBjESbL9eI3/Fd2SW/L1kOKOJ6lAsqsaMnuN1dBTAAAFlMU75XVn2xj3vMdoWxBKP6yYswBfsdaZnFQHAAAACZqJKohqe2Q60JHII6xx+YrJFTmibrNi7e8pICEfsbYEMYNKhOtMwAAAAAAAQCKAgAAAAAC7ekoBUtTAABQYyED6l4Vptz8do0rhD+X5Xlmyl5Wwi/fM/EwJmYE/LE4XWhnBfcyAqcAsnUhA/spF0dsJg2ZiBFYnA80MM2Pxou90wok6B8hA44T/vJlaKy4YEecR1gAAB4CSESydXapFHyp4KCUiJddycf+SqnAZI21/aJFiKwAAAAAAQdqRzBEAiBMdpIM1wDaIgn1BJarrd27uzx9kcTixUzQMFGbb0KTsQIgBxNIy+cxhoe1Bnxy/X3+ankfNtC4ydjJcMHlxV0MJqOAIQJUjewAnrbEt88DGQklYoDSLGlNS5Z2C6ukMaVGy+p6EgAAAAAAAAA=") + "cHNidP8BAP1FAQIAAAABGYuEj8rH1dQ8DYG/wIJoOmA07cMG3qUA2joduT39u3QBAAAAAEhEAAAGZi6ggGgAAAAqBOhp5BGydSEDT4d2r4kKjBDT7N3xtlQRvQOoZMDnvl9kcu+Yz0N+zOWsB9sJYW0AAAAmaiSqIantmOy8chX8u/gjrWjoJwzItqupL01TN2d15WGchnbpGlW08zmpugUAAAcEuQUHI7J1tyGqaVkFAABJZCEDd0QjA5VNPMrHshsJ5ToPa6aXjJClUKFubu0Z3qUgGCmsZyEDCXN1QPwcYCN+5PBjESbL9eI3/Fd2SW/L1kOKOJ6lAsqsaMnuN1dBTAAAFlMU75XVn2xj3vMdoWxBKP6yYswBfsdaZnFQHAAAACZqJKohqe2Q60JHII6xx+YrJFTmibrNi7e8pICEfsbYEMYNKhOtMwAAAAAAAQCKAgAAAAAC7ekoBUtTAABQYyED6l4Vptz8do0rhD+X5Xlmyl5Wwi/fM/EwJmYE/LE4XWhnBfcyAqcAsnUhA/spF0dsJg2ZiBFYnA80MM2Pxou90wok6B8hA44T/vJlaKy4YEecR1gAAB4CSESydXapFHyp4KCUiJddycf+SqnAZI21/aJFiKwAAAAAAQdqRzBEAiBMdpIM1wDaIgn1BJarrd27uzx9kcTixUzQMFGbb0KTsQIgBxNIy+cxhoe1Bnxy/X3+ankfNtC4ydjJcMHlxV0MJqOAIQJUjewAnrbEt88DGQklYoDSLGlNS5Z2C6ukMaVGy+p6EgAAAAAAAAA=" + ) val tx = psbt.transaction val decoded = SerializedPSBT.decodePSBT(psbt) diff --git a/app-commons-test/src/test/scala/org/bitcoins/commons/config/AppConfigTest.scala b/app-commons-test/src/test/scala/org/bitcoins/commons/config/AppConfigTest.scala index 28fa79b467..7ab792cbb2 100644 --- a/app-commons-test/src/test/scala/org/bitcoins/commons/config/AppConfigTest.scala +++ b/app-commons-test/src/test/scala/org/bitcoins/commons/config/AppConfigTest.scala @@ -80,10 +80,10 @@ class AppConfigTest extends BitcoinSAsyncTest { for { _ <- walletAppConfig.start() } yield { - //this should get substituted as all default sqlite - //configuration is saved in the "bitcoin-s.sqlite" key - //if in the future we change our default database behavior - //this test case will need to change to check that the profile is correct + // this should get substituted as all default sqlite + // configuration is saved in the "bitcoin-s.sqlite" key + // if in the future we change our default database behavior + // this test case will need to change to check that the profile is correct assert(walletAppConfig.dbConfig.profile.isInstanceOf[SQLiteProfile]) } } @@ -92,8 +92,8 @@ class AppConfigTest extends BitcoinSAsyncTest { val datadir = BitcoinSTestAppConfig.tmpDir() System.setProperty("bitcoin-s.wallet.requiredConfirmations", "1") - //need to invalidate the config cache to force typesafe config - //to freshly load all system properties + // need to invalidate the config cache to force typesafe config + // to freshly load all system properties ConfigFactory.invalidateCaches() val walletAppConfig = diff --git a/app-commons-test/src/test/scala/org/bitcoins/commons/json/AppServerCliJsonTest.scala b/app-commons-test/src/test/scala/org/bitcoins/commons/json/AppServerCliJsonTest.scala index 89f11d6348..63fff048ee 100644 --- a/app-commons-test/src/test/scala/org/bitcoins/commons/json/AppServerCliJsonTest.scala +++ b/app-commons-test/src/test/scala/org/bitcoins/commons/json/AppServerCliJsonTest.scala @@ -16,7 +16,8 @@ class AppServerCliJsonTest extends BitcoinSUnitTest { assert(parsed1.isSuccess) assert(parsed1.get.walletNameOpt == Some(walletName)) assert( - parsed1.get.passwordOpt.map(_.toStringSensitive) == Some(aesPassword)) + parsed1.get.passwordOpt.map(_.toStringSensitive) == Some(aesPassword) + ) assert(parsed1.get.bip39PasswordOpt == Some(bip39Password)) val arr2 = ujson.Arr(walletName, aesPassword, ujson.Null) @@ -24,7 +25,8 @@ class AppServerCliJsonTest extends BitcoinSUnitTest { assert(parsed2.isSuccess) assert(parsed2.get.walletNameOpt == Some(walletName)) assert( - parsed2.get.passwordOpt.map(_.toStringSensitive) == Some(aesPassword)) + parsed2.get.passwordOpt.map(_.toStringSensitive) == Some(aesPassword) + ) } } diff --git a/app-commons-test/src/test/scala/org/bitcoins/commons/json/DLCAcceptJsonSerializerTest.scala b/app-commons-test/src/test/scala/org/bitcoins/commons/json/DLCAcceptJsonSerializerTest.scala index eaaabc788d..7745c10cd6 100644 --- a/app-commons-test/src/test/scala/org/bitcoins/commons/json/DLCAcceptJsonSerializerTest.scala +++ b/app-commons-test/src/test/scala/org/bitcoins/commons/json/DLCAcceptJsonSerializerTest.scala @@ -51,7 +51,8 @@ class DLCAcceptJsonSerializerTest extends BitcoinSUnitTest { it must "have serialization symmetry for a accept json message" in { val accept = upickle.default.read[DLCAcceptTLV](testString)( - Picklers.dlcAcceptTLVPickler) + Picklers.dlcAcceptTLVPickler + ) val json: String = upickle.default.write(accept)(Picklers.dlcAcceptTLVPickler) assert(json == testString.replaceAll("\\s", "")) diff --git a/app-commons-test/src/test/scala/org/bitcoins/commons/json/SpendingInfoDbSerializerTest.scala b/app-commons-test/src/test/scala/org/bitcoins/commons/json/SpendingInfoDbSerializerTest.scala index 67232a2f21..a962303272 100644 --- a/app-commons-test/src/test/scala/org/bitcoins/commons/json/SpendingInfoDbSerializerTest.scala +++ b/app-commons-test/src/test/scala/org/bitcoins/commons/json/SpendingInfoDbSerializerTest.scala @@ -11,7 +11,8 @@ class SpendingInfoDbSerializerTest extends BitcoinSUnitTest { it must "be symmetrical" in { val original = TransactionTestUtil.spendingInfoDb val json = upickle.default.writeJs[SpendingInfoDb](original)( - Picklers.spendingInfoDbPickler) + Picklers.spendingInfoDbPickler + ) val parsed = upickle.default.read(json)(Picklers.spendingInfoDbPickler) diff --git a/app-commons-test/src/test/scala/org/bitcoins/commons/util/ServerArgParserTest.scala b/app-commons-test/src/test/scala/org/bitcoins/commons/util/ServerArgParserTest.scala index 390c58dda1..ac69794b36 100644 --- a/app-commons-test/src/test/scala/org/bitcoins/commons/util/ServerArgParserTest.scala +++ b/app-commons-test/src/test/scala/org/bitcoins/commons/util/ServerArgParserTest.scala @@ -13,7 +13,7 @@ class ServerArgParserTest extends BitcoinSUnitTest { it must "handle no command line flags" in { val parser = ServerArgParser(Vector.empty) - //config must be empty + // config must be empty assert(parser.toConfig == ConfigFactory.empty()) } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfig.scala b/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfig.scala index 0ec94a64a8..fdc3a2922e 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfig.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfig.scala @@ -13,38 +13,36 @@ import org.bitcoins.core.compat.JavaConverters._ import scala.util.Properties import scala.util.matching.Regex -/** Everything needed to configure functionality - * of bitcoin-s applications is found in here. +/** Everything needed to configure functionality of bitcoin-s applications is + * found in here. * - * @see [[https://github.com/bitcoin-s/bitcoin-s-core/blob/master/doc/configuration.md `configuration.md`]] - * for more information. + * @see + * [[https://github.com/bitcoin-s/bitcoin-s-core/blob/master/doc/configuration.md `configuration.md`]] + * for more information. */ abstract class AppConfig extends StartStopAsync[Unit] with BitcoinSLogger { - /** Starts this project. - * After this future resolves, all operations should be + /** Starts this project. After this future resolves, all operations should be * able to be performed correctly. * - * Starting may include creating database tables, - * making directories or files needed later or - * something else entirely. + * Starting may include creating database tables, making directories or files + * needed later or something else entirely. */ override def start(): Future[Unit] = { Future.unit } - /** Sub members of AppConfig should override this type with - * the type of themselves, ensuring `withOverrides` return - * the correct type + /** Sub members of AppConfig should override this type with the type of + * themselves, ensuring `withOverrides` return the correct type */ protected[bitcoins] type ConfigType <: AppConfig /** Constructor to make a new instance of this config type */ protected[bitcoins] def newConfigOfType( - configOverrides: Vector[Config]): ConfigType + configOverrides: Vector[Config] + ): ConfigType - /** List of user-provided configs that should - * override defaults + /** List of user-provided configs that should override defaults */ protected[bitcoins] def configOverrides: Vector[Config] @@ -52,14 +50,11 @@ abstract class AppConfig extends StartStopAsync[Unit] with BitcoinSLogger { withOverrides(Vector(configOverrides)) } - /** This method returns a new `AppConfig`, where every - * key under `bitcoin-s` overrides the configuration - * picked up by other means (the `reference.conf` - * provided by bitcoin-s and the `application.conf` - * provided by the user). If you pass in configs with - * overlapping keys (e.g. several configs with the key - * `bitcoin-s.network`), the latter config overrides the - * first. + /** This method returns a new `AppConfig`, where every key under `bitcoin-s` + * overrides the configuration picked up by other means (the `reference.conf` + * provided by bitcoin-s and the `application.conf` provided by the user). If + * you pass in configs with overlapping keys (e.g. several configs with the + * key `bitcoin-s.network`), the latter config overrides the first. */ def withOverrides(configOverrides: Vector[Config]): ConfigType = { val numOverrides = configOverrides.length @@ -180,7 +175,8 @@ object AppConfig extends BitcoinSLogger { def getBaseConfig( baseDatadir: Path, configFileName: String, - configOverrides: Vector[Config]): Config = { + configOverrides: Vector[Config] + ): Config = { val configOptions = ConfigParseOptions .defaults() @@ -195,7 +191,8 @@ object AppConfig extends BitcoinSLogger { val withDatadir = ConfigFactory.parseString( - s"bitcoin-s.datadir = ${safePathToString(baseDatadir)}") + s"bitcoin-s.datadir = ${safePathToString(baseDatadir)}" + ) withDatadir.withFallback(config) } @@ -237,8 +234,8 @@ object AppConfig extends BitcoinSLogger { /** The default data directory * - * TODO: use different directories on Windows and Mac, - * should probably mimic what Bitcoin Core does + * TODO: use different directories on Windows and Mac, should probably mimic + * what Bitcoin Core does */ private[bitcoins] lazy val DEFAULT_BITCOIN_S_DATADIR: Path = Paths.get(Properties.userHome, ".bitcoin-s") @@ -246,9 +243,8 @@ object AppConfig extends BitcoinSLogger { private[bitcoins] lazy val DEFAULT_BITCOIN_S_CONF_FILE: String = "bitcoin-s.conf" - /** Matches the default data directory location - * with a network appended, - * both with and without a trailing `/` + /** Matches the default data directory location with a network appended, both + * with and without a trailing `/` */ private lazy val defaultDatadirRegex: Regex = { // Fix for windows @@ -257,8 +253,8 @@ object AppConfig extends BitcoinSLogger { (home + "/.bitcoin-s/(testnet3|mainnet|regtest)/?$").r } - /** Throws if the encountered datadir is the default one. Useful - * in tests, to make sure you don't blow up important data. + /** Throws if the encountered datadir is the default one. Useful in tests, to + * make sure you don't blow up important data. */ private[bitcoins] def throwIfDefaultDatadir(config: AppConfig): Unit = { val datadirStr = config.datadir.toString() diff --git a/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfigFactory.scala b/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfigFactory.scala index 05fe2edbe6..0fb8070bcb 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfigFactory.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/config/AppConfigFactory.scala @@ -5,7 +5,10 @@ import com.typesafe.config.{Config, ConfigFactory} import java.nio.file.{Path, Paths} import scala.concurrent.ExecutionContext -/** @tparam I - the implicit argument. This is usually an execution context or an actor system */ +/** @tparam I + * \- the implicit argument. This is usually an execution context or an actor + * system + */ trait AppConfigFactoryBase[C <: AppConfig, I] { def moduleName: String @@ -18,13 +21,15 @@ trait AppConfigFactoryBase[C <: AppConfig, I] { fromConfig(ConfigFactory.load()) } - def fromDefaultDatadir(confs: Vector[Config] = Vector.empty)(implicit - i: I): C = { + def fromDefaultDatadir( + confs: Vector[Config] = Vector.empty + )(implicit i: I): C = { fromDatadir(AppConfig.DEFAULT_BITCOIN_S_DATADIR, confs) } def fromDatadir(datadir: Path, confs: Vector[Config] = Vector.empty)(implicit - i: I): C + i: I + ): C } trait AppConfigFactory[C <: AppConfig] diff --git a/app-commons/src/main/scala/org/bitcoins/commons/file/FileUtil.scala b/app-commons/src/main/scala/org/bitcoins/commons/file/FileUtil.scala index fdd5db09b0..15457eb4ab 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/file/FileUtil.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/file/FileUtil.scala @@ -12,17 +12,20 @@ object FileUtil extends BitcoinSLogger { /** Zips the [[directory]] into a zip file and then stores it at [[target]] * - * @see https://www.quickprogrammingtips.com/java/how-to-zip-a-folder-in-java.html + * @see + * https://www.quickprogrammingtips.com/java/how-to-zip-a-folder-in-java.html */ def zipDirectory( source: Path, target: Path, - fileNameFilter: Vector[Regex] = Vector.empty): Path = { + fileNameFilter: Vector[Regex] = Vector.empty + ): Path = { require( !Files.exists(target), - s"Cannot overwrite existing target directory=${target.toAbsolutePath}") + s"Cannot overwrite existing target directory=${target.toAbsolutePath}" + ) - //create directories for target if they DNE + // create directories for target if they DNE Files.createDirectories(target.getParent) val zos = new ZipOutputStream(new FileOutputStream(target.toFile)) @@ -33,16 +36,18 @@ object FileUtil extends BitcoinSLogger { @throws[IOException] override def visitFile( file: Path, - attrs: BasicFileAttributes): FileVisitResult = { + attrs: BasicFileAttributes + ): FileVisitResult = { if ( - fileNameFilter.exists(reg => - file.toAbsolutePath.toString.matches(reg.regex)) + fileNameFilter + .exists(reg => file.toAbsolutePath.toString.matches(reg.regex)) ) { logger.info(s"Skipping ${file.toAbsolutePath} for zip") FileVisitResult.CONTINUE } else { logger.info( - s"Zipping file=${file.toAbsolutePath} to ${target.toAbsolutePath}") + s"Zipping file=${file.toAbsolutePath} to ${target.toAbsolutePath}" + ) zos.putNextEntry(new ZipEntry(source.relativize(file).toString)) Files.copy(file, zos) zos.closeEntry() @@ -63,24 +68,27 @@ object FileUtil extends BitcoinSLogger { def copyDirectory( source: Path, target: Path, - fileNameFilter: Vector[Regex] = Vector.empty): Path = { + fileNameFilter: Vector[Regex] = Vector.empty + ): Path = { Files.walkFileTree( source, new SimpleFileVisitor[Path]() { @throws[IOException] override def visitFile( file: Path, - attrs: BasicFileAttributes): FileVisitResult = { + attrs: BasicFileAttributes + ): FileVisitResult = { if ( - fileNameFilter.exists(reg => - file.toAbsolutePath.toString.matches(reg.regex)) + fileNameFilter + .exists(reg => file.toAbsolutePath.toString.matches(reg.regex)) ) { logger.info(s"Skipping ${file.toAbsolutePath} for copy") FileVisitResult.CONTINUE } else { val targetPath = target.resolve(source.relativize(file)) logger.info( - s"Copying file=${file.toAbsolutePath} to ${targetPath.toAbsolutePath}") + s"Copying file=${file.toAbsolutePath} to ${targetPath.toAbsolutePath}" + ) Files.createDirectories(targetPath.getParent) Files.copy(file, targetPath) logger.info(s"Done copying file=${file.toAbsolutePath}") @@ -100,14 +108,16 @@ object FileUtil extends BitcoinSLogger { new SimpleFileVisitor[Path] { override def visitFile( file: Path, - attrs: BasicFileAttributes): FileVisitResult = { + attrs: BasicFileAttributes + ): FileVisitResult = { Files.delete(file) FileVisitResult.CONTINUE } override def postVisitDirectory( dir: Path, - exc: IOException): FileVisitResult = { + exc: IOException + ): FileVisitResult = { Files.delete(dir) FileVisitResult.CONTINUE } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/BitcoinSServerInfo.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/BitcoinSServerInfo.scala index a953d47a48..637f4d1d2b 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/BitcoinSServerInfo.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/BitcoinSServerInfo.scala @@ -12,7 +12,8 @@ case class BitcoinSServerInfo( blockHash: DoubleSha256DigestBE, torStarted: Boolean, syncing: Boolean, - isInitialBlockDownload: Boolean) { + isInitialBlockDownload: Boolean +) { lazy val toJson: Value = { Obj( @@ -38,11 +39,13 @@ object BitcoinSServerInfo { val sync = obj(PicklerKeys.syncKey).bool val isIBD = obj(PicklerKeys.isInitialBlockDownload).bool - BitcoinSServerInfo(network = network, - blockHeight = height, - blockHash = blockHash, - torStarted = torStarted, - syncing = sync, - isInitialBlockDownload = isIBD) + BitcoinSServerInfo( + network = network, + blockHeight = height, + blockHash = blockHash, + torStarted = torStarted, + syncing = sync, + isInitialBlockDownload = isIBD + ) } } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedPSBT.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedPSBT.scala index 349a63cffe..54151d6c75 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedPSBT.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedPSBT.scala @@ -14,7 +14,8 @@ import scodec.bits.ByteVector case class SerializedPSBT( global: SerializedPSBTGlobalMap, inputs: Vector[SerializedPSBTInputMap], - outputs: Vector[SerializedPSBTOutputMap]) { + outputs: Vector[SerializedPSBTOutputMap] +) { val toJson: JsValue = Json.toJson(this) } @@ -22,7 +23,8 @@ case class SerializedPSBTGlobalMap( tx: SerializedTransaction, version: UInt32, xpubs: Option[Vector[ExtPublicKey]], - unknowns: Vector[GlobalPSBTRecord.Unknown]) + unknowns: Vector[GlobalPSBTRecord.Unknown] +) case class SerializedPSBTInputMap( nonWitnessUtxo: Option[SerializedTransaction], @@ -35,13 +37,15 @@ case class SerializedPSBTInputMap( finalizedScriptSig: Option[Vector[ScriptToken]], finalizedScriptWitness: Option[SerializedTransactionWitness], proofOfReservesCommitment: Option[ByteVector], - unknowns: Vector[InputPSBTRecord.Unknown]) + unknowns: Vector[InputPSBTRecord.Unknown] +) case class SerializedPSBTOutputMap( redeemScript: Option[Vector[ScriptToken]], witScript: Option[Vector[ScriptToken]], bip32Paths: Option[Vector[OutputPSBTRecord.BIP32DerivationPath]], - unknowns: Vector[OutputPSBTRecord.Unknown]) + unknowns: Vector[OutputPSBTRecord.Unknown] +) object SerializedPSBT { @@ -57,7 +61,8 @@ object SerializedPSBT { def decodeInputMap( input: InputPSBTMap, - index: Int): SerializedPSBTInputMap = { + index: Int + ): SerializedPSBTInputMap = { val prevTxOpt = input.nonWitnessOrUnknownUTXOOpt.map(_.transactionSpent) val nonWitnessUtxo = prevTxOpt.map(decodeRawTransaction) val witnessUtxo = input.witnessUTXOOpt.map(rec => @@ -80,17 +85,19 @@ object SerializedPSBT { val unknowns = input.getRecords(PSBTInputKeyId.UnknownKeyId) - SerializedPSBTInputMap(nonWitnessUtxo, - witnessUtxo, - sigsOpt, - hashType, - redeemScript, - witScript, - bip32PathsOpt, - finalizedScriptSig, - finalizedWitScript, - porCommit, - unknowns) + SerializedPSBTInputMap( + nonWitnessUtxo, + witnessUtxo, + sigsOpt, + hashType, + redeemScript, + witScript, + bip32PathsOpt, + finalizedScriptSig, + finalizedWitScript, + porCommit, + unknowns + ) } def decodeOutputMap(output: OutputPSBTMap): SerializedPSBTOutputMap = { diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedTransaction.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedTransaction.scala index 9040e14174..68bdb307bb 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedTransaction.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/SerializedTransaction.scala @@ -26,7 +26,8 @@ case class SerializedTransaction( weight: Long, locktime: UInt32, vin: Vector[SerializedTransactionInput], - vout: Vector[SerializedTransactionOutput]) { + vout: Vector[SerializedTransactionOutput] +) { val toJson: JsValue = Json.toJson(this) } @@ -45,7 +46,8 @@ case class SerializedTransactionWitness( script: Option[Vector[ScriptToken]], pubKey: Option[ECPublicKeyBytes], signature: Option[ECDigitalSignature], - stack: Option[Vector[ByteVector]]) + stack: Option[Vector[ByteVector]] +) case class SerializedTransactionOutput( value: BigDecimal, @@ -65,35 +67,43 @@ object SerializedTransaction { } def decodeRawTransactionWitness( - witness: ScriptWitness): Option[SerializedTransactionWitness] = { + witness: ScriptWitness + ): Option[SerializedTransactionWitness] = { witness match { case EmptyScriptWitness => None case p2wpkh: P2WPKHWitnessV0 => Some( - SerializedTransactionWitness(hex = p2wpkh.hex, - scriptType = Some("P2WPKH"), - script = None, - pubKey = Some(p2wpkh.pubKey), - signature = Some(p2wpkh.signature), - stack = None)) + SerializedTransactionWitness( + hex = p2wpkh.hex, + scriptType = Some("P2WPKH"), + script = None, + pubKey = Some(p2wpkh.pubKey), + signature = Some(p2wpkh.signature), + stack = None + ) + ) case p2wsh: P2WSHWitnessV0 => Some( - SerializedTransactionWitness(hex = p2wsh.hex, - scriptType = Some("P2WSH"), - script = - Some(p2wsh.redeemScript.asm.toVector), - pubKey = None, - signature = None, - stack = Some(p2wsh.stack.toVector.tail))) + SerializedTransactionWitness( + hex = p2wsh.hex, + scriptType = Some("P2WSH"), + script = Some(p2wsh.redeemScript.asm.toVector), + pubKey = None, + signature = None, + stack = Some(p2wsh.stack.toVector.tail) + ) + ) case taprootWitness: TaprootWitness => throw new UnsupportedOperationException( - s"Taproot not supported, got=$taprootWitness") + s"Taproot not supported, got=$taprootWitness" + ) } } def decodeTransactionInput( input: TransactionInput, - witnessOpt: Option[ScriptWitness]): SerializedTransactionInput = { + witnessOpt: Option[ScriptWitness] + ): SerializedTransactionInput = { val decodedWitnessOpt = witnessOpt.flatMap(decodeRawTransactionWitness) SerializedTransactionInput( @@ -108,11 +118,14 @@ object SerializedTransaction { def decodeTransactionOutput( output: TransactionOutput, - index: Int): SerializedTransactionOutput = { - SerializedTransactionOutput(value = output.value.toBigDecimal, - n = UInt32(index), - scriptPubKey = output.scriptPubKey.asm.toVector, - hex = output.hex) + index: Int + ): SerializedTransactionOutput = { + SerializedTransactionOutput( + value = output.value.toBigDecimal, + n = UInt32(index), + scriptPubKey = output.scriptPubKey.asm.toVector, + hex = output.hex + ) } def decodeRawTransaction(tx: Transaction): SerializedTransaction = { @@ -135,14 +148,16 @@ object SerializedTransaction { case wtx: WitnessTransaction => Some(wtx.wTxIdBE) } - SerializedTransaction(txid = tx.txIdBE, - wtxid = wtxIdOpt, - version = tx.version, - size = tx.byteSize, - vsize = tx.vsize, - weight = tx.weight, - locktime = tx.lockTime, - vin = inputs, - vout = outputs) + SerializedTransaction( + txid = tx.txIdBE, + wtxid = wtxIdOpt, + version = tx.version, + size = tx.byteSize, + vsize = tx.vsize, + weight = tx.weight, + locktime = tx.lockTime, + vin = inputs, + vout = outputs + ) } } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/BlockchainResult.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/BlockchainResult.scala index a2ce0a38a0..1bd1bf0495 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/BlockchainResult.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/BlockchainResult.scala @@ -24,8 +24,8 @@ case class DumpTxOutSetResult( coins_written: Int, base_hash: DoubleSha256DigestBE, base_height: Int, - path: Path) - extends BlockchainResult + path: Path +) extends BlockchainResult case class GetBlockResult( hash: DoubleSha256DigestBE, @@ -45,8 +45,8 @@ case class GetBlockResult( difficulty: BigDecimal, chainwork: String, previousblockhash: Option[DoubleSha256DigestBE], - nextblockhash: Option[DoubleSha256DigestBE]) - extends BlockchainResult + nextblockhash: Option[DoubleSha256DigestBE] +) extends BlockchainResult abstract trait GetBlockWithTransactionsResult extends BlockchainResult { def hash: DoubleSha256DigestBE @@ -87,8 +87,8 @@ case class GetBlockWithTransactionsResultV22( difficulty: BigDecimal, chainwork: String, previousblockhash: Option[DoubleSha256DigestBE], - nextblockhash: Option[DoubleSha256DigestBE]) - extends GetBlockWithTransactionsResult + nextblockhash: Option[DoubleSha256DigestBE] +) extends GetBlockWithTransactionsResult sealed trait GetBlockChainInfoResult extends BlockchainResult { def chain: NetworkParameters @@ -121,8 +121,8 @@ case class GetBlockChainInfoResultPreV19( pruneheight: Option[Int], softforks: Vector[SoftforkPreV19], bip9_softforks: Map[String, Bip9SoftforkPreV19], - warnings: String) - extends GetBlockChainInfoResult + warnings: String +) extends GetBlockChainInfoResult case class GetBlockChainInfoResultPostV19( chain: NetworkParameters, @@ -138,8 +138,8 @@ case class GetBlockChainInfoResultPostV19( pruned: Boolean, pruneheight: Option[Int], softforks: Map[String, SoftforkPostV19], - warnings: String) - extends GetBlockChainInfoResult + warnings: String +) extends GetBlockChainInfoResult // adds time field removes softforks field case class GetBlockChainInfoResultPostV23( @@ -156,30 +156,30 @@ case class GetBlockChainInfoResultPostV23( size_on_disk: Long, pruned: Boolean, pruneheight: Option[Int], - warnings: String) - extends GetBlockChainInfoResult + warnings: String +) extends GetBlockChainInfoResult case class SoftforkPreV19( id: String, version: Int, enforce: Option[Map[String, SoftforkProgressPreV19]], - reject: SoftforkProgressPreV19) - extends BlockchainResult + reject: SoftforkProgressPreV19 +) extends BlockchainResult case class SoftforkProgressPreV19( status: Option[Boolean], found: Option[Int], required: Option[Int], - window: Option[Int]) - extends BlockchainResult + window: Option[Int] +) extends BlockchainResult case class Bip9SoftforkPreV19( status: String, bit: Option[Int], startTime: Int, timeout: BigInt, - since: Int) - extends BlockchainResult + since: Int +) extends BlockchainResult sealed trait SoftforkPostV19 extends BlockchainResult @@ -194,8 +194,8 @@ case class Bip9SoftforkDetails( bit: Option[Int], start_time: Int, timeout: BigInt, - since: Int) - extends BlockchainResult + since: Int +) extends BlockchainResult case class GetBlockHeaderResult( hash: DoubleSha256DigestBE, @@ -211,8 +211,8 @@ case class GetBlockHeaderResult( difficulty: BigDecimal, chainwork: String, previousblockhash: Option[DoubleSha256DigestBE], - nextblockhash: Option[DoubleSha256DigestBE]) - extends BlockchainResult { + nextblockhash: Option[DoubleSha256DigestBE] +) extends BlockchainResult { lazy val blockHeaderDb: BlockHeaderDb = { val bytes = ByteVector.fromValidHex(chainwork).dropWhile(_ == 0x00).toArray @@ -222,8 +222,8 @@ case class GetBlockHeaderResult( def blockHeader: BlockHeader = { - //prevblockhash is only empty if we have the genesis block - //we assume the prevhash of the gensis block is the empty hash + // prevblockhash is only empty if we have the genesis block + // we assume the prevhash of the gensis block is the empty hash val prevHash = { if (height == 0 && previousblockhash.isEmpty) { DoubleSha256DigestBE.empty @@ -231,12 +231,14 @@ case class GetBlockHeaderResult( previousblockhash.get } } - BlockHeader(version = Int32(version), - previousBlockHash = prevHash.flip, - merkleRootHash = merkleroot.flip, - time = time, - nBits = bits, - nonce = nonce) + BlockHeader( + version = Int32(version), + previousBlockHash = prevHash.flip, + merkleRootHash = merkleroot.flip, + time = time, + nBits = bits, + nonce = nonce + ) } } @@ -244,8 +246,8 @@ case class ChainTip( height: Int, hash: DoubleSha256DigestBE, branchlen: Int, - status: String) - extends BlockchainResult + status: String +) extends BlockchainResult case class GetChainTxStatsResult( time: UInt32, @@ -254,8 +256,8 @@ case class GetChainTxStatsResult( window_final_block_height: Option[Int], window_tx_count: Option[Int], window_interval: Option[UInt32], - txrate: Option[BigDecimal]) - extends BlockchainResult + txrate: Option[BigDecimal] +) extends BlockchainResult sealed trait GetMemPoolResult extends BlockchainResult { def size: Int @@ -284,8 +286,8 @@ case class GetMemPoolResultPreV19( ancestorfees: Option[Bitcoins], wtxid: DoubleSha256DigestBE, fees: FeeInfo, - depends: Vector[DoubleSha256DigestBE]) - extends GetMemPoolResult + depends: Vector[DoubleSha256DigestBE] +) extends GetMemPoolResult case class GetMemPoolResultPostV19( vsize: Int, @@ -301,8 +303,8 @@ case class GetMemPoolResultPostV19( ancestorfees: Option[Bitcoins], wtxid: DoubleSha256DigestBE, fees: FeeInfo, - depends: Vector[DoubleSha256DigestBE]) - extends GetMemPoolResult { + depends: Vector[DoubleSha256DigestBE] +) extends GetMemPoolResult { override def size: Int = vsize } @@ -317,8 +319,8 @@ case class GetMemPoolResultPostV23( ancestorsize: Int, wtxid: DoubleSha256DigestBE, fees: FeeInfo, - depends: Vector[DoubleSha256DigestBE]) - extends GetMemPoolResult { + depends: Vector[DoubleSha256DigestBE] +) extends GetMemPoolResult { override def size: Int = vsize } @@ -356,8 +358,8 @@ case class GetMemPoolEntryResultPreV19( ancestorfees: BitcoinFeeUnit, wtxid: DoubleSha256DigestBE, fees: FeeInfo, - depends: Option[Vector[DoubleSha256DigestBE]]) - extends GetMemPoolEntryResult + depends: Option[Vector[DoubleSha256DigestBE]] +) extends GetMemPoolEntryResult case class GetMemPoolEntryResultPostV19( vsize: Int, @@ -374,8 +376,8 @@ case class GetMemPoolEntryResultPostV19( ancestorfees: BitcoinFeeUnit, wtxid: DoubleSha256DigestBE, fees: FeeInfo, - depends: Option[Vector[DoubleSha256DigestBE]]) - extends GetMemPoolEntryResult { + depends: Option[Vector[DoubleSha256DigestBE]] +) extends GetMemPoolEntryResult { override def size: Int = vsize } @@ -390,8 +392,8 @@ case class GetMemPoolEntryResultPostV23( ancestorsize: Int, wtxid: DoubleSha256DigestBE, fees: FeeInfo, - depends: Option[Vector[DoubleSha256DigestBE]]) - extends GetMemPoolEntryResult { + depends: Option[Vector[DoubleSha256DigestBE]] +) extends GetMemPoolEntryResult { override def size: Int = vsize } @@ -401,8 +403,8 @@ case class GetMemPoolInfoResult( usage: Int, maxmempool: Int, mempoolminfee: BitcoinFeeUnit, - minrelaytxfee: Bitcoins) - extends BlockchainResult + minrelaytxfee: Bitcoins +) extends BlockchainResult sealed abstract trait GetTxOutResult extends BlockchainResult { def bestblock: DoubleSha256DigestBE @@ -417,8 +419,8 @@ case class GetTxOutResultV22( confirmations: Int, value: Bitcoins, scriptPubKey: RpcScriptPubKeyPostV22, - coinbase: Boolean) - extends GetTxOutResult + coinbase: Boolean +) extends GetTxOutResult case class GetTxOutSetInfoResult( height: Int, @@ -428,17 +430,18 @@ case class GetTxOutSetInfoResult( bogosize: Int, hash_serialized_2: DoubleSha256DigestBE, disk_size: Int, - total_amount: Bitcoins) - extends BlockchainResult + total_amount: Bitcoins +) extends BlockchainResult case class GetBlockFilterResult( filter: GolombFilter, - header: DoubleSha256DigestBE) - extends BlockchainResult { + header: DoubleSha256DigestBE +) extends BlockchainResult { def filterDb( height: Int, - blockHashBE: DoubleSha256DigestBE): CompactFilterDb = { + blockHashBE: DoubleSha256DigestBE + ): CompactFilterDb = { CompactFilterDbHelper.fromGolombFilter(filter, blockHashBE, height) } } @@ -446,7 +449,8 @@ case class GetBlockFilterResult( case class GetTxSpendingPrevOutResult( txid: DoubleSha256DigestBE, vout: Int, - spendingtxid: Option[DoubleSha256DigestBE]) { + spendingtxid: Option[DoubleSha256DigestBE] +) { def outpoint: TransactionOutPoint = TransactionOutPoint(txid, UInt32(vout)) } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/NetworkResult.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/NetworkResult.scala index 1066a69164..0bb40506c2 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/NetworkResult.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/NetworkResult.scala @@ -13,8 +13,8 @@ sealed abstract class NetworkResult case class Node( addednode: URI, connected: Option[Boolean], - addresses: Option[Vector[NodeAddress]]) - extends NetworkResult + addresses: Option[Vector[NodeAddress]] +) extends NetworkResult case class NodeAddress(address: URI, connected: String) extends NetworkResult @@ -22,8 +22,8 @@ case class GetNetTotalsResult( totalbytesrecv: Int, totalbytessent: Int, timemillis: UInt64, - uploadtarget: NetTarget) - extends NetworkResult + uploadtarget: NetTarget +) extends NetworkResult case class NetTarget( timeframe: UInt32, @@ -31,8 +31,8 @@ case class NetTarget( target_reached: Boolean, serve_historical_blocks: Boolean, bytes_left_in_cycle: Int, - time_left_in_cycle: UInt32) - extends NetworkResult + time_left_in_cycle: UInt32 +) extends NetworkResult trait GetNetworkInfoResult extends NetworkResult { def version: Int @@ -65,8 +65,8 @@ case class GetNetworkInfoResultPreV21( relayfee: Bitcoins, incrementalfee: Bitcoins, localaddresses: Vector[NetworkAddress], - warnings: String) - extends GetNetworkInfoResult + warnings: String +) extends GetNetworkInfoResult case class GetNetworkInfoResultPostV21( version: Int, @@ -84,16 +84,16 @@ case class GetNetworkInfoResultPostV21( relayfee: Bitcoins, incrementalfee: Bitcoins, localaddresses: Vector[NetworkAddress], - warnings: String) - extends GetNetworkInfoResult + warnings: String +) extends GetNetworkInfoResult case class Network( name: String, limited: Boolean, reachable: Boolean, proxy: String, - proxy_randomize_credentials: Boolean) - extends NetworkResult + proxy_randomize_credentials: Boolean +) extends NetworkResult case class NetworkAddress(address: String, port: Int, score: Int) extends NetworkResult @@ -127,8 +127,8 @@ case class PeerPostV21( inflight: Vector[Int], bytessent_per_msg: Map[String, Int], bytesrecv_per_msg: Map[String, Int], - minfeefilter: Option[SatoshisPerKiloByte]) - extends Peer { + minfeefilter: Option[SatoshisPerKiloByte] +) extends Peer { override val addnode: Boolean = connection_type == "manual" } @@ -148,8 +148,8 @@ case class PeerV22( minfeefilter: Option[SatoshisPerKiloByte], bip152_hb_to: Boolean, bip152_hb_from: Boolean, - permissions: Vector[String]) - extends Peer { + permissions: Vector[String] +) extends Peer { override val addnode: Boolean = connection_type == "manual" } @@ -186,8 +186,8 @@ case class PeerNetworkInfoPreV21( timeoffset: Int, pingtime: Option[BigDecimal], minping: Option[BigDecimal], - pingwait: Option[BigDecimal]) - extends PeerNetworkInfo + pingwait: Option[BigDecimal] +) extends PeerNetworkInfo case class PeerNetworkInfoPostV21( addr: URI, @@ -208,8 +208,8 @@ case class PeerNetworkInfoPostV21( timeoffset: Int, pingtime: Option[BigDecimal], minping: Option[BigDecimal], - pingwait: Option[BigDecimal]) - extends PeerNetworkInfo + pingwait: Option[BigDecimal] +) extends PeerNetworkInfo trait NodeBan extends NetworkResult { def address: URI @@ -221,8 +221,8 @@ case class NodeBanPreV20( address: URI, banned_until: UInt32, ban_created: UInt32, - ban_reason: String) - extends NodeBan + ban_reason: String +) extends NodeBan case class NodeBanPostV22( address: URI, diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/OtherResult.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/OtherResult.scala index 85c12f166d..f12e8809c8 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/OtherResult.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/OtherResult.scala @@ -40,8 +40,8 @@ case class GetBlockTemplateResult( weightlimit: Int, curtime: UInt32, bits: String, // What should this be? - height: Int) - extends OtherResult + height: Int +) extends OtherResult case class BlockTransaction( data: Transaction, @@ -51,8 +51,8 @@ case class BlockTransaction( fee: Satoshis, sigops: Int, weight: Int, - required: Option[Boolean]) - extends OtherResult + required: Option[Boolean] +) extends OtherResult case class GetMiningInfoResult( blocks: Int, @@ -62,8 +62,8 @@ case class GetMiningInfoResult( networkhashps: BigDecimal, pooledtx: Int, chain: String, - warnings: String) - extends OtherResult + warnings: String +) extends OtherResult case class GetMemoryInfoResult(locked: MemoryManager) extends OtherResult @@ -75,14 +75,12 @@ case class MemoryManager( total: Int, locked: Int, chunks_used: Int, - chunks_free: Int) - extends OtherResult + chunks_free: Int +) extends OtherResult -/** @note This is defined as a trait - * and not just a raw case class - * (as is done in other RPC return - * values) in order to make it possible - * to deprecate fields. +/** @note + * This is defined as a trait and not just a raw case class (as is done in + * other RPC return values) in order to make it possible to deprecate fields. */ trait ValidateAddressResult { @@ -149,14 +147,14 @@ case class ValidateAddressResultImpl( hdmasterkeyid: Option[Sha256Hash160Digest], ischange: Option[Boolean], solvable: Option[Boolean], - desc: Option[String]) - extends ValidateAddressResult + desc: Option[String] +) extends ValidateAddressResult case class EstimateSmartFeeResult( feerate: Option[BitcoinFeeUnit], errors: Option[Vector[String]], - blocks: Int) - extends OtherResult + blocks: Int +) extends OtherResult case class TestMempoolAcceptResult( txid: DoubleSha256DigestBE, @@ -164,17 +162,12 @@ case class TestMempoolAcceptResult( rejectReason: Option[String] ) -/** sealed trait TestMempoolAcceptResult { - * def txid: DoubleSha256DigestBE - * def allowed: Boolean - * def rejectReason: Option[String] - * } +/** sealed trait TestMempoolAcceptResult { def txid: DoubleSha256DigestBE def + * allowed: Boolean def rejectReason: Option[String] } * - * case class TestMempoolAcceptResultPreV22( - * txid: DoubleSha256DigestBE, - * allowed: Boolean, - * rejectReason: Option[String] - * ) extends TestMempoolAcceptResult + * case class TestMempoolAcceptResultPreV22( txid: DoubleSha256DigestBE, + * allowed: Boolean, rejectReason: Option[String] ) extends + * TestMempoolAcceptResult */ case class FeeInfoTwo( diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RawTransactionResult.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RawTransactionResult.scala index 51e8ef496c..ab8469de85 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RawTransactionResult.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RawTransactionResult.scala @@ -33,8 +33,8 @@ case class RpcTransactionV22( locktime: UInt32, vin: Vector[TransactionInput], vout: Vector[RpcTransactionOutputV22], - hex: Option[Transaction]) - extends RpcTransaction + hex: Option[Transaction] +) extends RpcTransaction sealed trait RpcTransactionOutput extends RawTransactionResult { def value: Bitcoins @@ -45,14 +45,14 @@ sealed trait RpcTransactionOutput extends RawTransactionResult { case class RpcTransactionOutputPreV22( value: Bitcoins, n: Int, - scriptPubKey: RpcScriptPubKeyPreV22) - extends RpcTransactionOutput + scriptPubKey: RpcScriptPubKeyPreV22 +) extends RpcTransactionOutput case class RpcTransactionOutputV22( value: Bitcoins, n: Int, - scriptPubKey: RpcScriptPubKeyPostV22) - extends RpcTransactionOutput + scriptPubKey: RpcScriptPubKeyPostV22 +) extends RpcTransactionOutput sealed trait RpcScriptPubKey extends RawTransactionResult { def asm: String @@ -66,16 +66,16 @@ case class RpcScriptPubKeyPreV22( hex: String, reqSigs: Option[Int], scriptType: ScriptType, - addresses: Option[Vector[BitcoinAddress]]) - extends RpcScriptPubKey + addresses: Option[Vector[BitcoinAddress]] +) extends RpcScriptPubKey case class RpcScriptPubKeyPostV22( asm: String, hex: String, scriptType: ScriptType, addresses: Option[Vector[BitcoinAddress]], - address: Option[BitcoinAddress]) - extends RpcScriptPubKey + address: Option[BitcoinAddress] +) extends RpcScriptPubKey sealed trait DecodeScriptResult extends RawTransactionResult { def asm: String @@ -86,14 +86,14 @@ sealed trait DecodeScriptResult extends RawTransactionResult { case class DecodeScriptResultV22( asm: String, typeOfScript: Option[ScriptType], - p2sh: P2SHAddress) - extends DecodeScriptResult + p2sh: P2SHAddress +) extends DecodeScriptResult case class FundRawTransactionResult( hex: Transaction, fee: Bitcoins, - changepos: Int) - extends RawTransactionResult + changepos: Int +) extends RawTransactionResult case class SignRawTransactionWithWalletResult( hex: Transaction, @@ -131,8 +131,8 @@ case class GetRawTransactionResultV22( blockhash: Option[DoubleSha256DigestBE], confirmations: Option[Int], time: Option[UInt32], - blocktime: Option[UInt32]) - extends GetRawTransactionResult + blocktime: Option[UInt32] +) extends GetRawTransactionResult case class GetRawTransactionVin( txid: Option[DoubleSha256DigestBE], @@ -148,16 +148,16 @@ case class GetRawTransactionScriptSig(asm: String, hex: ScriptSignature) case class SignRawTransactionResult( hex: Transaction, complete: Boolean, - errors: Option[Vector[SignRawTransactionError]]) - extends RawTransactionResult + errors: Option[Vector[SignRawTransactionError]] +) extends RawTransactionResult case class SignRawTransactionError( txid: DoubleSha256DigestBE, vout: Int, scriptSig: ScriptPubKey, sequence: UInt32, - error: String) - extends RawTransactionResult + error: String +) extends RawTransactionResult final case class GetRpcInfoResult( active_commands: Vector[RpcCommands] @@ -165,5 +165,5 @@ final case class GetRpcInfoResult( final case class RpcCommands( method: String, - duration: FiniteDuration //this time is in microseconds + duration: FiniteDuration // this time is in microseconds ) extends RawTransactionResult diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RpcOpts.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RpcOpts.scala index 74e5d5f9d7..b9462b1173 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RpcOpts.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RpcOpts.scala @@ -43,7 +43,8 @@ object RpcOpts { lockUnspents: Boolean = false, reverseChangeKey: Boolean = true, feeRate: Option[Bitcoins] = None, - subtractFeeFromOutputs: Option[Vector[Int]]) + subtractFeeFromOutputs: Option[Vector[Int]] + ) sealed abstract class FeeEstimationMode @@ -75,8 +76,9 @@ object RpcOpts { } } - implicit val fundRawTransactionOptionsWrites: Writes[ - FundRawTransactionOptions] = Json.writes[FundRawTransactionOptions] + implicit val fundRawTransactionOptionsWrites + : Writes[FundRawTransactionOptions] = + Json.writes[FundRawTransactionOptions] case class SignRawTransactionOutputParameter( txid: DoubleSha256DigestBE, @@ -84,10 +86,11 @@ object RpcOpts { scriptPubKey: ScriptPubKey, redeemScript: Option[ScriptPubKey] = None, witnessScript: Option[WitnessScriptPubKey] = None, - amount: Option[Bitcoins] = None) + amount: Option[Bitcoins] = None + ) - implicit val signRawTransactionOutputParameterWrites: Writes[ - SignRawTransactionOutputParameter] = + implicit val signRawTransactionOutputParameterWrites + : Writes[SignRawTransactionOutputParameter] = Json.writes[SignRawTransactionOutputParameter] object SignRawTransactionOutputParameter { @@ -97,7 +100,8 @@ object RpcOpts { scriptPubKey: ScriptPubKey, redeemScript: Option[ScriptPubKey] = None, witnessScript: Option[WitnessScriptPubKey] = None, - amount: Option[Bitcoins] = None): SignRawTransactionOutputParameter = { + amount: Option[Bitcoins] = None + ): SignRawTransactionOutputParameter = { SignRawTransactionOutputParameter( txid = transactionInput.previousOutput.txIdBE, vout = transactionInput.previousOutput.vout.toInt, @@ -117,7 +121,8 @@ object RpcOpts { keys: Option[Vector[ECPrivateKeyBytes]] = None, internal: Option[Boolean] = None, watchonly: Option[Boolean] = None, - label: Option[String] = None) + label: Option[String] = None + ) case class ImportMultiAddress(address: BitcoinAddress) @@ -140,7 +145,8 @@ object RpcOpts { object LockUnspentOutputParameter { def fromOutPoint( - outPoint: TransactionOutPoint): LockUnspentOutputParameter = { + outPoint: TransactionOutPoint + ): LockUnspentOutputParameter = { LockUnspentOutputParameter(outPoint.txIdBE, outPoint.vout.toInt) } @@ -216,7 +222,9 @@ object RpcOpts { override def fromString(string: String): AddressType = { fromStringOpt(string).getOrElse( throw new IllegalArgumentException( - s"Could not find AddressType for string: $string")) + s"Could not find AddressType for string: $string" + ) + ) } } @@ -236,7 +244,8 @@ object RpcOpts { case class BlockTemplateRequest( mode: String, capabilities: Vector[String], - rules: Vector[String]) + rules: Vector[String] + ) implicit val blockTemplateRequest: Writes[BlockTemplateRequest] = Json.writes[BlockTemplateRequest] diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RpcPsbtResult.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RpcPsbtResult.scala index 121eb69ab8..664605d1b2 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RpcPsbtResult.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/RpcPsbtResult.scala @@ -35,8 +35,8 @@ final case class DecodePsbtResultV22( unknown: Map[String, String], inputs: Vector[RpcPsbtInputV22], outputs: Vector[RpcPsbtOutput], - fee: Option[Bitcoins]) - extends DecodePsbtResult + fee: Option[Bitcoins] +) extends DecodePsbtResult sealed abstract class RpcPsbtInput extends RpcPsbtResult { def nonWitnessUtxo: Option[RpcTransaction] diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/WalletResult.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/WalletResult.scala index e0785917f7..0131023483 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/WalletResult.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/bitcoind/WalletResult.scala @@ -30,15 +30,16 @@ case class MultiSigResultPostV20( address: BitcoinAddress, redeemScript: ScriptPubKey, descriptor: String, - warnings: Option[String]) //available in v23 + warnings: Option[String] +) //available in v23 extends MultiSigResult case class BumpFeeResult( txid: DoubleSha256DigestBE, origfee: Bitcoins, fee: Bitcoins, // TODO: Should be BitcoinFeeUnit - errors: Vector[String]) - extends WalletResult + errors: Vector[String] +) extends WalletResult case class GetTransactionResult( amount: Bitcoins, @@ -56,14 +57,14 @@ case class GetTransactionResult( comment: Option[String], to: Option[String], details: Vector[TransactionDetails], - hex: Transaction) - extends WalletResult + hex: Transaction +) extends WalletResult case class SetWalletFlagResult( flag_name: String, flag_state: Boolean, - warnings: Option[String]) - extends WalletResult + warnings: Option[String] +) extends WalletResult case class GetBalancesResult(mine: BalanceInfo, watchonly: Option[BalanceInfo]) extends WalletResult @@ -71,7 +72,8 @@ case class GetBalancesResult(mine: BalanceInfo, watchonly: Option[BalanceInfo]) case class BalanceInfo( trusted: Bitcoins, untrusted_pending: Bitcoins, - immature: Bitcoins) + immature: Bitcoins +) case class TransactionDetails( involvesWatchonly: Option[Boolean], @@ -81,8 +83,8 @@ case class TransactionDetails( amount: Bitcoins, vout: Int, fee: Option[Bitcoins], - abandoned: Option[Boolean]) - extends WalletResult + abandoned: Option[Boolean] +) extends WalletResult sealed trait GetWalletInfoResult extends WalletResult { def walletname: String @@ -114,8 +116,8 @@ case class GetWalletInfoResultPostV22( hdmasterkeyid: Option[Sha256Hash160Digest], unlocked_until: Option[Int], private_keys_enabled: Boolean, - descriptors: Boolean) - extends GetWalletInfoResult + descriptors: Boolean +) extends GetWalletInfoResult case class ImportMultiResult(success: Boolean, error: Option[ImportMultiError]) extends WalletResult @@ -125,15 +127,15 @@ case class ImportMultiError(code: Int, message: String) extends WalletResult case class RpcAddress( address: BitcoinAddress, balance: Bitcoins, - account: Option[String]) - extends WalletResult + account: Option[String] +) extends WalletResult case class RpcAccount( involvesWatchonly: Boolean, account: String, amount: Bitcoins, - confirmations: Int) - extends WalletResult + confirmations: Int +) extends WalletResult case class LoadWalletResult(name: String, warning: String) extends WalletResult case class RescanBlockChainResult(start_height: Int, stop_height: Int) @@ -146,28 +148,28 @@ case class ReceivedAddress( amount: Bitcoins, confirmations: Int, label: String, - txids: Vector[DoubleSha256DigestBE]) - extends WalletResult + txids: Vector[DoubleSha256DigestBE] +) extends WalletResult case class ReceivedAccount( involvesWatchonly: Option[Boolean], account: String, amount: Bitcoins, confirmations: Int, - lable: Option[String]) - extends WalletResult + lable: Option[String] +) extends WalletResult case class ReceivedLabel( involvesWatchonly: Option[Boolean], amount: Bitcoins, confirmations: Int, - label: String) - extends WalletResult + label: String +) extends WalletResult case class ListSinceBlockResult( transactions: Vector[Payment], - lastblock: DoubleSha256DigestBE) - extends WalletResult + lastblock: DoubleSha256DigestBE +) extends WalletResult case class Payment( involvesWatchonly: Option[Boolean], @@ -188,8 +190,8 @@ case class Payment( timereceived: UInt32, bip125_replaceable: String, comment: Option[String], - to: Option[String]) - extends WalletResult + to: Option[String] +) extends WalletResult case class ListTransactionsResult( account: Option[String], @@ -214,8 +216,8 @@ case class ListTransactionsResult( to: Option[String], otheraccount: Option[String], bip125_replaceable: String, - abandoned: Option[Boolean]) - extends WalletResult + abandoned: Option[Boolean] +) extends WalletResult case class UnspentOutput( txid: DoubleSha256DigestBE, @@ -228,8 +230,8 @@ case class UnspentOutput( confirmations: Int, spendable: Boolean, solvable: Boolean, - reused: Option[Boolean]) - extends WalletResult + reused: Option[Boolean] +) extends WalletResult sealed trait AddressInfoResult extends WalletResult { def address: BitcoinAddress @@ -274,8 +276,8 @@ case class AddressInfoResultPreV18( hdkeypath: Option[BIP32Path], hdseedid: Option[RipeMd160Digest], hdmasterkeyid: Option[RipeMd160Digest], - labels: Vector[LabelResult]) - extends AddressInfoResult + labels: Vector[LabelResult] +) extends AddressInfoResult // The split into two case classes is to deal with the 22 param limit for case classes case class AddressInfoResultPostV18( @@ -297,8 +299,8 @@ case class AddressInfoResultPostV18( hdkeypath: Option[BIP32Path], hdseedid: Option[RipeMd160Digest], hdmasterfingerprint: Option[String], - labels: Vector[LabelResult]) - extends AddressInfoResult { + labels: Vector[LabelResult] +) extends AddressInfoResult { override def ismine: Boolean = isProps.ismine def solvable: Boolean = isProps.solvable override def iswatchonly: Boolean = isProps.iswatchonly @@ -315,7 +317,8 @@ object AddressInfoResultPostV18 { iswatchonly: Boolean, isscript: Boolean, iswitness: Boolean, - iscompressed: Option[Boolean]) + iscompressed: Option[Boolean] + ) case class AddressInfoResultPostV18WithoutIsProps( address: BitcoinAddress, @@ -335,11 +338,13 @@ object AddressInfoResultPostV18 { hdkeypath: Option[BIP32Path], hdseedid: Option[RipeMd160Digest], hdmasterfingerprint: Option[String], - labels: Vector[LabelResult]) + labels: Vector[LabelResult] + ) def apply( info: AddressInfoResultPostV18WithoutIsProps, - isProps: AddressInfoIsProps): AddressInfoResultPostV18 = { + isProps: AddressInfoIsProps + ): AddressInfoResultPostV18 = { AddressInfoResultPostV18( address = info.address, scriptPubKey = info.scriptPubKey, @@ -401,7 +406,8 @@ object AddressInfoResultPostV21 { iswatchonly: Boolean, isscript: Boolean, iswitness: Boolean, - iscompressed: Option[Boolean]) + iscompressed: Option[Boolean] + ) case class AddressInfoResultPostV21WithoutIsProps( address: BitcoinAddress, @@ -420,11 +426,13 @@ object AddressInfoResultPostV21 { hdkeypath: Option[BIP32Path], hdseedid: Option[RipeMd160Digest], hdmasterfingerprint: Option[String], - labels: Vector[String]) + labels: Vector[String] + ) def apply( info: AddressInfoResultPostV21WithoutIsProps, - isProps: AddressInfoIsProps): AddressInfoResultPostV21 = { + isProps: AddressInfoIsProps + ): AddressInfoResultPostV21 = { AddressInfoResultPostV21( address = info.address, scriptPubKey = info.scriptPubKey, @@ -474,8 +482,8 @@ case class EmbeddedResult( witness_program: Option[String], pubkey: ECPublicKey, address: BitcoinAddress, - scriptPubKey: ScriptPubKey) - extends WalletResult + scriptPubKey: ScriptPubKey +) extends WalletResult case class LabelResult(name: String, purpose: LabelPurpose) extends WalletResult @@ -494,5 +502,5 @@ final case class CreateWalletResult( case class ImportDescriptorResult( success: Boolean, - warnings: Option[Vector[String]]) - extends WalletResult + warnings: Option[Vector[String]] +) extends WalletResult diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/cli/ContractDescriptorParser.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/cli/ContractDescriptorParser.scala index 147177fc0c..16fd572989 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/cli/ContractDescriptorParser.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/cli/ContractDescriptorParser.scala @@ -18,34 +18,40 @@ object ContractDescriptorParser { def parseCmdLine( value: ujson.Value, - announcementTLV: OracleAnnouncementTLV): ContractDescriptorTLV = { + announcementTLV: OracleAnnouncementTLV + ): ContractDescriptorTLV = { value match { case obj: Obj => upickle.default .read[ContractDescriptorV0TLV](obj)(Picklers.contractDescriptorV0) case arr: Arr => - //we read the number of digits from the announcement, - //take in tlv points for the payout curve - //and don't provide access to give a rounding mode as a parameter + // we read the number of digits from the announcement, + // take in tlv points for the payout curve + // and don't provide access to give a rounding mode as a parameter val payoutPoints: Vector[TLVPoint] = arr.value.toVector.map { pointJs => upickle.default .read[TLVPoint](pointJs)(Picklers.tlvPointReader) } val payoutCurve = DLCPayoutCurve - .fromPoints(payoutPoints, - serializationVersion = DLCSerializationVersion.Beta) + .fromPoints( + payoutPoints, + serializationVersion = DLCSerializationVersion.Beta + ) .toTLV val numDigits = announcementTLV.eventTLV.eventDescriptor .asInstanceOf[DigitDecompositionEventDescriptorV0TLV] .numDigits .toInt - ContractDescriptorV1TLV(numDigits, - payoutCurve, - RoundingIntervalsV0TLV.noRounding) + ContractDescriptorV1TLV( + numDigits, + payoutCurve, + RoundingIntervalsV0TLV.noRounding + ) case fail @ (_: Num | _: Bool | Null | _: Str) => sys.error( - s"Cannot parse contract descriptor from $fail, expected json object or array") + s"Cannot parse contract descriptor from $fail, expected json object or array" + ) } } } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/clightning/CLightningJsonModels.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/clightning/CLightningJsonModels.scala index ca36df7aef..ff06c49e11 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/clightning/CLightningJsonModels.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/clightning/CLightningJsonModels.scala @@ -94,8 +94,8 @@ object CLightningJsonModels { case class ListFundsResult( outputs: Vector[Output], - channels: Vector[ChannelFunds]) - extends CLightningJsonModel + channels: Vector[ChannelFunds] + ) extends CLightningJsonModel case class Channel( source: NodeId, @@ -159,8 +159,8 @@ object CLightningJsonModels { connected: Boolean, features: ByteVector, netaddr: Vector[String], - channels: Vector[CLightningPeerChannel]) - extends CLightningJsonModel + channels: Vector[CLightningPeerChannel] + ) extends CLightningJsonModel case class CLightningPeers(peers: Vector[CLightningPeer]) extends CLightningJsonModel @@ -228,8 +228,8 @@ object CLightningJsonModels { ) extends CLightningJsonModel case class CLightningListInvoicesResult( - invoices: Vector[CLightningLookupInvoiceResult]) - extends CLightningJsonModel + invoices: Vector[CLightningLookupInvoiceResult] + ) extends CLightningJsonModel case class CLightningPsbtResult(signed_psbt: PSBT) extends CLightningJsonModel diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/eclair/EclairModels.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/eclair/EclairModels.scala index 9bc9fad903..88ff18a856 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/eclair/EclairModels.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/eclair/EclairModels.scala @@ -33,22 +33,27 @@ case class GetInfoResult( network: BitcoinNetwork, blockHeight: Long, publicAddresses: Seq[InetSocketAddress], - instanceId: UUID) + instanceId: UUID +) case class PeerInfo( nodeId: NodeId, state: PeerState, address: Option[String], - channels: Int) + channels: Int +) case class ChannelCommandResult( - results: scala.collection.Map[ - Either[ShortChannelId, FundedChannelId], - State] + results: scala.collection.Map[Either[ + ShortChannelId, + FundedChannelId + ], + State] ) case class UpdateRelayFeeResult( - results: Map[Either[ShortChannelId, FundedChannelId], UpdateRelayFee]) + results: Map[Either[ShortChannelId, FundedChannelId], UpdateRelayFee] +) sealed trait UpdateRelayFee @@ -57,8 +62,8 @@ object UpdateRelayFee { case class OK( channelId: ChannelId, feeBaseMsat: MilliSatoshis, - feeProportionalMillionths: Long) - extends UpdateRelayFee + feeProportionalMillionths: Long + ) extends UpdateRelayFee case class Error(message: String) extends UpdateRelayFee } @@ -84,12 +89,10 @@ object ChannelCommandResult extends StringFactory[State] { } } -/** This is the data model returned by the RPC call - * `channels nodeId`. The content of the objects - * being returne differ based on whatever state - * the channel is in. The member of this abstract - * class are in eveyr channel state, whereas other - * channel states may have extra information. +/** This is the data model returned by the RPC call `channels nodeId`. The + * content of the objects being returne differ based on whatever state the + * channel is in. The member of this abstract class are in eveyr channel state, + * whereas other channel states may have extra information. */ sealed abstract class ChannelInfo { def nodeId: NodeId @@ -111,8 +114,8 @@ case class BaseChannelInfo( state: ChannelState ) extends ChannelInfo -/** This represents the case where the channel is - * in state `NORMAL` (i.e. an open channel) +/** This represents the case where the channel is in state `NORMAL` (i.e. an + * open channel) */ case class OpenChannelInfo( nodeId: NodeId, @@ -129,7 +132,8 @@ case class UnknownFeature(bitIndex: Int) case class Features( activated: Set[ActivatedFeature], - unknown: Set[UnknownFeature]) + unknown: Set[UnknownFeature] +) case class NodeInfo( signature: ECDigitalSignature, @@ -138,7 +142,8 @@ case class NodeInfo( nodeId: NodeId, rgbColor: String, alias: String, - addresses: Vector[InetSocketAddress]) + addresses: Vector[InetSocketAddress] +) case class ChannelDesc(shortChannelId: ShortChannelId, a: NodeId, b: NodeId) @@ -154,7 +159,7 @@ case class NetworkFeesResult( txId: DoubleSha256DigestBE, fee: Satoshis, txType: String, - timestamp: Instant //milliseconds + timestamp: Instant // milliseconds ) case class ChannelStats( @@ -189,7 +194,8 @@ case class RealChannelId(status: String, realScid: ShortChannelId) case class ShortIds( real: RealChannelId, localAlias: String, - remoteAlias: String) + remoteAlias: String +) case class UsableBalancesResult( remoteNodeId: NodeId, @@ -210,7 +216,7 @@ object ReceivedPayment { case class Part( amount: MilliSatoshis, fromChannelId: FundedChannelId, - timestamp: Instant //milliseconds + timestamp: Instant // milliseconds ) } @@ -220,7 +226,7 @@ case class RelayedPayment( paymentHash: Sha256Digest, fromChannelId: FundedChannelId, toChannelId: FundedChannelId, - timestamp: Instant //milliseconds + timestamp: Instant // milliseconds ) case class SentPayment( @@ -239,7 +245,7 @@ object SentPayment { amount: MilliSatoshis, feesPaid: MilliSatoshis, toChannelId: FundedChannelId, - timestamp: Instant //milliseconds + timestamp: Instant // milliseconds ) } @@ -249,13 +255,14 @@ case class ChannelUpdate( signature: ECDigitalSignature, chainHash: DoubleSha256Digest, shortChannelId: ShortChannelId, - timestamp: Instant, //seconds + timestamp: Instant, // seconds channelFlags: ChannelFlags, cltvExpiryDelta: Int, htlcMinimumMsat: MilliSatoshis, feeProportionalMillionths: FeeProportionalMillionths, htlcMaximumMsat: Option[MilliSatoshis], - feeBaseMsat: MilliSatoshis) + feeBaseMsat: MilliSatoshis +) case class ChannelResult( nodeId: NodeId, @@ -263,7 +270,8 @@ case class ChannelResult( state: ChannelState, feeBaseMsat: Option[MilliSatoshis], feeProportionalMillionths: Option[FeeProportionalMillionths], - data: JsObject) { + data: JsObject +) { lazy val shortChannelId: Option[ShortChannelId] = (data \ "shortIds" \ "real" \ "realScid").validate[ShortChannelId].asOpt @@ -273,12 +281,13 @@ case class ChannelResult( case class InvoiceResult( prefix: LnHumanReadablePart, - timestamp: Instant, //seconds + timestamp: Instant, // seconds nodeId: NodeId, serialized: String, description: String, paymentHash: Sha256Digest, - expiry: FiniteDuration) + expiry: FiniteDuration +) case class PaymentId(value: UUID) { override def toString: String = value.toString @@ -288,16 +297,17 @@ case class SendToRouteResult(paymentId: PaymentId, parentId: PaymentId) case class PaymentRequest( prefix: LnHumanReadablePart, - timestamp: Instant, //seconds + timestamp: Instant, // seconds nodeId: NodeId, serialized: String, description: String, paymentHash: Sha256Digest, paymentMetadata: String, - expiry: FiniteDuration, //seconds + expiry: FiniteDuration, // seconds minFinalCltvExpiry: Int, amount: Option[MilliSatoshis], - features: Features) + features: Features +) sealed trait PaymentType @@ -314,7 +324,7 @@ object PaymentType extends StringFactory[PaymentType] { case "SwapIn" => SwapIn case "SwapOut" => SwapOut case "placeholder" => Placeholder - case _ => throw new RuntimeException(s"Unknown payment type `$str`") + case _ => throw new RuntimeException(s"Unknown payment type `$str`") } } @@ -328,16 +338,18 @@ case class OutgoingPayment( amount: MilliSatoshis, recipientAmount: MilliSatoshis, recipientNodeId: NodeId, - createdAt: Instant, //milliseconds + createdAt: Instant, // milliseconds paymentRequest: Option[PaymentRequest], - status: OutgoingPaymentStatus) + status: OutgoingPaymentStatus +) case class IncomingPayment( paymentRequest: PaymentRequest, paymentPreimage: PaymentPreimage, paymentType: PaymentType, - createdAt: Instant, //milliseconds - status: IncomingPaymentStatus) + createdAt: Instant, // milliseconds + status: IncomingPaymentStatus +) sealed trait IncomingPaymentStatus @@ -349,7 +361,7 @@ object IncomingPaymentStatus { case class Received( amount: MilliSatoshis, - receivedAt: Instant //milliseconds + receivedAt: Instant // milliseconds ) extends IncomingPaymentStatus } @@ -363,7 +375,7 @@ object OutgoingPaymentStatus { paymentPreimage: PaymentPreimage, feesPaid: MilliSatoshis, route: Seq[Hop], - completedAt: Instant //milliseconds + completedAt: Instant // milliseconds ) extends OutgoingPaymentStatus case class Failed(failures: Seq[PaymentFailure], completedAt: Instant) @@ -373,7 +385,8 @@ object OutgoingPaymentStatus { case class PaymentFailure( failureType: PaymentFailure.Type, failureMessage: String, - failedRoute: Seq[Hop]) + failedRoute: Seq[Hop] +) object PaymentFailure { sealed trait Type @@ -385,7 +398,8 @@ object PaymentFailure { case class Hop( nodeId: NodeId, nextNodeId: NodeId, - shortChannelId: Option[ShortChannelId]) + shortChannelId: Option[ShortChannelId] +) sealed trait WebSocketEvent @@ -397,7 +411,7 @@ object WebSocketEvent { paymentHash: Sha256Digest, fromChannelId: FundedChannelId, toChannelId: FundedChannelId, - timestamp: Instant //milliseconds + timestamp: Instant // milliseconds ) extends WebSocketEvent case class PaymentReceived( @@ -442,7 +456,7 @@ object WebSocketEvent { case class PaymentSettlingOnchain( amount: MilliSatoshis, paymentHash: Sha256Digest, - timestamp: Instant //milliseconds + timestamp: Instant // milliseconds ) extends WebSocketEvent } @@ -456,4 +470,5 @@ case class WalletTransaction( blockHash: DoubleSha256DigestBE, confirmations: Long, txid: DoubleSha256DigestBE, - timestamp: Long) + timestamp: Long +) diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/lnd/LndModels.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/lnd/LndModels.scala index 64ccf312ef..397ef97445 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/lnd/LndModels.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/lnd/LndModels.scala @@ -16,8 +16,8 @@ case class AddInvoiceResult( rHash: PaymentHashTag, invoice: LnInvoice, addIndex: UInt64, - paymentAddr: ByteVector) - extends LndModel + paymentAddr: ByteVector +) extends LndModel case class UTXOResult( address: BitcoinAddress, diff --git a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/ws/WsModels.scala b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/ws/WsModels.scala index a96da9804f..b992d32cc7 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/ws/WsModels.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/jsonmodels/ws/WsModels.scala @@ -14,7 +14,9 @@ import ujson.Value import java.net.InetSocketAddress -/** The event type being sent over the websocket. An example is [[WalletWsType.NewAddress]] */ +/** The event type being sent over the websocket. An example is + * [[WalletWsType.NewAddress]] + */ sealed trait WsType object WsType extends StringFactory[WsType] { @@ -46,15 +48,17 @@ object WalletWsType extends StringFactory[WalletWsType] { case object FeeRateChange extends WalletWsType private val all = - Vector(TxProcessed, - TxBroadcast, - ReservedUtxos, - NewAddress, - DLCStateChange, - DLCOfferAdd, - DLCOfferRemove, - RescanComplete, - FeeRateChange) + Vector( + TxProcessed, + TxBroadcast, + ReservedUtxos, + NewAddress, + DLCStateChange, + DLCOfferAdd, + DLCOfferRemove, + RescanComplete, + FeeRateChange + ) override def fromStringOpt(string: String): Option[WalletWsType] = { all.find(_.toString.toLowerCase() == string.toLowerCase) @@ -140,9 +144,9 @@ object DLCNodeWsType extends StringFactory[DLCNodeWsType] { } } -/** A notification that we send over the websocket. - * The type of the notification is indicated by [[WsType]]. - * An example is [[org.bitcoins.commons.jsonmodels.ws.WalletNotification.NewAddressNotification]] +/** A notification that we send over the websocket. The type of the notification + * is indicated by [[WsType]]. An example is + * [[org.bitcoins.commons.jsonmodels.ws.WalletNotification.NewAddressNotification]] * This sends a notification that the wallet generated a new address */ sealed trait WsNotification[T] { @@ -263,13 +267,14 @@ object ChainNotification { } case class CompactFilterHeaderProcessedNotification( - payload: CompactFilterHeaderDb) - extends ChainNotification[CompactFilterHeaderDb] { + payload: CompactFilterHeaderDb + ) extends ChainNotification[CompactFilterHeaderDb] { override val `type`: ChainWsType = ChainWsType.CompactFilterHeaderProcessed override val json: ujson.Value = { upickle.default.writeJs(this)( - WsPicklers.compactFilterHeaderProcessedPickler) + WsPicklers.compactFilterHeaderProcessedPickler + ) } } @@ -311,7 +316,8 @@ object DLCNodeNotification { override def `type`: DLCNodeWsType = DLCNodeWsType.DLCConnectionInitiated override def json: Value = upickle.default.writeJs(this)( - WsPicklers.dlcNodeConnectionInitiatedPickler) + WsPicklers.dlcNodeConnectionInitiatedPickler + ) } case class DLCNodeConnectionEstablished(payload: InetSocketAddress) @@ -319,7 +325,8 @@ object DLCNodeNotification { override def `type`: DLCNodeWsType = DLCNodeWsType.DLCConnectionEstablished override def json: Value = upickle.default.writeJs(this)( - WsPicklers.dlcNodeConnectionEstablishedPickler) + WsPicklers.dlcNodeConnectionEstablishedPickler + ) } case class DLCNodeConnectionFailed(payload: InetSocketAddress) diff --git a/app-commons/src/main/scala/org/bitcoins/commons/rpc/Command.scala b/app-commons/src/main/scala/org/bitcoins/commons/rpc/Command.scala index d0292ef995..ff27d874ea 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/rpc/Command.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/rpc/Command.scala @@ -91,8 +91,8 @@ object GetNewAddress extends ServerJsonModels { case class LockUnspent( unlock: Boolean, - outputParam: Vector[LockUnspentOutputParameter]) - extends CliCommand + outputParam: Vector[LockUnspentOutputParameter] +) extends CliCommand with AppServerCliCommand object LockUnspent extends ServerJsonModels { @@ -109,7 +109,9 @@ object LockUnspent extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -132,7 +134,9 @@ object LabelAddress extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -154,7 +158,9 @@ object GetAddressTags extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -176,7 +182,9 @@ object GetAddressLabel extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -197,7 +205,9 @@ object DropAddressLabel extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -219,7 +229,9 @@ object DropAddressLabels extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -231,8 +243,10 @@ case class GetBalance(isSats: Boolean) object GetBalance extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[GetBalance] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(GetBalance(jsArr.arr.head.bool)) } @@ -245,8 +259,10 @@ case class GetConfirmedBalance(isSats: Boolean) object GetConfirmedBalance extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[GetConfirmedBalance] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(GetConfirmedBalance(jsArr.arr.head.bool)) } @@ -259,8 +275,10 @@ case class GetUnconfirmedBalance(isSats: Boolean) object GetUnconfirmedBalance extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[GetUnconfirmedBalance] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(GetUnconfirmedBalance(jsArr.arr.head.bool)) } @@ -273,8 +291,10 @@ case class GetAddressInfo(address: BitcoinAddress) object GetAddressInfo extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[GetAddressInfo] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) val address = jsToBitcoinAddress(jsArr.arr.head) @@ -289,8 +309,10 @@ case class SendRawTransaction(tx: Transaction) object SendRawTransaction extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[SendRawTransaction] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(SendRawTransaction(jsToTx(jsArr.arr.head))) } @@ -298,8 +320,8 @@ object SendRawTransaction extends ServerJsonModels { case class KeyManagerPassphraseChange( oldPassword: AesPassword, - newPassword: AesPassword) - extends CliCommand + newPassword: AesPassword +) extends CliCommand with AppServerCliCommand object KeyManagerPassphraseChange extends ServerJsonModels { @@ -316,11 +338,15 @@ object KeyManagerPassphraseChange extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing old password and new password arguments")) + "Missing old password and new password arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -344,15 +370,17 @@ object KeyManagerPassphraseSet extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } case class ExportSeed( walletNameOpt: Option[String], - passwordOpt: Option[AesPassword]) - extends CliCommand + passwordOpt: Option[AesPassword] +) extends CliCommand with AppServerCliCommand object ExportSeed extends ServerJsonModels { @@ -365,8 +393,8 @@ object ExportSeed extends ServerJsonModels { case class MarkSeedAsBackedUp( walletNameOpt: Option[String], - passwordOpt: Option[AesPassword]) - extends CliCommand + passwordOpt: Option[AesPassword] +) extends CliCommand with AppServerCliCommand object MarkSeedAsBackedUp extends ServerJsonModels { @@ -379,8 +407,8 @@ object MarkSeedAsBackedUp extends ServerJsonModels { case class GetSeedBackupTime( walletNameOpt: Option[String], - passwordOpt: Option[AesPassword]) - extends CliCommand + passwordOpt: Option[AesPassword] +) extends CliCommand with AppServerCliCommand object GetSeedBackupTime extends ServerJsonModels { @@ -394,8 +422,8 @@ object GetSeedBackupTime extends ServerJsonModels { case class ImportSeed( walletNameOpt: Option[String], mnemonic: MnemonicCode, - passwordOpt: Option[AesPassword]) - extends CliCommand + passwordOpt: Option[AesPassword] +) extends CliCommand with AppServerCliCommand object ImportSeed extends ServerJsonModels { @@ -420,11 +448,15 @@ object ImportSeed extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing walletName, mnemonic, and password argument")) + "Missing walletName, mnemonic, and password argument" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 3")) + s"Bad number of arguments: ${other.length}. Expected: 3" + ) + ) } } } @@ -432,8 +464,8 @@ object ImportSeed extends ServerJsonModels { case class ImportXprv( walletNameOpt: Option[String], xprv: ExtPrivateKey, - passwordOpt: Option[AesPassword]) - extends CliCommand + passwordOpt: Option[AesPassword] +) extends CliCommand with AppServerCliCommand object ImportXprv extends ServerJsonModels { @@ -458,11 +490,15 @@ object ImportXprv extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing walletName, xprv, and password argument")) + "Missing walletName, xprv, and password argument" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 3")) + s"Bad number of arguments: ${other.length}. Expected: 3" + ) + ) } } } @@ -470,8 +506,8 @@ object ImportXprv extends ServerJsonModels { case class CreateMultisig( requiredKeys: Int, keys: Vector[ECPublicKey], - addressType: AddressType) - extends CliCommand + addressType: AddressType +) extends CliCommand with AppServerCliCommand object CreateMultisig extends ServerJsonModels { @@ -498,11 +534,15 @@ object CreateMultisig extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing requiredKeys, keys, and addressType argument")) + "Missing requiredKeys, keys, and addressType argument" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 3")) + s"Bad number of arguments: ${other.length}. Expected: 3" + ) + ) } } } @@ -514,8 +554,10 @@ case class CombinePSBTs(psbts: Seq[PSBT]) object CombinePSBTs extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[CombinePSBTs] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(CombinePSBTs(jsToPSBTSeq(jsArr.arr.head))) } @@ -539,8 +581,10 @@ case class FinalizePSBT(psbt: PSBT) extends CliCommand with AppServerCliCommand object FinalizePSBT extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[FinalizePSBT] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(FinalizePSBT(jsToPSBT(jsArr.arr.head))) } @@ -553,8 +597,10 @@ case class ExtractFromPSBT(psbt: PSBT) object ExtractFromPSBT extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[ExtractFromPSBT] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(ExtractFromPSBT(jsToPSBT(jsArr.arr.head))) } @@ -567,8 +613,10 @@ case class ConvertToPSBT(tx: Transaction) object ConvertToPSBT extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[ConvertToPSBT] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(ConvertToPSBT(jsToTx(jsArr.arr.head))) } @@ -582,8 +630,10 @@ object GetBlockHeader extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[GetBlockHeader] = Try { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) GetBlockHeader(DoubleSha256DigestBE(jsArr.arr.head.str)) } @@ -604,7 +654,9 @@ object DecodeRawTransaction extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -623,7 +675,9 @@ object DecodePSBT extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -641,7 +695,9 @@ object AnalyzePSBT extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -651,8 +707,8 @@ case class Rescan( startBlock: Option[BlockStamp], endBlock: Option[BlockStamp], force: Boolean, - ignoreCreationTime: Boolean) - extends CliCommand + ignoreCreationTime: Boolean +) extends CliCommand with AppServerCliCommand object Rescan extends ServerJsonModels { @@ -693,11 +749,13 @@ object Rescan extends ServerJsonModels { val end = parseBlockStamp(endJs) val force = parseBoolean(forceJs) val ignoreCreationTime = parseBoolean(ignoreCreationTimeJs) - Rescan(batchSize = batchSize, - startBlock = start, - endBlock = end, - force = force, - ignoreCreationTime = ignoreCreationTime) + Rescan( + batchSize = batchSize, + startBlock = start, + endBlock = end, + force = force, + ignoreCreationTime = ignoreCreationTime + ) } case Nil => Failure(new IllegalArgumentException("Missing addresses")) @@ -705,7 +763,9 @@ object Rescan extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 5")) + s"Bad number of arguments: ${other.length}. Expected: 5" + ) + ) } } @@ -718,8 +778,10 @@ case class GetTransaction(txId: DoubleSha256DigestBE) object GetTransaction extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[GetTransaction] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(GetTransaction(DoubleSha256DigestBE(jsArr.arr.head.str))) } @@ -729,8 +791,8 @@ case class SendToAddress( destination: BitcoinAddress, amount: Bitcoins, satoshisPerVirtualByte: Option[SatoshisPerVirtualByte], - noBroadcast: Boolean) - extends CliCommand + noBroadcast: Boolean +) extends CliCommand with Broadcastable with SendCliCommand @@ -753,12 +815,16 @@ object SendToAddress extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing address, amount, and fee rate arguments")) + "Missing address, amount, and fee rate arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 4")) + s"Bad number of arguments: ${other.length}. Expected: 4" + ) + ) } } @@ -785,7 +851,9 @@ case object GetDLCs case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -808,7 +876,9 @@ object GetDLC extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -821,8 +891,8 @@ case class CreateDLCOffer( refundLocktime: UInt32, externalPayoutAddressOpt: Option[BitcoinAddress], externalChangeAddressOpt: Option[BitcoinAddress], - peerAddressOpt: Option[InetSocketAddress]) - extends CliCommand + peerAddressOpt: Option[InetSocketAddress] +) extends CliCommand with AppServerCliCommand object CreateDLCOffer extends ServerJsonModels { @@ -837,7 +907,8 @@ object CreateDLCOffer extends ServerJsonModels { refundLTJs: Value, payoutAddressJs: Value, changeAddressJs: Value, - peerAddressJs: Value) = Try { + peerAddressJs: Value + ) = Try { val contractInfoTLV = jsToContractInfoTLV(contractInfoJs) val collateral = jsToSatoshis(collateralJs) val feeRate = jsToSatoshisPerVirtualByteOpt(feeRateOptJs) @@ -853,57 +924,69 @@ object CreateDLCOffer extends ServerJsonModels { val peerAddressJsOpt = nullToOpt(peerAddressJs) val peerAddressOpt = peerAddressJsOpt.map(js => jsToInetSocketAddress(js)) - CreateDLCOffer(contractInfoTLV, - collateral, - feeRate, - locktimeOpt, - refundLT, - payoutAddressOpt, - changeAddressOpt, - peerAddressOpt) + CreateDLCOffer( + contractInfoTLV, + collateral, + feeRate, + locktimeOpt, + refundLT, + payoutAddressOpt, + changeAddressOpt, + peerAddressOpt + ) } jsArr.arr.toList match { case contractInfoJs :: collateralJs :: feeRateOptJs :: locktimeJs :: refundLTJs :: Nil => - parseParameters(contractInfoJs, - collateralJs, - feeRateOptJs, - locktimeJs, - refundLTJs, - Null, - Null, - Null) + parseParameters( + contractInfoJs, + collateralJs, + feeRateOptJs, + locktimeJs, + refundLTJs, + Null, + Null, + Null + ) case contractInfoJs :: collateralJs :: feeRateOptJs :: locktimeJs :: refundLTJs :: payoutAddressJs :: Nil => - parseParameters(contractInfoJs, - collateralJs, - feeRateOptJs, - locktimeJs, - refundLTJs, - payoutAddressJs, - Null, - Null) + parseParameters( + contractInfoJs, + collateralJs, + feeRateOptJs, + locktimeJs, + refundLTJs, + payoutAddressJs, + Null, + Null + ) case contractInfoJs :: collateralJs :: feeRateOptJs :: locktimeJs :: refundLTJs :: payoutAddressJs :: changeAddressJs :: Nil => - parseParameters(contractInfoJs, - collateralJs, - feeRateOptJs, - locktimeJs, - refundLTJs, - payoutAddressJs, - changeAddressJs, - Null) + parseParameters( + contractInfoJs, + collateralJs, + feeRateOptJs, + locktimeJs, + refundLTJs, + payoutAddressJs, + changeAddressJs, + Null + ) case contractInfoJs :: collateralJs :: feeRateOptJs :: locktimeJs :: refundLTJs :: payoutAddressJs :: changeAddressJs :: peerAddressJs :: Nil => - parseParameters(contractInfoJs, - collateralJs, - feeRateOptJs, - locktimeJs, - refundLTJs, - payoutAddressJs, - changeAddressJs, - peerAddressJs) + parseParameters( + contractInfoJs, + collateralJs, + feeRateOptJs, + locktimeJs, + refundLTJs, + payoutAddressJs, + changeAddressJs, + peerAddressJs + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 6")) + s"Bad number of arguments: ${other.length}. Expected: 6" + ) + ) } } } @@ -927,7 +1010,9 @@ object DecodeContractInfo extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -959,7 +1044,9 @@ object DecodeOffer extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -983,7 +1070,9 @@ object DecodeAnnouncement extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -992,8 +1081,8 @@ case class AcceptDLCOffer( offer: LnMessage[DLCOfferTLV], externalPayoutAddressOpt: Option[BitcoinAddress], externalChangeAddressOpt: Option[BitcoinAddress], - peerAddress: Option[InetSocketAddress]) - extends CliCommand + peerAddress: Option[InetSocketAddress] +) extends CliCommand with AcceptDLCCliCommand object AcceptDLCOffer extends ServerJsonModels { @@ -1003,7 +1092,8 @@ object AcceptDLCOffer extends ServerJsonModels { offerJs: Value, payoutAddressJs: Value, changeAddressJs: Value, - peerAddressJs: Value): Try[AcceptDLCOffer] = Try { + peerAddressJs: Value + ): Try[AcceptDLCOffer] = Try { val offer = LnMessageFactory(DLCOfferTLV) .fromHexT(offerJs.str) .getOrElse(LnMessage(DLCOfferTLV.fromHex(offerJs.str))) @@ -1026,17 +1116,21 @@ object AcceptDLCOffer extends ServerJsonModels { case offerJs :: payoutAddressJs :: changeAddressJs :: Nil => parseParameters(offerJs, payoutAddressJs, changeAddressJs, Null) case offerJs :: payoutAddressJs :: changeAddressJs :: peerAddressJs :: Nil => - parseParameters(offerJs, - payoutAddressJs, - changeAddressJs, - peerAddressJs) + parseParameters( + offerJs, + payoutAddressJs, + changeAddressJs, + peerAddressJs + ) case Nil => Failure(new IllegalArgumentException("Missing offer argument")) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -1045,8 +1139,8 @@ case class AcceptDLC( offer: LnMessage[DLCOfferTLV], peerAddr: InetSocketAddress, externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]) - extends CliCommand + externalChangeAddressOpt: Option[BitcoinAddress] +) extends CliCommand with AcceptDLCCliCommand object AcceptDLC extends ServerJsonModels { @@ -1056,7 +1150,8 @@ object AcceptDLC extends ServerJsonModels { offerJs: Value, addrJs: Value, payoutAddressJs: Value, - changeAddressJs: Value): Try[AcceptDLC] = Try { + changeAddressJs: Value + ): Try[AcceptDLC] = Try { val lnMessageOfferT = LnMessageFactory(DLCOfferTLV) .fromHexT(offerJs.str) val offer: LnMessage[DLCOfferTLV] = lnMessageOfferT match { @@ -1084,12 +1179,15 @@ object AcceptDLC extends ServerJsonModels { parseParameters(offerJs, addrJs, payoutAddressJs, changeAddressJs) case Nil => Failure( - new IllegalArgumentException("Missing offer and peerAddr argument")) + new IllegalArgumentException("Missing offer and peerAddr argument") + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -1118,7 +1216,9 @@ object SignDLC extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -1144,7 +1244,9 @@ object AddDLCSigs extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -1167,7 +1269,9 @@ object GetDLCFundingTx extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -1190,7 +1294,9 @@ object BroadcastDLCFundingTx extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -1198,8 +1304,8 @@ object BroadcastDLCFundingTx extends ServerJsonModels { case class ExecuteDLC( contractId: ByteVector, oracleSigs: Vector[OracleAttestmentTLV], - noBroadcast: Boolean) - extends CliCommand + noBroadcast: Boolean +) extends CliCommand with Broadcastable object ExecuteDLC extends ServerJsonModels { @@ -1217,11 +1323,15 @@ object ExecuteDLC extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing contractId, oracleSigs, and noBroadcast arguments")) + "Missing contractId, oracleSigs, and noBroadcast arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 3")) + s"Bad number of arguments: ${other.length}. Expected: 3" + ) + ) } } } @@ -1246,7 +1356,9 @@ object ExecuteDLCRefund extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -1255,8 +1367,8 @@ case class SendFromOutPoints( outPoints: Vector[TransactionOutPoint], destination: BitcoinAddress, amount: Bitcoins, - feeRateOpt: Option[SatoshisPerVirtualByte]) - extends CliCommand + feeRateOpt: Option[SatoshisPerVirtualByte] +) extends CliCommand with SendCliCommand object SendFromOutPoints extends ServerJsonModels { @@ -1271,28 +1383,34 @@ object SendFromOutPoints extends ServerJsonModels { val satoshisPerVirtualByte = nullToOpt(satsPerVBytesJs).map(satsPerVBytes => SatoshisPerVirtualByte(Satoshis(satsPerVBytes.num.toLong))) - SendFromOutPoints(outPoints, - address, - bitcoins, - satoshisPerVirtualByte) + SendFromOutPoints( + outPoints, + address, + bitcoins, + satoshisPerVirtualByte + ) } case Nil => Failure( new IllegalArgumentException( - "Missing outPoints, address, amount, and fee rate arguments")) + "Missing outPoints, address, amount, and fee rate arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 4")) + s"Bad number of arguments: ${other.length}. Expected: 4" + ) + ) } } } case class SweepWallet( destination: BitcoinAddress, - feeRateOpt: Option[SatoshisPerVirtualByte]) - extends CliCommand + feeRateOpt: Option[SatoshisPerVirtualByte] +) extends CliCommand with SendCliCommand with ServerJsonModels @@ -1315,13 +1433,15 @@ object SweepWallet extends ServerJsonModels { } case Nil => Failure( - new IllegalArgumentException( - "Missing address and fee rate arguments")) + new IllegalArgumentException("Missing address and fee rate arguments") + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -1330,8 +1450,8 @@ case class SendWithAlgo( destination: BitcoinAddress, amount: Bitcoins, feeRateOpt: Option[SatoshisPerVirtualByte], - algo: CoinSelectionAlgo) - extends CliCommand + algo: CoinSelectionAlgo +) extends CliCommand with SendCliCommand with ServerJsonModels @@ -1353,12 +1473,16 @@ object SendWithAlgo extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing address, amount, fee rate, and algo arguments")) + "Missing address, amount, fee rate, and algo arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 4")) + s"Bad number of arguments: ${other.length}. Expected: 4" + ) + ) } } @@ -1372,8 +1496,10 @@ case class SignPSBT(psbt: PSBT) object SignPSBT extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[SignPSBT] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try(SignPSBT(jsToPSBT(jsArr.arr.head))) } @@ -1382,8 +1508,8 @@ object SignPSBT extends ServerJsonModels { case class OpReturnCommit( message: String, hashMessage: Boolean, - feeRateOpt: Option[SatoshisPerVirtualByte]) - extends CliCommand + feeRateOpt: Option[SatoshisPerVirtualByte] +) extends CliCommand with AppServerCliCommand with ServerJsonModels @@ -1403,12 +1529,16 @@ object OpReturnCommit extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing message, hashMessage, and fee rate arguments")) + "Missing message, hashMessage, and fee rate arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 3")) + s"Bad number of arguments: ${other.length}. Expected: 3" + ) + ) } } } @@ -1416,13 +1546,13 @@ case class BumpFee(txId: DoubleSha256DigestBE, feeRate: SatoshisPerVirtualByte) case class BumpFeeCPFP( txId: DoubleSha256DigestBE, - feeRate: SatoshisPerVirtualByte) - extends AppServerCliCommand + feeRate: SatoshisPerVirtualByte +) extends AppServerCliCommand case class BumpFeeRBF( txId: DoubleSha256DigestBE, - feeRate: SatoshisPerVirtualByte) - extends AppServerCliCommand + feeRate: SatoshisPerVirtualByte +) extends AppServerCliCommand object BumpFee extends ServerJsonModels { @@ -1436,12 +1566,15 @@ object BumpFee extends ServerJsonModels { } case Nil => Failure( - new IllegalArgumentException("Missing txId and fee rate arguments")) + new IllegalArgumentException("Missing txId and fee rate arguments") + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -1449,8 +1582,8 @@ object BumpFee extends ServerJsonModels { case class CreateContractInfo( announcementTLV: OracleAnnouncementTLV, totalCollateral: Satoshis, - contractDescriptor: ContractDescriptorTLV) - extends CommandRpc + contractDescriptor: ContractDescriptorTLV +) extends CommandRpc with AppServerCliCommand with ServerJsonModels { @@ -1462,9 +1595,11 @@ case class CreateContractInfo( object CreateContractInfo extends ServerJsonModels { lazy val empty: CreateContractInfo = { - CreateContractInfo(announcementTLV = OracleAnnouncementV0TLV.dummy, - totalCollateral = Satoshis.zero, - contractDescriptor = ContractDescriptorTLV.empty) + CreateContractInfo( + announcementTLV = OracleAnnouncementV0TLV.dummy, + totalCollateral = Satoshis.zero, + contractDescriptor = ContractDescriptorTLV.empty + ) } def fromJsArr(arr: ujson.Arr): Try[CreateContractInfo] = { @@ -1474,17 +1609,20 @@ object CreateContractInfo extends ServerJsonModels { val announcementTLV = OracleAnnouncementTLV.fromHex(announcementVal.str) val totalCollateral = Satoshis(totalCollateralVal.num.toLong) - //validate that these are part of the announcement? + // validate that these are part of the announcement? val contractDescriptor = ContractDescriptorParser.parseCmdLine(payoutsVal, announcementTLV) - CreateContractInfo(announcementTLV, - totalCollateral, - contractDescriptor) + CreateContractInfo( + announcementTLV, + totalCollateral, + contractDescriptor + ) } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to createcontractinfo, got=${other.length} expected=3") + s"Bad number or arguments to createcontractinfo, got=${other.length} expected=3" + ) Failure(exn) } } @@ -1514,7 +1652,8 @@ object ContactAdd { } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to contact-add, got=${other.length} expected=3") + s"Bad number or arguments to contact-add, got=${other.length} expected=3" + ) Failure(exn) } } @@ -1541,7 +1680,8 @@ object ContactRemove { } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to contact-remove, got=${other.length} expected=1") + s"Bad number or arguments to contact-remove, got=${other.length} expected=1" + ) Failure(exn) } } @@ -1555,8 +1695,10 @@ case class DLCContactAdd(dlcId: Sha256Digest, address: InetSocketAddress) object DLCContactAdd { val empty: DLCContactAdd = - DLCContactAdd(Sha256Digest.empty, - InetSocketAddress.createUnresolved("127.0.0.1", 9999)) + DLCContactAdd( + Sha256Digest.empty, + InetSocketAddress.createUnresolved("127.0.0.1", 9999) + ) def fromJsArr(arr: ujson.Arr): Try[DLCContactAdd] = { arr.arr.toList match { @@ -1571,7 +1713,8 @@ object DLCContactAdd { } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to dlc-contact-add, got=${other.length} expected=2") + s"Bad number or arguments to dlc-contact-add, got=${other.length} expected=2" + ) Failure(exn) } } @@ -1592,7 +1735,8 @@ object DLCContactRemove { } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to contact-remove, got=${other.length} expected=1") + s"Bad number or arguments to contact-remove, got=${other.length} expected=1" + ) Failure(exn) } } @@ -1617,7 +1761,8 @@ object DLCCheckConnection { } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to checkconnection, got=${other.length} expected=1") + s"Bad number or arguments to checkconnection, got=${other.length} expected=1" + ) Failure(exn) } } @@ -1626,8 +1771,8 @@ object DLCCheckConnection { case class LoadWallet( walletNameOpt: Option[String], passwordOpt: Option[AesPassword], - bip39PasswordOpt: Option[String]) - extends CommandRpc + bip39PasswordOpt: Option[String] +) extends CommandRpc with AppServerCliCommand object LoadWallet extends ServerJsonModels with BitcoinSLogger { @@ -1637,9 +1782,11 @@ object LoadWallet extends ServerJsonModels with BitcoinSLogger { case _ :: _ :: bip39PasswordJs :: Nil => val (walletNameOpt, passwordOpt) = jsToWalletNameAndPassword(arr.arr.slice(0, 2)) - LoadWallet(walletNameOpt, - passwordOpt, - nullToOpt(bip39PasswordJs).map(_.str)) + LoadWallet( + walletNameOpt, + passwordOpt, + nullToOpt(bip39PasswordJs).map(_.str) + ) case _ :: _ :: Nil => val (walletNameOpt, passwordOpt) = jsToWalletNameAndPassword(arr.arr.slice(0, 2)) @@ -1650,7 +1797,8 @@ object LoadWallet extends ServerJsonModels with BitcoinSLogger { LoadWallet(None, None, None) case other => throw new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 3") + s"Bad number of arguments: ${other.length}. Expected: 3" + ) } } } @@ -1664,7 +1812,8 @@ trait ServerJsonModels { case _: Value => throw Value.InvalidData( js, - "Expected an OracleAnnouncementTLV as a hex string") + "Expected an OracleAnnouncementTLV as a hex string" + ) } def jsToContractInfoTLV(js: Value): ContractInfoV0TLV = @@ -1724,7 +1873,8 @@ trait ServerJsonModels { LockUnspentOutputParameter.fromJson(js) def jsToLockUnspentOutputParameters( - js: Value): Seq[LockUnspentOutputParameter] = { + js: Value + ): Seq[LockUnspentOutputParameter] = { js.arr.foldLeft(Seq.empty[LockUnspentOutputParameter])((seq, outPoint) => seq :+ jsToLockUnspentOutputParameter(outPoint)) } @@ -1750,11 +1900,13 @@ trait ServerJsonModels { case _: Value => throw Value.InvalidData( js, - "Expected a SchnorrDigitalSignature as a hex string") + "Expected a SchnorrDigitalSignature as a hex string" + ) } def jsToSchnorrDigitalSignatureVec( - js: Value): Vector[SchnorrDigitalSignature] = { + js: Value + ): Vector[SchnorrDigitalSignature] = { js.arr.foldLeft(Vector.empty[SchnorrDigitalSignature])((vec, sig) => vec :+ jsToSchnorrDigitalSignature(sig)) } @@ -1766,7 +1918,8 @@ trait ServerJsonModels { case _: Value => throw Value.InvalidData( js, - "Expected a OracleAttestmentTLV as a hex string") + "Expected a OracleAttestmentTLV as a hex string" + ) } def jsToOracleAttestmentTLVVec(js: Value): Vector[OracleAttestmentTLV] = { @@ -1800,17 +1953,20 @@ trait ServerJsonModels { val walletNameOpt = jsToStringOpt(js) if (!walletNameOpt.forall(_.length <= WalletNames.walletNameMaxLen)) { throw new IllegalArgumentException( - s"Invalid wallet name length: ${walletNameOpt.map(_.length).getOrElse(0)}. Max length is ${WalletNames.walletNameMaxLen}.") + s"Invalid wallet name length: ${walletNameOpt.map(_.length).getOrElse(0)}. Max length is ${WalletNames.walletNameMaxLen}." + ) } if (!walletNameOpt.forall(WalletNames.validateWalletName)) { throw new IllegalArgumentException( - s"Invalid wallet name `${walletNameOpt.getOrElse("")}`.") + s"Invalid wallet name `${walletNameOpt.getOrElse("")}`." + ) } walletNameOpt } def jsToWalletNameAndPassword( - js: Value): (Option[String], Option[AesPassword]) = { + js: Value + ): (Option[String], Option[AesPassword]) = { js match { case Arr(arr) => arr.toList match { @@ -1822,7 +1978,8 @@ trait ServerJsonModels { (None, None) case other => throw new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2") + s"Bad number of arguments: ${other.length}. Expected: 2" + ) } case _: Value => throw new IllegalArgumentException(s"Expected json.Arr") @@ -1835,14 +1992,16 @@ trait ServerJsonModels { case Arr(arr) => arr.map(_.str).toVector case Null | False | True | Num(_) | Obj(_) => throw new IllegalArgumentException( - "mnemonic must be a string or array of strings") + "mnemonic must be a string or array of strings" + ) } MnemonicCode.fromWords(mnemonicWords) } def jsToInetSocketAddress( js: Value, - defaultPort: Int = -1): InetSocketAddress = { + defaultPort: Int = -1 + ): InetSocketAddress = { js match { case str: Str => val uri = new URI("tcp://" + str.str) diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonReaders.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonReaders.scala index 1aa72696a5..d0aad8ec42 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonReaders.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonReaders.scala @@ -51,21 +51,21 @@ import scala.util.{Failure, Success, Try} object JsonReaders { - /** Tries to prase the provided JSON into a map with keys of - * type `K` and values of type `V` + /** Tries to prase the provided JSON into a map with keys of type `K` and + * values of type `V` */ - def mapReads[K, V](js: JsValue)(implicit - readsK: Reads[K], - readsV: Reads[V]): JsResult[Map[K, V]] = { + def mapReads[K, V]( + js: JsValue + )(implicit readsK: Reads[K], readsV: Reads[V]): JsResult[Map[K, V]] = { js.validate[JsObject].flatMap { jsObj => val jsResults: scala.collection.Seq[(JsResult[K], JsResult[V])] = jsObj.fields.map { case (key, value) => JsString(key).validate[K] -> value.validate[V] } - val allErrors: scala.collection.Seq[( - JsPath, - scala.collection.Seq[JsonValidationError])] = + val allErrors: scala.collection.Seq[ + (JsPath, scala.collection.Seq[JsonValidationError]) + ] = jsResults.collect { case (JsError(keyErrors), _) => keyErrors case (_, JsError(valueErrors)) => valueErrors @@ -91,16 +91,20 @@ object JsonReaders { override def reads(json: JsValue): JsResult[ZonedDateTime] = SerializerUtil.processJsNumberBigInt[ZonedDateTime](bigInt => - ZonedDateTime.ofInstant(Instant.ofEpochSecond(bigInt.toLong), - ZoneOffset.UTC))(json) + ZonedDateTime.ofInstant( + Instant.ofEpochSecond(bigInt.toLong), + ZoneOffset.UTC + ))(json) } implicit object LocalDateTimeReads extends Reads[LocalDateTime] { override def reads(json: JsValue): JsResult[LocalDateTime] = SerializerUtil.processJsNumberBigInt[LocalDateTime](bigInt => - LocalDateTime.ofInstant(Instant.ofEpochSecond(bigInt.toLong), - ZoneId.systemDefault()))(json) + LocalDateTime.ofInstant( + Instant.ofEpochSecond(bigInt.toLong), + ZoneId.systemDefault() + ))(json) } implicit object BigIntReads extends Reads[BigInt] { @@ -119,21 +123,24 @@ object JsonReaders { override def reads(json: JsValue): JsResult[RipeMd160Digest] = SerializerUtil.processJsString[RipeMd160Digest](RipeMd160Digest.fromHex)( - json) + json + ) } implicit object RipeMd160DigestBEReads extends Reads[RipeMd160DigestBE] { override def reads(json: JsValue): JsResult[RipeMd160DigestBE] = SerializerUtil.processJsString[RipeMd160DigestBE]( - RipeMd160DigestBE.fromHex)(json) + RipeMd160DigestBE.fromHex + )(json) } implicit object DoubleSha256DigestReads extends Reads[DoubleSha256Digest] { override def reads(json: JsValue): JsResult[DoubleSha256Digest] = SerializerUtil.processJsString[DoubleSha256Digest]( - DoubleSha256Digest.fromHex)(json) + DoubleSha256Digest.fromHex + )(json) } implicit object DoubleSha256DigestBEReads @@ -141,7 +148,8 @@ object JsonReaders { override def reads(json: JsValue): JsResult[DoubleSha256DigestBE] = SerializerUtil.processJsString[DoubleSha256DigestBE]( - DoubleSha256DigestBE.fromHex)(json) + DoubleSha256DigestBE.fromHex + )(json) } implicit object BitcoinsReads extends Reads[Bitcoins] { @@ -161,7 +169,8 @@ object JsonReaders { override def reads(json: JsValue): JsResult[Satoshis] = SerializerUtil.processJsNumber[Satoshis](num => Satoshis(num.toBigInt))( - json) + json + ) } implicit object BlockHeaderReads extends Reads[BlockHeader] { @@ -266,8 +275,10 @@ object JsonReaders { case JsNumber(num) if num != 0 => SerializerUtil.buildErrorMsg("Expected witness_version 0", num) case err => - SerializerUtil.buildErrorMsg("Expected numerical witness_version", - err) + SerializerUtil.buildErrorMsg( + "Expected numerical witness_version", + err + ) } } @@ -316,21 +327,24 @@ object JsonReaders { override def reads(json: JsValue): JsResult[ScriptPubKey] = SerializerUtil.processJsString[ScriptPubKey](ScriptPubKey.fromAsmHex)( - json) + json + ) } implicit object ScriptWitnessReads extends Reads[ScriptWitness] { override def reads(json: JsValue): JsResult[ScriptWitness] = SerializerUtil.processJsStringOpt[ScriptWitness]( - ScriptWitness.fromHexOpt)(json) + ScriptWitness.fromHexOpt + )(json) } implicit object DescriptorReads extends Reads[Descriptor] { override def reads(json: JsValue): JsResult[Descriptor] = { SerializerUtil.processJsStringOpt[Descriptor](Descriptor.fromStringOpt)( - json) + json + ) } } @@ -344,7 +358,8 @@ object JsonReaders { override def reads(json: JsValue): JsResult[Sha256Hash160Digest] = SerializerUtil.processJsString[Sha256Hash160Digest]( - Sha256Hash160Digest.fromHex)(json) + Sha256Hash160Digest.fromHex + )(json) } implicit object ECPublicKeyReads extends Reads[ECPublicKey] { @@ -357,14 +372,16 @@ object JsonReaders { override def reads(json: JsValue): JsResult[ECPublicKeyBytes] = SerializerUtil.processJsString[ECPublicKeyBytes]( - ECPublicKeyBytes.fromHex)(json) + ECPublicKeyBytes.fromHex + )(json) } implicit object SchnorrPublicKeyReads extends Reads[SchnorrPublicKey] { override def reads(json: JsValue): JsResult[SchnorrPublicKey] = SerializerUtil.processJsString[SchnorrPublicKey]( - SchnorrPublicKey.fromHex)(json) + SchnorrPublicKey.fromHex + )(json) } implicit object SchnorrNonceReads extends Reads[SchnorrNonce] { @@ -378,7 +395,8 @@ object JsonReaders { override def reads(json: JsValue): JsResult[SchnorrDigitalSignature] = SerializerUtil.processJsString[SchnorrDigitalSignature]( - SchnorrDigitalSignature.fromHex)(json) + SchnorrDigitalSignature.fromHex + )(json) } implicit object FieldElementReads extends Reads[FieldElement] { @@ -423,7 +441,8 @@ object JsonReaders { override def reads(json: JsValue): JsResult[ScriptSignature] = SerializerUtil.processJsString[ScriptSignature]( - ScriptSignature.fromAsmHex)(json) + ScriptSignature.fromAsmHex + )(json) } implicit object TransactionInputReads extends Reads[TransactionInput] { @@ -433,7 +452,8 @@ object JsonReaders { (json \ "coinbase").validate[String] match { case s: JsSuccess[String] => JsSuccess( - CoinbaseInput(ScriptSignature.fromAsmHex(s.value), sequence)) + CoinbaseInput(ScriptSignature.fromAsmHex(s.value), sequence) + ) case _ => (json \ "txid").validate[DoubleSha256DigestBE].flatMap { txid => (json \ "vout").validate[UInt32].flatMap { vout => @@ -441,9 +461,12 @@ object JsonReaders { .validate[ScriptSignature] .flatMap { scriptSig => JsSuccess( - TransactionInput(TransactionOutPoint(txid.flip, vout), - scriptSig, - sequence)) + TransactionInput( + TransactionOutPoint(txid.flip, vout), + scriptSig, + sequence + ) + ) } } } @@ -510,7 +533,8 @@ object JsonReaders { case Some(JsNumber(n)) => JsSuccess(Bitcoins(n)) case Some( err @ (JsNull | _: JsBoolean | _: JsString | _: JsArray | - _: JsObject)) => + _: JsObject) + ) => SerializerUtil.buildJsErrorMsg("jsnumber", err) case None => JsError("error.expected.balance") } @@ -605,9 +629,11 @@ object JsonReaders { pubkey <- (json \ "pubkey").validate[ECPublicKey] masterFingerprint <- (json \ "master_fingerprint").validate[String] path <- (json \ "path").validate[String] - } yield PsbtBIP32Deriv(pubkey = pubkey, - masterFingerprint = masterFingerprint, - path = path) + } yield PsbtBIP32Deriv( + pubkey = pubkey, + masterFingerprint = masterFingerprint, + path = path + ) } implicit object RpcPsbtScriptReads extends Reads[RpcPsbtScript] { @@ -618,19 +644,24 @@ object JsonReaders { hex <- (json \ "hex").validate[ScriptPubKey] scriptType <- (json \ "type").validateOpt[ScriptType] address <- (json \ "address").validateOpt[BitcoinAddress] - } yield RpcPsbtScript(asm = asm, - hex = hex, - scriptType = scriptType, - address = address) + } yield RpcPsbtScript( + asm = asm, + hex = hex, + scriptType = scriptType, + address = address + ) } implicit object MapPubKeySignatureReads extends Reads[Map[ECPublicKey, ECDigitalSignature]] { override def reads( - json: JsValue): JsResult[Map[ECPublicKey, ECDigitalSignature]] = - JsonReaders.mapReads(json)(implicitly[Reads[ECPublicKey]], - implicitly[Reads[ECDigitalSignature]]) + json: JsValue + ): JsResult[Map[ECPublicKey, ECDigitalSignature]] = + JsonReaders.mapReads(json)( + implicitly[Reads[ECPublicKey]], + implicitly[Reads[ECDigitalSignature]] + ) } implicit object RpcPsbtInputV22Reads extends Reads[RpcPsbtInputV22] { @@ -740,7 +771,8 @@ object JsonReaders { case Failure(err) => SerializerUtil.buildJsErrorMsg( s"Unexpected Service Identifier: $err", - json) + json + ) } case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray | _: JsObject) => @@ -759,7 +791,8 @@ object JsonReaders { case Failure(err) => SerializerUtil.buildJsErrorMsg( s"Unexpected Service Identifier: $err", - json) + json + ) } case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray | _: JsObject) => @@ -778,7 +811,8 @@ object JsonReaders { case Failure(err) => SerializerUtil.buildJsErrorMsg( s"Unexpected Service Identifier: $err", - json) + json + ) } case err @ (JsNull | _: JsBoolean | _: JsNumber | _: JsArray | _: JsObject) => @@ -786,10 +820,11 @@ object JsonReaders { } } - implicit val feeProportionalMillionthsReads: Reads[ - FeeProportionalMillionths] = Reads { js => + implicit val feeProportionalMillionthsReads + : Reads[FeeProportionalMillionths] = Reads { js => SerializerUtil.processJsNumberBigInt(FeeProportionalMillionths.fromBigInt)( - js) + js + ) } implicit val channelStateReads: Reads[ChannelState] = { @@ -845,7 +880,8 @@ object JsonReaders { implicit val lnHrpReads: Reads[LnHumanReadablePart] = { Reads { jsValue => SerializerUtil.processJsStringOpt(LnHumanReadablePart.fromStringOpt(_))( - jsValue) + jsValue + ) } } @@ -861,7 +897,8 @@ object JsonReaders { addr.split(":") match { case Array(host, portStr) => val port = Try(portStr.toInt).getOrElse( - throw new RuntimeException(s"Invalid port number `$portStr`")) + throw new RuntimeException(s"Invalid port number `$portStr`") + ) InetSocketAddress.createUnresolved(host, port.toInt) case _ => throw new RuntimeException(s"Invalid inet address `$addr`") } @@ -922,7 +959,8 @@ object JsonReaders { implicit val shortChannelIdReads: Reads[ShortChannelId] = { Reads { jsValue => SerializerUtil.processJsString(ShortChannelId.fromHumanReadableString)( - jsValue) + jsValue + ) } } @@ -943,13 +981,15 @@ object JsonReaders { rgbColor <- (jsValue \ "rgbColor").validate[String] alias <- (jsValue \ "alias").validate[String] addresses <- (jsValue \ "addresses").validate[Vector[InetSocketAddress]] - } yield NodeInfo(signature, - features, - timestamp, - nodeId, - rgbColor, - alias, - addresses) + } yield NodeInfo( + signature, + features, + timestamp, + nodeId, + rgbColor, + alias, + addresses + ) } } @@ -986,13 +1026,15 @@ object JsonReaders { description <- (jsValue \ "description").validate[String] paymentHash <- (jsValue \ "paymentHash").validate[Sha256Digest] expiry <- (jsValue \ "expiry").validate[Long] - } yield InvoiceResult(prefix, - timestamp, - nodeId, - serialized, - description, - paymentHash, - expiry.seconds) + } yield InvoiceResult( + prefix, + timestamp, + nodeId, + serialized, + description, + paymentHash, + expiry.seconds + ) } } @@ -1010,12 +1052,14 @@ object JsonReaders { (jsValue \ "data" \ "commitments" \ "localCommit" \ "spec" \ "toLocal") .validate[MilliSatoshis] - } yield OpenChannelInfo(nodeId = nodeId, - shortChannelId = shortChannelId, - channelId = channelId, - localMsat = localMsat, - remoteMsat = remoteMsat, - state = state) + } yield OpenChannelInfo( + nodeId = nodeId, + shortChannelId = shortChannelId, + channelId = channelId, + localMsat = localMsat, + remoteMsat = remoteMsat, + state = state + ) } implicit val baseChannelInfoReads: Reads[BaseChannelInfo] = Reads { jsValue => @@ -1030,11 +1074,13 @@ object JsonReaders { (jsValue \ "data" \ "commitments" \ "localCommit" \ "spec" \ "toLocal") .validate[MilliSatoshis] - } yield BaseChannelInfo(nodeId = nodeId, - channelId = channelId, - localMsat = localMsat, - remoteMsat = remoteMsat, - state = state) + } yield BaseChannelInfo( + nodeId = nodeId, + channelId = channelId, + localMsat = localMsat, + remoteMsat = remoteMsat, + state = state + ) } implicit val channelInfoReads: Reads[ChannelInfo] = Reads { jsValue => @@ -1078,12 +1124,14 @@ object JsonReaders { val result = Try( UpdateRelayFee.OK( channelId = FundedChannelId.fromHex( - (x._2 \ "channelId").validate[String].get), + (x._2 \ "channelId").validate[String].get + ), feeBaseMsat = (x._2 \ "cmd" \ "feeBase").validate[MilliSatoshis].get, feeProportionalMillionths = (x._2 \ "cmd" \ "feeProportionalMillionths").validate[Long].get - )) match { + ) + ) match { case Success(ok) => ok case Failure(_) => UpdateRelayFee.Error(x._2.toString()) } @@ -1136,13 +1184,13 @@ object JsonReaders { implicit val sendToRouteResultReads: Reads[SendToRouteResult] = Json.reads[SendToRouteResult] - //don't make this implicit so we don't accidentally read the wrong time unit + // don't make this implicit so we don't accidentally read the wrong time unit val finiteDurationReadsMilliseconds: Reads[FiniteDuration] = Reads { js => SerializerUtil.processJsNumberBigInt(_.longValue.millis)(js) } - //don't make this implicit so we don't accidentally read the wrong time unit + // don't make this implicit so we don't accidentally read the wrong time unit val finiteDurationReadsSeconds: Reads[FiniteDuration] = Reads { js => SerializerUtil.processJsNumberBigInt(_.longValue.seconds)(js) } @@ -1182,10 +1230,12 @@ object JsonReaders { route <- (js \ "route").validate[Seq[Hop]] completed <- (js \ "completedAt" \ "unix") .validate[Instant](instantReadsMilliseconds) - } yield OutgoingPaymentStatus.Succeeded(paymentPreimage = preimage, - feesPaid = feesPaid, - route = route, - completedAt = completed) + } yield OutgoingPaymentStatus.Succeeded( + paymentPreimage = preimage, + feesPaid = feesPaid, + route = route, + completedAt = completed + ) } implicit val paymentFailureTypeReads: Reads[PaymentFailure.Type] = Reads { @@ -1247,17 +1297,19 @@ object JsonReaders { amount <- (js \ "amount").validateOpt[MilliSatoshis] minFinalCltvExpiry <- (js \ "minFinalCltvExpiry").validate[Int] features <- (js \ "features").validate[Features] - } yield PaymentRequest(prefix, - timestamp, - nodeId, - serialized, - description, - paymentHash, - paymentMetadata, - expiry, - minFinalCltvExpiry, - amount, - features) + } yield PaymentRequest( + prefix, + timestamp, + nodeId, + serialized, + description, + paymentHash, + paymentMetadata, + expiry, + minFinalCltvExpiry, + amount, + features + ) } implicit val paymentSucceededReads: Reads[OutgoingPayment] = Reads { js => @@ -1274,17 +1326,19 @@ object JsonReaders { .validate[Instant](instantReadsMilliseconds) paymentRequest <- (js \ "paymentRequest").validateOpt[PaymentRequest] status <- (js \ "status").validate[OutgoingPaymentStatus] - } yield OutgoingPayment(id, - parentId, - externalId, - paymentHash, - paymentType, - amount, - recipientAmount, - recipientNodeId, - createdAt, - paymentRequest, - status) + } yield OutgoingPayment( + id, + parentId, + externalId, + paymentHash, + paymentType, + amount, + recipientAmount, + recipientNodeId, + createdAt, + paymentRequest, + status + ) } implicit val receivedPaymentResultReads: Reads[IncomingPayment] = Reads { @@ -1296,11 +1350,13 @@ object JsonReaders { createdAt <- (js \ "createdAt" \ "unix") .validate[Instant](instantReadsMilliseconds) status <- (js \ "status").validate[IncomingPaymentStatus] - } yield IncomingPayment(paymentRequest, - paymentPreimage, - paymentType, - createdAt, - status) + } yield IncomingPayment( + paymentRequest, + paymentPreimage, + paymentType, + createdAt, + status + ) } implicit val channelResultReads: Reads[ChannelResult] = Reads { js => @@ -1314,12 +1370,14 @@ object JsonReaders { (js \ "data" \ "channelUpdate" \ "feeProportionalMillionths") .validateOpt[FeeProportionalMillionths] data <- (js \ "data").validate[JsObject] - } yield ChannelResult(nodeId = nodeId, - state = state, - channelId = channelId, - feeBaseMsat = feeBaseMsat, - feeProportionalMillionths = feeProportional, - data = data) + } yield ChannelResult( + nodeId = nodeId, + state = state, + channelId = channelId, + feeBaseMsat = feeBaseMsat, + feeProportionalMillionths = feeProportional, + data = data + ) } implicit val lnInvoiceReads: Reads[LnInvoice] = @@ -1370,12 +1428,14 @@ object JsonReaders { toChannelId <- (js \ "toChannelId").validate[FundedChannelId] timestamp <- (js \ "timestamp" \ "unix") .validate[Instant](instantReadsMilliseconds) - } yield RelayedPayment(amountIn, - amountOut, - paymentHash, - fromChannelId, - toChannelId, - timestamp) + } yield RelayedPayment( + amountIn, + amountOut, + paymentHash, + fromChannelId, + toChannelId, + timestamp + ) } implicit val auditResultReads: Reads[AuditResult] = Json.reads[AuditResult] @@ -1388,12 +1448,14 @@ object JsonReaders { txType <- (js \ "txType").validate[String] timestamp <- (js \ "timestamp" \ "unix") .validate[Instant](instantReadsMilliseconds) - } yield NetworkFeesResult(remoteNodeId, - channelId, - txId, - fee, - txType, - timestamp) + } yield NetworkFeesResult( + remoteNodeId, + channelId, + txId, + fee, + txType, + timestamp + ) } implicit val channelStatsDirectionReads: Reads[ChannelStats.Direction] = @@ -1417,28 +1479,32 @@ object JsonReaders { toChannelId <- (js \ "toChannelId").validate[FundedChannelId] timestamp <- (js \ "timestamp" \ "unix") .validate[Instant](instantReadsMilliseconds) - } yield WebSocketEvent.PaymentRelayed(amountIn, - amountOut, - paymentHash, - fromChannelId, - toChannelId, - timestamp) + } yield WebSocketEvent.PaymentRelayed( + amountIn, + amountOut, + paymentHash, + fromChannelId, + toChannelId, + timestamp + ) } - implicit val paymentReceivedEventPartReads: Reads[ - WebSocketEvent.PaymentReceived.Part] = Reads { js => + implicit val paymentReceivedEventPartReads + : Reads[WebSocketEvent.PaymentReceived.Part] = Reads { js => for { amount <- (js \ "amount").validate[MilliSatoshis] fromChannelId <- (js \ "fromChannelId").validate[FundedChannelId] timestamp <- (js \ "timestamp" \ "unix") .validate[Instant](instantReadsMilliseconds) - } yield WebSocketEvent.PaymentReceived.Part(amount, - fromChannelId, - timestamp) + } yield WebSocketEvent.PaymentReceived.Part( + amount, + fromChannelId, + timestamp + ) } - implicit val paymentReceivedEventReads: Reads[ - WebSocketEvent.PaymentReceived] = Reads { js => + implicit val paymentReceivedEventReads + : Reads[WebSocketEvent.PaymentReceived] = Reads { js => for { paymentHash <- (js \ "paymentHash").validate[Sha256Digest] parts <- (js \ "parts") @@ -1454,14 +1520,16 @@ object JsonReaders { failures <- (js \ "failures").validate[Vector[JsObject]] timestamp <- (js \ "timestamp" \ "unix") .validate[Instant](instantReadsMilliseconds) - } yield WebSocketEvent.PaymentFailed(id, - paymentHash, - failures.map(_.toString()), - timestamp) + } yield WebSocketEvent.PaymentFailed( + id, + paymentHash, + failures.map(_.toString()), + timestamp + ) } - implicit val paymentSentEventPartReads: Reads[ - WebSocketEvent.PaymentSent.Part] = Reads { js => + implicit val paymentSentEventPartReads + : Reads[WebSocketEvent.PaymentSent.Part] = Reads { js => for { id <- (js \ "id").validate[PaymentId] amount <- (js \ "amount").validate[MilliSatoshis] @@ -1469,11 +1537,13 @@ object JsonReaders { toChannelId <- (js \ "toChannelId").validate[FundedChannelId] timestamp <- (js \ "timestamp" \ "unix") .validate[Instant](instantReadsMilliseconds) - } yield WebSocketEvent.PaymentSent.Part(id, - amount, - feesPaid, - toChannelId, - timestamp) + } yield WebSocketEvent.PaymentSent.Part( + id, + amount, + feesPaid, + toChannelId, + timestamp + ) } implicit val paymentSentEventReads: Reads[WebSocketEvent.PaymentSent] = @@ -1484,22 +1554,26 @@ object JsonReaders { paymentPreimage <- (js \ "paymentPreimage").validate[PaymentPreimage] parts <- (js \ "parts") .validate[Vector[WebSocketEvent.PaymentSent.Part]] - } yield WebSocketEvent.PaymentSent(id, - paymentHash, - paymentPreimage, - parts) + } yield WebSocketEvent.PaymentSent( + id, + paymentHash, + paymentPreimage, + parts + ) } - implicit val paymentSettlingOnchainEventReads: Reads[ - WebSocketEvent.PaymentSettlingOnchain] = Reads { js => + implicit val paymentSettlingOnchainEventReads + : Reads[WebSocketEvent.PaymentSettlingOnchain] = Reads { js => for { amount <- (js \ "amount").validate[MilliSatoshis] paymentHash <- (js \ "paymentHash").validate[Sha256Digest] timestamp <- (js \ "timestamp" \ "unix") .validate[Instant](instantReadsMilliseconds) - } yield WebSocketEvent.PaymentSettlingOnchain(amount, - paymentHash, - timestamp) + } yield WebSocketEvent.PaymentSettlingOnchain( + amount, + paymentHash, + timestamp + ) } implicit val webSocketEventReads: Reads[WebSocketEvent] = @@ -1549,7 +1623,8 @@ object JsonReaders { implicit val connectionDirectionReads: Reads[ConnectionDirection] = { Reads { jsValue => SerializerUtil.processJsStringOpt(ConnectionDirection.fromStringOpt)( - jsValue) + jsValue + ) } } @@ -1568,7 +1643,8 @@ object JsonReaders { implicit val closedChannelTypeReads: Reads[ClosedChannelType] = { Reads { jsValue => SerializerUtil.processJsStringOpt(ClosedChannelType.fromStringOpt)( - jsValue) + jsValue + ) } } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala index 7b75d02478..22230d62b1 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonSerializers.scala @@ -136,8 +136,8 @@ object JsonSerializers { .readNullable[Vector[BitcoinAddress]] and (__ \ "address").readNullable[BitcoinAddress])(RpcScriptPubKeyPostV22) - implicit val rpcTransactionOutputPreV22Reads: Reads[ - RpcTransactionOutputPreV22] = + implicit val rpcTransactionOutputPreV22Reads + : Reads[RpcTransactionOutputPreV22] = Json.reads[RpcTransactionOutputPreV22] implicit val rpcTransactionOutputV22Reads: Reads[RpcTransactionOutputV22] = @@ -154,18 +154,19 @@ object JsonSerializers { implicit val fundRawTransactionResultReads: Reads[FundRawTransactionResult] = Json.reads[FundRawTransactionResult] - implicit val signRawTransactionWithWalletResultReads: Reads[ - SignRawTransactionWithWalletResult] = + implicit val signRawTransactionWithWalletResultReads + : Reads[SignRawTransactionWithWalletResult] = Json.reads[SignRawTransactionWithWalletResult] - implicit val getRawTransactionScriptSigReads: Reads[ - GetRawTransactionScriptSig] = Json.reads[GetRawTransactionScriptSig] + implicit val getRawTransactionScriptSigReads + : Reads[GetRawTransactionScriptSig] = + Json.reads[GetRawTransactionScriptSig] implicit val getRawTransactionVinReads: Reads[GetRawTransactionVin] = Json.reads[GetRawTransactionVin] - implicit val getRawTransactionResultV22Reads: Reads[ - GetRawTransactionResultV22] = + implicit val getRawTransactionResultV22Reads + : Reads[GetRawTransactionResultV22] = Json.reads[GetRawTransactionResultV22] implicit val signRawTransactionErrorReads: Reads[SignRawTransactionError] = @@ -258,8 +259,8 @@ object JsonSerializers { implicit val getBlockResultReads: Reads[GetBlockResult] = Json.reads[GetBlockResult] - implicit val getBlockWithTransactionsResultV22Reads: Reads[ - GetBlockWithTransactionsResultV22] = + implicit val getBlockWithTransactionsResultV22Reads + : Reads[GetBlockWithTransactionsResultV22] = Json.reads[GetBlockWithTransactionsResultV22] implicit val softforkProgressPreV19Reads: Reads[SoftforkProgressPreV19] = @@ -271,8 +272,8 @@ object JsonSerializers { implicit val bip9SoftforkPreV19Reads: Reads[Bip9SoftforkPreV19] = Json.reads[Bip9SoftforkPreV19] - implicit val getBlockChainInfoResultPreV19Reads: Reads[ - GetBlockChainInfoResultPreV19] = + implicit val getBlockChainInfoResultPreV19Reads + : Reads[GetBlockChainInfoResultPreV19] = Json.reads[GetBlockChainInfoResultPreV19] implicit val bip9SoftforkDetailsReads: Reads[Bip9SoftforkDetails] = @@ -286,11 +287,13 @@ object JsonSerializers { } } - implicit val getBlockChainInfoResultPostV19Reads: Reads[ - GetBlockChainInfoResultPostV19] = Json.reads[GetBlockChainInfoResultPostV19] + implicit val getBlockChainInfoResultPostV19Reads + : Reads[GetBlockChainInfoResultPostV19] = + Json.reads[GetBlockChainInfoResultPostV19] - implicit val getBlockChainInfoResultPostV23Reads: Reads[ - GetBlockChainInfoResultPostV23] = Json.reads[GetBlockChainInfoResultPostV23] + implicit val getBlockChainInfoResultPostV23Reads + : Reads[GetBlockChainInfoResultPostV23] = + Json.reads[GetBlockChainInfoResultPostV23] implicit val blockHeaderFormattedReads: Reads[GetBlockHeaderResult] = Json.reads[GetBlockHeaderResult] @@ -311,16 +314,16 @@ object JsonSerializers { implicit val getMemPoolResultPostV23Reads: Reads[GetMemPoolResultPostV23] = Json.reads[GetMemPoolResultPostV23] - implicit val getMemPoolEntryResultPreV19Reads: Reads[ - GetMemPoolEntryResultPreV19] = + implicit val getMemPoolEntryResultPreV19Reads + : Reads[GetMemPoolEntryResultPreV19] = Json.reads[GetMemPoolEntryResultPreV19] - implicit val getMemPoolEntryResultPostV19Reads: Reads[ - GetMemPoolEntryResultPostV19] = + implicit val getMemPoolEntryResultPostV19Reads + : Reads[GetMemPoolEntryResultPostV19] = Json.reads[GetMemPoolEntryResultPostV19] - implicit val getMemPoolEntryResultPostV23Reads: Reads[ - GetMemPoolEntryResultPostV23] = + implicit val getMemPoolEntryResultPostV23Reads + : Reads[GetMemPoolEntryResultPostV23] = Json.reads[GetMemPoolEntryResultPostV23] implicit val getMemPoolInfoResultReads: Reads[GetMemPoolInfoResult] = @@ -332,12 +335,12 @@ object JsonSerializers { implicit val getTxOutSetInfoResultReads: Reads[GetTxOutSetInfoResult] = Json.reads[GetTxOutSetInfoResult] - implicit val GetTxSpendingPrevOutResultReads: Reads[ - GetTxSpendingPrevOutResult] = + implicit val GetTxSpendingPrevOutResultReads + : Reads[GetTxSpendingPrevOutResult] = Json.reads[GetTxSpendingPrevOutResult] - implicit val SimulateRawTransactionResultReads: Reads[ - SimulateRawTransactionResult] = + implicit val SimulateRawTransactionResultReads + : Reads[SimulateRawTransactionResult] = Json.reads[SimulateRawTransactionResult] implicit object Bip32PathFormats extends Format[BIP32Path] { @@ -383,8 +386,8 @@ object JsonSerializers { (__ \ "details").read[Vector[TransactionDetails]] and (__ \ "hex").read[Transaction])(GetTransactionResult) - implicit val getWalletInfoResultReadsPostV22: Reads[ - GetWalletInfoResultPostV22] = + implicit val getWalletInfoResultReadsPostV22 + : Reads[GetWalletInfoResultPostV22] = Json.reads[GetWalletInfoResultPostV22] implicit val importMultiErrorReads: Reads[ImportMultiError] = @@ -530,8 +533,8 @@ object JsonSerializers { implicit val addressInfoResultPreV18Reads: Reads[AddressInfoResultPreV18] = Json.reads[AddressInfoResultPreV18] - implicit val addressInfoResultPostV18Reads: Reads[ - AddressInfoResultPostV18] = { + implicit val addressInfoResultPostV18Reads + : Reads[AddressInfoResultPostV18] = { Reads[AddressInfoResultPostV18] { json => for { isProps <- @@ -539,7 +542,8 @@ object JsonSerializers { infoWithoutProps <- Json .reads[ - AddressInfoResultPostV18.AddressInfoResultPostV18WithoutIsProps] + AddressInfoResultPostV18.AddressInfoResultPostV18WithoutIsProps + ] .reads(json) } yield { AddressInfoResultPostV18(infoWithoutProps, isProps) @@ -547,8 +551,8 @@ object JsonSerializers { } } - implicit val addressInfoResultPostV21Reads: Reads[ - AddressInfoResultPostV21] = { + implicit val addressInfoResultPostV21Reads + : Reads[AddressInfoResultPostV21] = { Reads[AddressInfoResultPostV21] { json => for { isProps <- @@ -556,7 +560,8 @@ object JsonSerializers { infoWithoutProps <- Json .reads[ - AddressInfoResultPostV21.AddressInfoResultPostV21WithoutIsProps] + AddressInfoResultPostV21.AddressInfoResultPostV21WithoutIsProps + ] .reads(json) } yield { AddressInfoResultPostV21(infoWithoutProps, isProps) @@ -591,8 +596,8 @@ object JsonSerializers { implicit val psbtWitnessUtxoInputReads: Reads[PsbtWitnessUtxoInput] = Json.reads[PsbtWitnessUtxoInput] - implicit val mapPubKeySignatureReads: Reads[ - Map[ECPublicKey, ECDigitalSignature]] = MapPubKeySignatureReads + implicit val mapPubKeySignatureReads + : Reads[Map[ECPublicKey, ECDigitalSignature]] = MapPubKeySignatureReads implicit val rpcPsbtInputV22Reads: Reads[RpcPsbtInputV22] = RpcPsbtInputV22Reads @@ -609,8 +614,8 @@ object JsonSerializers { implicit val analyzePsbtResultReads: Reads[AnalyzePsbtResult] = Json.reads[AnalyzePsbtResult] - implicit val getNodeAddressesPostV22Reads: Reads[ - GetNodeAddressesResultPostV22] = + implicit val getNodeAddressesPostV22Reads + : Reads[GetNodeAddressesResultPostV22] = Reads[GetNodeAddressesResultPostV22] { js => for { time <- (js \ "time").validate[Long].map(_.seconds) @@ -618,11 +623,13 @@ object JsonSerializers { address <- (js \ "address").validate[URI] port <- (js \ "port").validate[Int] network <- (js \ "network").validate[String] - } yield GetNodeAddressesResultPostV22(time, - services, - address, - port, - network) + } yield GetNodeAddressesResultPostV22( + time, + services, + address, + port, + network + ) } implicit val rgetpcCommandsReads: Reads[RpcCommands] = Reads[RpcCommands] { @@ -648,8 +655,8 @@ object JsonSerializers { implicit val getDescriptorInfoResultReads: Reads[GetDescriptorInfoResult] = Json.reads[GetDescriptorInfoResult] - implicit val walletCreateFundedPsbtResultReads: Reads[ - WalletCreateFundedPsbtResult] = + implicit val walletCreateFundedPsbtResultReads + : Reads[WalletCreateFundedPsbtResult] = Json.reads[WalletCreateFundedPsbtResult] implicit val scriptTypeReads: Reads[ScriptType] = ScriptTypeReads @@ -659,8 +666,9 @@ object JsonSerializers { implicit val FeeInfoTwoReads: Reads[FeeInfoTwo] = Json.reads[FeeInfoTwo] - implicit val testMempoolAcceptResultReadsPostV22: Reads[ - TestMempoolAcceptResultPostV22] = Json.reads[TestMempoolAcceptResultPostV22] + implicit val testMempoolAcceptResultReadsPostV22 + : Reads[TestMempoolAcceptResultPostV22] = + Json.reads[TestMempoolAcceptResultPostV22] implicit val indexInfoResultReads: Reads[IndexInfoResult] = Json.reads[IndexInfoResult] @@ -719,12 +727,12 @@ object JsonSerializers { implicit val cLightningInvoiceResultReads: Reads[CLightningInvoiceResult] = Json.reads[CLightningInvoiceResult] - implicit val cLightningLookupInvoiceResultReads: Reads[ - CLightningLookupInvoiceResult] = + implicit val cLightningLookupInvoiceResultReads + : Reads[CLightningLookupInvoiceResult] = Json.reads[CLightningLookupInvoiceResult] - implicit val cLightningListInvoicesResultReads: Reads[ - CLightningListInvoicesResult] = + implicit val cLightningListInvoicesResultReads + : Reads[CLightningListInvoicesResult] = Json.reads[CLightningListInvoicesResult] implicit val cLightningPayResultReads: Reads[CLightningPayResult] = @@ -745,23 +753,23 @@ object JsonSerializers { implicit val cLightningWithdrawResultReads: Reads[WithdrawResult] = Json.reads[WithdrawResult] - implicit val cLightningFundChannelStartResultReads: Reads[ - FundChannelStartResult] = + implicit val cLightningFundChannelStartResultReads + : Reads[FundChannelStartResult] = Json.reads[FundChannelStartResult] - implicit val cLightningFundChannelCompleteResultReads: Reads[ - FundChannelCompleteResult] = + implicit val cLightningFundChannelCompleteResultReads + : Reads[FundChannelCompleteResult] = Json.reads[FundChannelCompleteResult] - implicit val cLightningFundChannelCancelResultReads: Reads[ - FundChannelCancelResult] = + implicit val cLightningFundChannelCancelResultReads + : Reads[FundChannelCancelResult] = Json.reads[FundChannelCancelResult] implicit val CLightningTransactionReads: Reads[CLightningTransaction] = Json.reads[CLightningTransaction] - implicit val CLightningListTransactionsResultsReads: Reads[ - ListTransactionsResults] = + implicit val CLightningListTransactionsResultsReads + : Reads[ListTransactionsResults] = Json.reads[ListTransactionsResults] implicit val SendCustomMessageResultReads: Reads[SendCustomMessageResult] = @@ -788,14 +796,17 @@ object JsonSerializers { implicit val int32Writes: Writes[Int32] = Writes[Int32](num => JsNumber(num.toLong)) - implicit val serializedTransactionWitnessWrites: Writes[ - SerializedTransactionWitness] = Json.writes[SerializedTransactionWitness] + implicit val serializedTransactionWitnessWrites + : Writes[SerializedTransactionWitness] = + Json.writes[SerializedTransactionWitness] - implicit val serializedTransactionInputWrites: Writes[ - SerializedTransactionInput] = Json.writes[SerializedTransactionInput] + implicit val serializedTransactionInputWrites + : Writes[SerializedTransactionInput] = + Json.writes[SerializedTransactionInput] - implicit val serializedTransactionOutputWrites: Writes[ - SerializedTransactionOutput] = Json.writes[SerializedTransactionOutput] + implicit val serializedTransactionOutputWrites + : Writes[SerializedTransactionOutput] = + Json.writes[SerializedTransactionOutput] implicit val serializedTransactionWrites: Writes[SerializedTransaction] = Json.writes[SerializedTransaction] @@ -822,46 +833,46 @@ object JsonSerializers { Json.writes[SerializedPSBT] // Map stuff - implicit def mapDoubleSha256DigestReadsPreV19: Reads[ - Map[DoubleSha256Digest, GetMemPoolResultPreV19]] = + implicit def mapDoubleSha256DigestReadsPreV19 + : Reads[Map[DoubleSha256Digest, GetMemPoolResultPreV19]] = Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPreV19](s => JsSuccess(DoubleSha256Digest.fromHex(s))) - implicit def mapDoubleSha256DigestReadsPostV19: Reads[ - Map[DoubleSha256Digest, GetMemPoolResultPostV19]] = + implicit def mapDoubleSha256DigestReadsPostV19 + : Reads[Map[DoubleSha256Digest, GetMemPoolResultPostV19]] = Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPostV19](s => JsSuccess(DoubleSha256Digest.fromHex(s))) - implicit def mapDoubleSha256DigestReadsPostV23: Reads[ - Map[DoubleSha256Digest, GetMemPoolResultPostV23]] = + implicit def mapDoubleSha256DigestReadsPostV23 + : Reads[Map[DoubleSha256Digest, GetMemPoolResultPostV23]] = Reads.mapReads[DoubleSha256Digest, GetMemPoolResultPostV23](s => JsSuccess(DoubleSha256Digest.fromHex(s))) - implicit def mapDoubleSha256DigestBEReadsPreV19: Reads[ - Map[DoubleSha256DigestBE, GetMemPoolResultPreV19]] = + implicit def mapDoubleSha256DigestBEReadsPreV19 + : Reads[Map[DoubleSha256DigestBE, GetMemPoolResultPreV19]] = Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPreV19](s => JsSuccess(DoubleSha256DigestBE.fromHex(s))) - implicit def mapDoubleSha256DigestBEReadsPostV19: Reads[ - Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]] = + implicit def mapDoubleSha256DigestBEReadsPostV19 + : Reads[Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]] = Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPostV19](s => JsSuccess(DoubleSha256DigestBE.fromHex(s))) - implicit def mapDoubleSha256DigestBEReadsPostV23: Reads[ - Map[DoubleSha256DigestBE, GetMemPoolResultPostV23]] = + implicit def mapDoubleSha256DigestBEReadsPostV23 + : Reads[Map[DoubleSha256DigestBE, GetMemPoolResultPostV23]] = Reads.mapReads[DoubleSha256DigestBE, GetMemPoolResultPostV23](s => JsSuccess(DoubleSha256DigestBE.fromHex(s))) - implicit def mapAddressesByLabelReads: Reads[ - Map[BitcoinAddress, LabelResult]] = + implicit def mapAddressesByLabelReads + : Reads[Map[BitcoinAddress, LabelResult]] = Reads.mapReads[BitcoinAddress, LabelResult](s => JsSuccess(BitcoinAddress.fromString(s))) implicit def mapSatsPerKByteByIntReads: Reads[Map[Int, SatoshisPerKiloByte]] = Reads.mapReads[Int, SatoshisPerKiloByte](s => JsSuccess(s.toInt)) - implicit def mapBitcoinerLiveEstimateReads: Reads[ - Map[Int, BitcoinerLiveEstimate]] = + implicit def mapBitcoinerLiveEstimateReads + : Reads[Map[Int, BitcoinerLiveEstimate]] = Reads.mapReads[Int, BitcoinerLiveEstimate](s => JsSuccess(s.toInt)) implicit val outputMapWrites: Writes[Map[BitcoinAddress, Bitcoins]] = diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonWriters.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonWriters.scala index 6f3e2a3f3f..2f62ef37e9 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonWriters.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/JsonWriters.scala @@ -40,7 +40,8 @@ object JsonWriters { case _: SIGHASH_SINGLE_ANYONECANPAY => JsString("SINGLE|ANYONECANPAY") case _: SIGHASH_ANYONECANPAY => throw new IllegalArgumentException( - "SIGHHASH_ANYONECANPAY is not supported by the bitcoind RPC interface") + "SIGHHASH_ANYONECANPAY is not supported by the bitcoind RPC interface" + ) } } @@ -122,17 +123,22 @@ object JsonWriters { override def writes(o: TransactionInput): JsValue = JsObject( - Seq(("txid", JsString(o.previousOutput.txIdBE.hex)), - ("vout", JsNumber(o.previousOutput.vout.toLong)), - ("sequence", JsNumber(o.sequence.toLong)))) + Seq( + ("txid", JsString(o.previousOutput.txIdBE.hex)), + ("vout", JsNumber(o.previousOutput.vout.toLong)), + ("sequence", JsNumber(o.sequence.toLong)) + ) + ) } implicit object TransactionOutPointWrites extends OWrites[TransactionOutPoint] { override def writes(o: TransactionOutPoint): JsObject = { - Json.obj(PicklerKeys.txIdKey -> o.txIdBE.hex, - PicklerKeys.voutKey -> o.vout.toLong) + Json.obj( + PicklerKeys.txIdKey -> o.txIdBE.hex, + PicklerKeys.voutKey -> o.vout.toLong + ) } } @@ -152,8 +158,9 @@ object JsonWriters { override def writes(o: PSBT): JsValue = JsString(o.base64) } - implicit def mapWrites[K, V](keyString: K => String)(implicit - vWrites: Writes[V]): Writes[Map[K, V]] = + implicit def mapWrites[K, V]( + keyString: K => String + )(implicit vWrites: Writes[V]): Writes[Map[K, V]] = new Writes[Map[K, V]] { override def writes(o: Map[K, V]): JsValue = @@ -180,7 +187,8 @@ object JsonWriters { implicit object LnInvoiceWrites extends Writes[LnInvoice] { override def writes(invoice: LnInvoice): JsValue = JsString( - invoice.toString) + invoice.toString + ) } implicit object WalletCreateFundedPsbtOptionsWrites @@ -195,7 +203,8 @@ object JsonWriters { ) def addToMapIfDefined[T](key: String, opt: Option[T])(implicit - writes: Writes[T]): Unit = + writes: Writes[T] + ): Unit = opt.foreach(o => jsOpts += (key -> Json.toJson(o))) addToMapIfDefined("changeAddress", opts.changeAddress) @@ -214,7 +223,8 @@ object JsonWriters { override def writes(o: GlobalPSBTRecord.Unknown): JsValue = JsObject( - Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex)))) + Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex))) + ) } implicit object InputPSBTRecordUnknownWrites @@ -222,7 +232,8 @@ object JsonWriters { override def writes(o: InputPSBTRecord.Unknown): JsValue = JsObject( - Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex)))) + Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex))) + ) } implicit object OutputPSBTRecordUnknownWrites @@ -230,7 +241,8 @@ object JsonWriters { override def writes(o: OutputPSBTRecord.Unknown): JsValue = JsObject( - Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex)))) + Seq(("key", JsString(o.key.toHex)), ("value", JsString(o.value.toHex))) + ) } implicit object PartialSignatureWrites @@ -238,8 +250,11 @@ object JsonWriters { override def writes(o: InputPSBTRecord.PartialSignature): JsValue = JsObject( - Seq(("pubkey", JsString(o.pubKey.hex)), - ("signature", JsString(o.signature.hex)))) + Seq( + ("pubkey", JsString(o.pubKey.hex)), + ("signature", JsString(o.signature.hex)) + ) + ) } implicit object InputBIP32PathWrites @@ -247,9 +262,12 @@ object JsonWriters { override def writes(o: InputPSBTRecord.BIP32DerivationPath): JsValue = JsObject( - Seq(("pubkey", JsString(o.pubKey.hex)), - ("master_fingerprint", JsString(o.masterFingerprint.toHex)), - ("path", JsString(o.path.toString)))) + Seq( + ("pubkey", JsString(o.pubKey.hex)), + ("master_fingerprint", JsString(o.masterFingerprint.toHex)), + ("path", JsString(o.path.toString)) + ) + ) } implicit object OutputBIP32PathWrites @@ -257,8 +275,11 @@ object JsonWriters { override def writes(o: OutputPSBTRecord.BIP32DerivationPath): JsValue = JsObject( - Seq(("pubkey", JsString(o.pubKey.hex)), - ("master_fingerprint", JsString(o.masterFingerprint.toHex)), - ("path", JsString(o.path.toString)))) + Seq( + ("pubkey", JsString(o.pubKey.hex)), + ("master_fingerprint", JsString(o.masterFingerprint.toHex)), + ("path", JsString(o.path.toString)) + ) + ) } } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/Picklers.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/Picklers.scala index a49faf3edb..0db13178f0 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/Picklers.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/Picklers.scala @@ -62,7 +62,8 @@ object Picklers { str => { val uri = new URI("tcp://" + str) InetSocketAddress.createUnresolved(uri.getHost, uri.getPort) - }) + } + ) implicit val byteVectorPickler: ReadWriter[ByteVector] = readwriter[String].bimap(_.toHex, str => ByteVector.fromValidHex(str)) @@ -80,14 +81,16 @@ object Picklers { implicit val schnorrNoncePickler: ReadWriter[SchnorrNonce] = readwriter[String].bimap(_.hex, SchnorrNonce.fromHex) - implicit val enumEventDescriptorPickler: ReadWriter[ - EnumEventDescriptorV0TLV] = + implicit val enumEventDescriptorPickler + : ReadWriter[EnumEventDescriptorV0TLV] = readwriter[String].bimap(_.hex, EnumEventDescriptorV0TLV.fromHex) - implicit val digitDecompEventDescriptorPickler: ReadWriter[ - DigitDecompositionEventDescriptorV0TLV] = - readwriter[String].bimap(_.hex, - DigitDecompositionEventDescriptorV0TLV.fromHex) + implicit val digitDecompEventDescriptorPickler + : ReadWriter[DigitDecompositionEventDescriptorV0TLV] = + readwriter[String].bimap( + _.hex, + DigitDecompositionEventDescriptorV0TLV.fromHex + ) implicit val eventDescriptorPickler: ReadWriter[EventDescriptorTLV] = readwriter[String].bimap(_.hex, EventDescriptorTLV.fromHex) @@ -116,8 +119,8 @@ object Picklers { implicit val uInt32Pickler: ReadWriter[UInt32] = readwriter[Long].bimap(_.toLong, long => UInt32(long)) - implicit val satoshisPerVirtualBytePickler: ReadWriter[ - SatoshisPerVirtualByte] = + implicit val satoshisPerVirtualBytePickler + : ReadWriter[SatoshisPerVirtualByte] = readwriter[Long] .bimap(_.toLong, long => SatoshisPerVirtualByte(Satoshis(long))) @@ -133,8 +136,8 @@ object Picklers { implicit val contractInfoTLVPickler: ReadWriter[ContractInfoV0TLV] = readwriter[String].bimap(_.hex, ContractInfoV0TLV.fromHex) - implicit val schnorrDigitalSignaturePickler: ReadWriter[ - SchnorrDigitalSignature] = + implicit val schnorrDigitalSignaturePickler + : ReadWriter[SchnorrDigitalSignature] = readwriter[String].bimap(_.hex, SchnorrDigitalSignature.fromHex) implicit val partialSignaturePickler: ReadWriter[PartialSignature] = @@ -223,14 +226,16 @@ object Picklers { upickle.default.read[TransactionOutput](obj(PicklerKeys.outputKey)) val hdPath = upickle.default.read[HDPath](obj(PicklerKeys.hdPathKey)) val redeemScript = upickle.default.read[Option[ScriptPubKey]]( - obj(PicklerKeys.redeemScriptKey)) + obj(PicklerKeys.redeemScriptKey) + ) val scriptWitness = upickle.default.read[Option[ScriptWitness]](obj(PicklerKeys.witnessKey)) val state = upickle.default.read[TxoState](obj(PicklerKeys.stateKey)) val txId = upickle.default.read[DoubleSha256DigestBE](obj(PicklerKeys.txIdKey)) val spendingTxId = upickle.default.read[Option[DoubleSha256DigestBE]]( - obj(PicklerKeys.spendingTxIdKey)) + obj(PicklerKeys.spendingTxIdKey) + ) SpendingInfoDb( id = id, outpoint = outpoint, @@ -293,7 +298,8 @@ object Picklers { } private def parseAdaptorSignatures( - arr: ujson.Arr): Vector[ECAdaptorSignature] = { + arr: ujson.Arr + ): Vector[ECAdaptorSignature] = { arr.value.toVector.map { case obj: ujson.Obj => ECAdaptorSignature.fromHex(obj(PicklerKeys.signatureKey).str) @@ -303,19 +309,22 @@ object Picklers { } private def writeAdaptorSignatures( - sigs: Vector[ECAdaptorSignature]): Vector[ujson.Obj] = { + sigs: Vector[ECAdaptorSignature] + ): Vector[ujson.Obj] = { sigs.map { sig => ujson.Obj(PicklerKeys.signatureKey -> Str(sig.hex)) } } private def writeCetAdaptorSigs( - cetSignaturesTLV: CETSignaturesTLV): ujson.Obj = { + cetSignaturesTLV: CETSignaturesTLV + ): ujson.Obj = { cetSignaturesTLV match { case v0: CETSignaturesV0TLV => val sigsVec = writeAdaptorSignatures(v0.sigs) ujson.Obj( - PicklerKeys.ecdsaAdaptorSignaturesKey -> ujson.Arr.from(sigsVec)) + PicklerKeys.ecdsaAdaptorSignaturesKey -> ujson.Arr.from(sigsVec) + ) } } @@ -323,17 +332,20 @@ object Picklers { val tempContractId = Sha256Digest.fromHex(obj(PicklerKeys.tempContractIdKey).str) val acceptCollateral = Satoshis( - obj(PicklerKeys.acceptCollateralKey).num.toLong) + obj(PicklerKeys.acceptCollateralKey).num.toLong + ) val fundingPubKey = ECPublicKey.fromHex(obj(PicklerKeys.fundingPubKeyKey).str) val payoutSpk = ScriptPubKey.fromAsmHex(obj(PicklerKeys.payoutSpkKey).str) val payoutSerialId = parseU64(obj(PicklerKeys.payoutSerialIdKey).str) val fundingInputs = parseFundingInputs( - obj(PicklerKeys.fundingInputsKey).arr) + obj(PicklerKeys.fundingInputsKey).arr + ) val changeSpk = ScriptPubKey.fromAsmHex(obj(PicklerKeys.changeSpkKey).str) val changeSerialId = parseU64(obj(PicklerKeys.changeSerialIdKey).str) val cetAdaptorSigs = parseCetAdaptorSignatures( - obj(PicklerKeys.cetAdaptorSignaturesKey).obj) + obj(PicklerKeys.cetAdaptorSignaturesKey).obj + ) val refundSignature = ECDigitalSignature.fromHex(obj(PicklerKeys.refundSignatureKey).str) val negotiationFields = { @@ -365,17 +377,21 @@ object Picklers { Obj( PicklerKeys.tempContractIdKey -> Str(accept.tempContractId.hex), PicklerKeys.acceptCollateralKey -> Num( - accept.acceptCollateralSatoshis.toLong.toDouble), + accept.acceptCollateralSatoshis.toLong.toDouble + ), PicklerKeys.fundingPubKeyKey -> Str(accept.fundingPubKey.hex), PicklerKeys.payoutSpkKey -> Str(accept.payoutSPK.asmHex), PicklerKeys.payoutSerialIdKey -> Str( - accept.payoutSerialId.toBigInt.toString()), + accept.payoutSerialId.toBigInt.toString() + ), PicklerKeys.fundingInputsKey -> writeJs(accept.fundingInputs), PicklerKeys.changeSpkKey -> Str(accept.changeSPK.asmHex), PicklerKeys.changeSerialIdKey -> Str( - accept.changeSerialId.toBigInt.toString()), + accept.changeSerialId.toBigInt.toString() + ), PicklerKeys.cetAdaptorSignaturesKey -> writeCetAdaptorSigs( - accept.cetSignatures), + accept.cetSignatures + ), PicklerKeys.refundSignatureKey -> Str(accept.refundSignature.hex), PicklerKeys.negotiationFieldsKey -> ujson.Null ) @@ -383,13 +399,15 @@ object Picklers { private def parseFundingSignatures(obj: ujson.Obj): FundingSignaturesTLV = { val fundingSignatures: Vector[ujson.Value] = obj( - PicklerKeys.fundingSignaturesKey).arr.toVector + PicklerKeys.fundingSignaturesKey + ).arr.toVector val witV0 = paresFundingSignaturesArr(fundingSignatures) FundingSignaturesV0TLV(witV0) } private def paresFundingSignaturesArr( - arr: Vector[ujson.Value]): Vector[ScriptWitnessV0] = { + arr: Vector[ujson.Value] + ): Vector[ScriptWitnessV0] = { arr.map { case obj: ujson.Obj => val witnessElementsArr = obj(PicklerKeys.witnessElementsKey).arr @@ -405,7 +423,8 @@ object Picklers { } private def writeFundingSignatures( - fundingSigs: FundingSignaturesTLV): ujson.Obj = { + fundingSigs: FundingSignaturesTLV + ): ujson.Obj = { val sigs: Vector[ujson.Obj] = fundingSigs match { case v0: FundingSignaturesV0TLV => val witnessJson: Vector[Obj] = { @@ -424,11 +443,13 @@ object Picklers { private def readSignTLV(obj: ujson.Obj): DLCSignTLV = { val contractId = ByteVector.fromValidHex(obj(PicklerKeys.contractIdKey).str) val adaptorSigs = parseCetAdaptorSignatures( - obj(PicklerKeys.cetAdaptorSignaturesKey).obj) + obj(PicklerKeys.cetAdaptorSignaturesKey).obj + ) val refundSignature = ECDigitalSignature.fromHex(obj(PicklerKeys.refundSignatureKey).str) val fundingSignatures = parseFundingSignatures( - obj(PicklerKeys.fundingSignaturesKey).obj) + obj(PicklerKeys.fundingSignaturesKey).obj + ) val signTLV = DLCSignTLV(contractId, adaptorSigs, refundSignature, fundingSignatures) @@ -441,7 +462,8 @@ object Picklers { ujson.Obj( PicklerKeys.contractIdKey -> sign.contractId.toHex, PicklerKeys.cetAdaptorSignaturesKey -> writeCetAdaptorSigs( - sign.cetSignatures), + sign.cetSignatures + ), PicklerKeys.refundSignatureKey -> ujson.Str(sign.refundSignature.hex), PicklerKeys.fundingSignaturesKey -> writeFundingSignatures(sign.fundingSignatures) @@ -456,8 +478,8 @@ object Picklers { readwriter[ujson.Obj].bimap(writeSignTLV, readSignTLV) } - implicit val lnMessageDLCAcceptTLVPickler: ReadWriter[ - LnMessage[DLCAcceptTLV]] = + implicit val lnMessageDLCAcceptTLVPickler + : ReadWriter[LnMessage[DLCAcceptTLV]] = readwriter[String].bimap(_.hex, LnMessageFactory(DLCAcceptTLV).fromHex) implicit val lnMessageDLCSignTLVPickler: ReadWriter[LnMessage[DLCSignTLV]] = @@ -488,8 +510,8 @@ object Picklers { implicit val addressLabelTagPickler: ReadWriter[AddressLabelTag] = readwriter[String].bimap(_.name, AddressLabelTag) - implicit val lockUnspentOutputParameterPickler: ReadWriter[ - LockUnspentOutputParameter] = + implicit val lockUnspentOutputParameterPickler + : ReadWriter[LockUnspentOutputParameter] = readwriter[Value].bimap(_.toJson, LockUnspentOutputParameter.fromJson) // can't make implicit because it will overlap with ones needed for cli @@ -501,8 +523,10 @@ object Picklers { val descriptorJson = announcement.eventTLV.eventDescriptor match { case EnumEventDescriptorV0TLV(outcomes) => - Obj("outcomes" -> outcomes.map(Str(_)), - "hex" -> announcement.eventTLV.eventDescriptor.hex) + Obj( + "outcomes" -> outcomes.map(Str(_)), + "hex" -> announcement.eventTLV.eventDescriptor.hex + ) case numeric: NumericEventDescriptorTLV => Obj( "base" -> Num(numeric.base.toLong.toDouble), @@ -516,10 +540,12 @@ object Picklers { val maturityStr = TimeUtil.iso8601ToString(Date.from(announcement.eventTLV.maturation)) - val eventJson = Obj("nonces" -> noncesJson, - "maturity" -> Str(maturityStr), - "descriptor" -> descriptorJson, - "eventId" -> Str(announcement.eventTLV.eventId)) + val eventJson = Obj( + "nonces" -> noncesJson, + "maturity" -> Str(maturityStr), + "descriptor" -> descriptorJson, + "eventId" -> Str(announcement.eventTLV.eventId) + ) Obj( "announcementSignature" -> Str(announcement.announcementSignature.hex), @@ -541,10 +567,12 @@ object Picklers { val sigsJson = attestments.sigs.map(sig => Str(sig.hex)) val valuesJson = attestments.outcomes.map(Str(_)) - Obj("eventId" -> Str(attestments.eventId), - "signatures" -> sigsJson, - "values" -> valuesJson, - "hex" -> attestments.hex) + Obj( + "eventId" -> Str(attestments.eventId), + "signatures" -> sigsJson, + "values" -> valuesJson, + "hex" -> attestments.hex + ) } implicit val fundingInputV0Writer: Writer[FundingInputTLV] = @@ -591,15 +619,17 @@ object Picklers { } } - implicit val hyperbolaPayoutCurvePieceTLVWriter: Writer[ - HyperbolaPayoutCurvePieceTLV] = { + implicit val hyperbolaPayoutCurvePieceTLVWriter + : Writer[HyperbolaPayoutCurvePieceTLV] = { writer[Obj].comap { piece => Obj( PicklerKeys.usePositivePiece -> Bool(piece.usePositivePiece), PicklerKeys.translateOutcome -> Num( - piece.translateOutcome.toBigDecimal.toDouble), + piece.translateOutcome.toBigDecimal.toDouble + ), PicklerKeys.translatePayout -> Num( - piece.translatePayout.toBigDecimal.toDouble), + piece.translatePayout.toBigDecimal.toDouble + ), PicklerKeys.a -> Num(piece.a.toBigDecimal.toDouble), PicklerKeys.b -> Num(piece.b.toBigDecimal.toDouble), PicklerKeys.c -> Num(piece.c.toBigDecimal.toDouble), @@ -612,7 +642,7 @@ object Picklers { implicit val payoutFunctionV0TLVWriter: Writer[PayoutFunctionV0TLV] = { def endpoint(json: Value, isEndpoint: Boolean): Value = json match { case obj: Obj => - //drop old value on the floor if there is one + // drop old value on the floor if there is one obj.value.put(PicklerKeys.isEndpointKey, Bool(isEndpoint)) Obj(obj.value) case v: Value => v @@ -644,7 +674,8 @@ object Picklers { val points: Vector[TLVPoint] = pointsArr.map { case x @ (_: Arr | _: Num | Null | _: Bool | _: Str) => sys.error( - s"Cannot have $x when parsing payout curve points, expected json object") + s"Cannot have $x when parsing payout curve points, expected json object" + ) case obj: Obj => upickle.default.read[TLVPoint](obj) }.toVector @@ -660,8 +691,10 @@ object Picklers { import roundingIntervals._ val intervalsJs = intervalStarts.map { i => - Obj("beginInterval" -> Num(i._1.toDouble), - "roundingMod" -> Num(i._2.toLong.toDouble)) + Obj( + "beginInterval" -> Num(i._1.toDouble), + "roundingMod" -> Num(i._2.toLong.toDouble) + ) } Obj("intervals" -> intervalsJs) @@ -686,10 +719,12 @@ object Picklers { writer[Obj].comap { v1 => import v1._ - Obj("numDigits" -> Num(numDigits.toDouble), - "payoutFunction" -> writeJs(payoutFunction), - "roundingIntervals" -> writeJs(roundingIntervals), - "hex" -> v1.hex) + Obj( + "numDigits" -> Num(numDigits.toDouble), + "payoutFunction" -> writeJs(payoutFunction), + "roundingIntervals" -> writeJs(roundingIntervals), + "hex" -> v1.hex + ) } implicit val contractDescriptorWriter: Writer[ContractDescriptorTLV] = @@ -704,23 +739,29 @@ object Picklers { writer[Obj].comap { oracleInfo => Obj( "announcement" -> writeJs(oracleInfo.announcement)( - oracleAnnouncementTLVJsonWriter)) + oracleAnnouncementTLVJsonWriter + ) + ) } implicit val oracleInfoV1TLVWriter: Writer[OracleInfoV1TLV] = writer[Obj].comap { oracleInfo => import oracleInfo._ - Obj("threshold" -> Num(threshold.toDouble), - "announcements" -> oracles.map(o => - writeJs(o)(oracleAnnouncementTLVJsonWriter))) + Obj( + "threshold" -> Num(threshold.toDouble), + "announcements" -> oracles.map(o => + writeJs(o)(oracleAnnouncementTLVJsonWriter)) + ) } implicit val oracleParamsV0TLVWriter: Writer[OracleParamsV0TLV] = writer[Obj].comap { params => import params._ - Obj("maxErrorExp" -> Num(maxErrorExp.toDouble), - "minFailExp" -> Num(minFailExp.toDouble), - "maximizeCoverage" -> Bool(maximizeCoverage)) + Obj( + "maxErrorExp" -> Num(maxErrorExp.toDouble), + "minFailExp" -> Num(minFailExp.toDouble), + "maximizeCoverage" -> Bool(maximizeCoverage) + ) } implicit val oracleParamsTLVWriter: Writer[OracleParamsTLV] = @@ -731,10 +772,12 @@ object Picklers { implicit val oracleInfoV2TLVWriter: Writer[OracleInfoV2TLV] = writer[Obj].comap { oracleInfo => import oracleInfo._ - Obj("threshold" -> Num(threshold.toDouble), - "announcements" -> oracles.map(o => - writeJs(o)(oracleAnnouncementTLVJsonWriter)), - "params" -> writeJs(params)) + Obj( + "threshold" -> Num(threshold.toDouble), + "announcements" -> oracles.map(o => + writeJs(o)(oracleAnnouncementTLVJsonWriter)), + "params" -> writeJs(params) + ) } implicit val oracleInfoTLVWriter: Writer[OracleInfoTLV] = @@ -762,15 +805,18 @@ object Picklers { case (c, o) => val contractDescriptorJson = writeJs(c) val oracleInfoJson = writeJs(o) - ujson.Obj(PicklerKeys.contractDescriptorKey -> contractDescriptorJson, - PicklerKeys.oracleInfoKey -> oracleInfoJson) + ujson.Obj( + PicklerKeys.contractDescriptorKey -> contractDescriptorJson, + PicklerKeys.oracleInfoKey -> oracleInfoJson + ) } val arrayJson = ujson.Arr.from(arrayVec) Obj( PicklerKeys.totalCollateralKey -> Num( - contractInfo.totalCollateral.toLong.toDouble), + contractInfo.totalCollateral.toLong.toDouble + ), PicklerKeys.pairsKey -> arrayJson ) } @@ -840,9 +886,11 @@ object Picklers { PicklerKeys.tempContractIdKey -> Str(tempContractId.hex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -852,8 +900,8 @@ object Picklers { ) } - implicit val acceptedComputingAdaptorSigsW: Writer[ - AcceptedComputingAdaptorSigs] = writer[Obj].comap { accepted => + implicit val acceptedComputingAdaptorSigsW + : Writer[AcceptedComputingAdaptorSigs] = writer[Obj].comap { accepted => import accepted._ Obj( "state" -> Str(statusString), @@ -864,9 +912,11 @@ object Picklers { "contractId" -> Str(contractId.toHex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -887,9 +937,11 @@ object Picklers { "contractId" -> Str(contractId.toHex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -911,9 +963,11 @@ object Picklers { "contractId" -> Str(contractId.toHex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -935,9 +989,11 @@ object Picklers { "contractId" -> Str(contractId.toHex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -960,9 +1016,11 @@ object Picklers { "contractId" -> Str(contractId.toHex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -985,9 +1043,11 @@ object Picklers { "contractId" -> Str(contractId.toHex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -1004,11 +1064,15 @@ object Picklers { import claimed._ val (oraclesJs, outcomesJs) = oracleOutcome match { case EnumOracleOutcome(oracles, outcome) => - (Arr.from(oracles.map(o => Str(o.announcement.hex))), - Str(outcome.outcome)) + ( + Arr.from(oracles.map(o => Str(o.announcement.hex))), + Str(outcome.outcome) + ) case numeric: NumericOracleOutcome => - (Arr.from(numeric.oracles.map(_.announcement.hex)), - Arr.from(numeric.outcomes.map(o => Arr.from(o.digits)))) + ( + Arr.from(numeric.oracles.map(_.announcement.hex)), + Arr.from(numeric.outcomes.map(o => Arr.from(o.digits))) + ) } Obj( @@ -1020,9 +1084,11 @@ object Picklers { "contractId" -> Str(contractId.toHex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -1034,7 +1100,8 @@ object Picklers { "oracles" -> oraclesJs, PicklerKeys.myPayout -> Num(claimed.myPayout.satoshis.toLong.toDouble), counterPartyPayoutKey -> Num( - claimed.counterPartyPayout.satoshis.toLong.toDouble), + claimed.counterPartyPayout.satoshis.toLong.toDouble + ), PicklerKeys.pnl -> Num(claimed.pnl.satoshis.toLong.toDouble), PicklerKeys.rateOfReturn -> Num(claimed.rateOfReturn.toDouble), "payoutAddress" -> writeJs(payoutAddress), @@ -1047,11 +1114,15 @@ object Picklers { import remoteClaimed._ val (oraclesJs, outcomesJs) = oracleOutcome match { case EnumOracleOutcome(oracles, outcome) => - (Arr.from(oracles.map(o => Str(o.announcement.hex))), - Str(outcome.outcome)) + ( + Arr.from(oracles.map(o => Str(o.announcement.hex))), + Str(outcome.outcome) + ) case numeric: NumericOracleOutcome => - (Arr.from(numeric.oracles.map(_.announcement.hex)), - Arr.from(numeric.outcomes.map(o => Arr.from(o.digits)))) + ( + Arr.from(numeric.oracles.map(_.announcement.hex)), + Arr.from(numeric.outcomes.map(o => Arr.from(o.digits))) + ) } Obj( @@ -1063,9 +1134,11 @@ object Picklers { "contractId" -> Str(contractId.toHex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -1076,9 +1149,11 @@ object Picklers { "outcomes" -> outcomesJs, "oracles" -> oraclesJs, PicklerKeys.myPayout -> Num( - remoteClaimed.myPayout.satoshis.toLong.toDouble), + remoteClaimed.myPayout.satoshis.toLong.toDouble + ), counterPartyPayoutKey -> Num( - remoteClaimed.counterPartyPayout.satoshis.toLong.toDouble), + remoteClaimed.counterPartyPayout.satoshis.toLong.toDouble + ), PicklerKeys.pnl -> Num(remoteClaimed.pnl.satoshis.toLong.toDouble), PicklerKeys.rateOfReturn -> Num(remoteClaimed.rateOfReturn.toDouble), "payoutAddress" -> writeJs(payoutAddress), @@ -1097,9 +1172,11 @@ object Picklers { "contractId" -> Str(contractId.toHex), "contractInfo" -> Str(contractInfo.hex), "contractMaturity" -> Num( - timeouts.contractMaturity.toUInt32.toLong.toDouble), + timeouts.contractMaturity.toUInt32.toLong.toDouble + ), "contractTimeout" -> Num( - timeouts.contractTimeout.toUInt32.toLong.toDouble), + timeouts.contractTimeout.toUInt32.toLong.toDouble + ), "feeRate" -> Num(feeRate.toLong.toDouble), "totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble), "localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble), @@ -1108,7 +1185,8 @@ object Picklers { "closingTxId" -> Str(closingTxId.hex), PicklerKeys.myPayout -> Num(refunded.myPayout.satoshis.toLong.toDouble), counterPartyPayoutKey -> Num( - refunded.counterPartyPayout.satoshis.toLong.toDouble), + refunded.counterPartyPayout.satoshis.toLong.toDouble + ), PicklerKeys.pnl -> Num(refunded.pnl.satoshis.toLong.toDouble), PicklerKeys.rateOfReturn -> Num(refunded.rateOfReturn.toDouble), "payoutAddress" -> writeJs(payoutAddress), @@ -1161,11 +1239,13 @@ object Picklers { val message = Try(obj("message").str).toOption val receivedAt = Instant.ofEpochSecond(obj("receivedAt").num.toLong) val offerTLV = DLCOfferTLV.fromHex(obj("offerTLV").str) - IncomingDLCOfferDb(hash = hash, - peer = peer, - message = message, - receivedAt = receivedAt, - offerTLV = offerTLV) + IncomingDLCOfferDb( + hash = hash, + peer = peer, + message = message, + receivedAt = receivedAt, + offerTLV = offerTLV + ) } implicit val dlcOfferRemoveR: Reader[Sha256Digest] = @@ -1202,8 +1282,10 @@ object Picklers { lazy val payoutAddress: Option[PayoutAddress] = payoutAddressJs match { case json: Obj => json("address").strOpt.map(a => - PayoutAddress(BitcoinAddress.fromString(a), - json("isExternal").boolOpt.getOrElse(false))) + PayoutAddress( + BitcoinAddress.fromString(a), + json("isExternal").boolOpt.getOrElse(false) + )) case Null => None case v: Value => throw new IllegalArgumentException(s"Unexpected payout address $v") @@ -1228,8 +1310,10 @@ object Picklers { lazy val oracleOutcome = outcomes.head match { case outcome: EnumOutcome => - EnumOracleOutcome(oracles.asInstanceOf[Vector[EnumSingleOracleInfo]], - outcome) + EnumOracleOutcome( + oracles.asInstanceOf[Vector[EnumSingleOracleInfo]], + outcome + ) case UnsignedNumericOutcome(_) => val numericOutcomes = outcomes.map(_.asInstanceOf[UnsignedNumericOutcome]) @@ -1377,8 +1461,10 @@ object Picklers { peerOpt ) case DLCState.RemoteClaimed => - require(oracleSigs.size == 1, - "Remote claimed should only have one oracle sig") + require( + oracleSigs.size == 1, + "Remote claimed should only have one oracle sig" + ) RemoteClaimed( dlcId, isInitiator, @@ -1425,13 +1511,17 @@ object Picklers { writer[Obj].comap { walletAccounting: DLCWalletAccounting => Obj( PicklerKeys.myCollateral -> Num( - walletAccounting.myCollateral.satoshis.toLong.toDouble), + walletAccounting.myCollateral.satoshis.toLong.toDouble + ), PicklerKeys.theirCollateral -> Num( - walletAccounting.theirCollateral.satoshis.toLong.toDouble), + walletAccounting.theirCollateral.satoshis.toLong.toDouble + ), PicklerKeys.myPayout -> Num( - walletAccounting.myPayout.satoshis.toLong.toDouble), + walletAccounting.myPayout.satoshis.toLong.toDouble + ), PicklerKeys.theirPayout -> Num( - walletAccounting.theirPayout.satoshis.toLong.toDouble), + walletAccounting.theirPayout.satoshis.toLong.toDouble + ), PicklerKeys.pnl -> Num(walletAccounting.pnl.satoshis.toLong.toDouble), PicklerKeys.rateOfReturn -> Num(walletAccounting.rateOfReturn.toDouble) ) @@ -1441,7 +1531,8 @@ object Picklers { implicit val mnemonicCodePickler: ReadWriter[MnemonicCode] = readwriter[String].bimap( _.words.mkString(" "), - str => MnemonicCode.fromWords(str.split(' ').toVector)) + str => MnemonicCode.fromWords(str.split(' ').toVector) + ) implicit val extPrivateKeyPickler: ReadWriter[ExtPrivateKey] = readwriter[String].bimap(ExtKey.toString, ExtPrivateKey.fromString) @@ -1559,13 +1650,16 @@ object Picklers { } private def writeCompactFilterDb( - compactFilterDb: CompactFilterDb): ujson.Obj = { + compactFilterDb: CompactFilterDb + ): ujson.Obj = { ujson.Obj( PicklerKeys.hashKey -> ujson.Str(compactFilterDb.hashBE.hex), PicklerKeys.filterTypeKey -> ujson.Str( - compactFilterDb.filterType.toString), + compactFilterDb.filterType.toString + ), PicklerKeys.compactFilterBytesKey -> ujson.Str( - compactFilterDb.bytes.toHex), + compactFilterDb.bytes.toHex + ), PicklerKeys.heightKey -> ujson.Num(compactFilterDb.height), PicklerKeys.blockHashKey -> ujson.Str(compactFilterDb.blockHashBE.hex) ) @@ -1590,7 +1684,8 @@ object Picklers { } private def writeCompactFilterHeaderDb( - filterHeaderDb: CompactFilterHeaderDb): ujson.Obj = { + filterHeaderDb: CompactFilterHeaderDb + ): ujson.Obj = { ujson.Obj( PicklerKeys.hashKey -> ujson.Str(filterHeaderDb.hashBE.hex), PicklerKeys.filterHashKey -> ujson.Str(filterHeaderDb.filterHashBE.hex), @@ -1602,7 +1697,8 @@ object Picklers { } private def readCompactFilterHeaderDb( - obj: ujson.Obj): CompactFilterHeaderDb = { + obj: ujson.Obj + ): CompactFilterHeaderDb = { val hash = DoubleSha256DigestBE.fromHex(obj(PicklerKeys.hashKey).str) val filterHash = DoubleSha256DigestBE.fromHex(obj(PicklerKeys.filterHashKey).str) @@ -1611,11 +1707,13 @@ object Picklers { val blockHash = DoubleSha256DigestBE.fromHex(obj(PicklerKeys.blockHashKey).str) val height = obj(PicklerKeys.heightKey).num - CompactFilterHeaderDb(hashBE = hash, - filterHashBE = filterHash, - previousFilterHeaderBE = previousFilterHeader, - blockHashBE = blockHash, - height = height.toInt) + CompactFilterHeaderDb( + hashBE = hash, + filterHashBE = filterHash, + previousFilterHeaderBE = previousFilterHeader, + blockHashBE = blockHash, + height = height.toInt + ) } private def writeContactDb(contact: DLCContactDb): ujson.Obj = { diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/SerializerUtil.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/SerializerUtil.scala index 3cc26d3d93..0184b40a90 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/SerializerUtil.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/SerializerUtil.scala @@ -4,8 +4,9 @@ import play.api.libs.json._ sealed abstract class SerializerUtil { - def processJsNumberBigInt[T](numFunc: BigInt => T)( - json: JsValue): JsResult[T] = + def processJsNumberBigInt[T]( + numFunc: BigInt => T + )(json: JsValue): JsResult[T] = json match { case JsNumber(nDecimal) => val nOpt = nDecimal.toBigIntExact @@ -54,14 +55,15 @@ sealed abstract class SerializerUtil { SerializerUtil.buildJsErrorMsg("jsstring", err) } - def processJsStringOpt[T](f: String => Option[T])( - jsValue: JsValue): JsResult[T] = { + def processJsStringOpt[T]( + f: String => Option[T] + )(jsValue: JsValue): JsResult[T] = { jsValue match { case JsString(key) => val tOpt = f(key) tOpt match { case Some(t) => JsSuccess(t) - case None => SerializerUtil.buildErrorMsg("invalid jsstring", jsValue) + case None => SerializerUtil.buildErrorMsg("invalid jsstring", jsValue) } case err @ (_: JsNumber | _: JsObject | _: JsArray | JsNull | _: JsBoolean) => diff --git a/app-commons/src/main/scala/org/bitcoins/commons/serializers/WsPicklers.scala b/app-commons/src/main/scala/org/bitcoins/commons/serializers/WsPicklers.scala index 768b79a7d3..30cb50f876 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/serializers/WsPicklers.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/serializers/WsPicklers.scala @@ -69,13 +69,15 @@ object WsPicklers { } private def writeChainNotification( - notification: ChainNotification[_]): ujson.Obj = { + notification: ChainNotification[_] + ): ujson.Obj = { val payloadJson: ujson.Value = notification match { case BlockProcessedNotification(block) => upickle.default.writeJs(block)(Picklers.getBlockHeaderResultPickler) case CompactFilterHeaderProcessedNotification(filterHeader) => upickle.default.writeJs(filterHeader)( - Picklers.compactFilterHeaderPickler) + Picklers.compactFilterHeaderPickler + ) case CompactFilterProcessedNotification(filter) => upickle.default.writeJs(filter)(Picklers.compactFilterDbPickler) case SyncFlagChangedNotification(syncing) => @@ -115,7 +117,8 @@ object WsPicklers { } private def writeWalletNotification( - notification: WalletNotification[_]): ujson.Obj = { + notification: WalletNotification[_] + ): ujson.Obj = { val payloadJson: ujson.Value = notification match { case TxBroadcastNotification(tx) => upickle.default.writeJs(tx)(Picklers.transactionPickler) @@ -184,7 +187,8 @@ object WsPicklers { } private def writeTorNotification( - notification: TorNotification[_]): ujson.Obj = { + notification: TorNotification[_] + ): ujson.Obj = { val payloadJson = notification.`type` match { case TorWsType.TorStarted => ujson.Null @@ -206,12 +210,15 @@ object WsPicklers { } private def writeDLCNodeNotification( - notification: DLCNodeNotification[_]): ujson.Obj = { + notification: DLCNodeNotification[_] + ): ujson.Obj = { def addr2str(address: InetSocketAddress) = address.getHostName + ":" + address.getPort def failure2obj(payload: (Sha256Digest, String)): ujson.Obj = { - ujson.Obj(PicklerKeys.idKey -> writeJs(payload._1.hex), - PicklerKeys.errorKey -> writeJs(payload._2)) + ujson.Obj( + PicklerKeys.idKey -> writeJs(payload._1.hex), + PicklerKeys.errorKey -> writeJs(payload._2) + ) } val payloadJson: ujson.Value = notification match { case DLCNodeConnectionInitiated(address) => @@ -238,13 +245,16 @@ object WsPicklers { } private def readDLCNodeNotification( - obj: ujson.Obj): DLCNodeNotification[_] = { + obj: ujson.Obj + ): DLCNodeNotification[_] = { val typeObj = read[DLCNodeWsType](obj(PicklerKeys.typeKey)) val payloadObj = obj(PicklerKeys.payloadKey) def obj2failure(payload: ujson.Value): (Sha256Digest, String) = { - (Sha256Digest.fromHex(payload.obj(PicklerKeys.idKey).str), - payload.obj(PicklerKeys.errorKey).str) + ( + Sha256Digest.fromHex(payload.obj(PicklerKeys.idKey).str), + payload.obj(PicklerKeys.errorKey).str + ) } typeObj match { @@ -278,25 +288,29 @@ object WsPicklers { implicit val newAddressPickler: ReadWriter[NewAddressNotification] = { readwriter[ujson.Obj].bimap( writeWalletNotification(_), - readWalletNotification(_).asInstanceOf[NewAddressNotification]) + readWalletNotification(_).asInstanceOf[NewAddressNotification] + ) } implicit val txProcessedPickler: ReadWriter[TxProcessedNotification] = { readwriter[ujson.Obj].bimap( writeWalletNotification(_), - readWalletNotification(_).asInstanceOf[TxProcessedNotification]) + readWalletNotification(_).asInstanceOf[TxProcessedNotification] + ) } implicit val txBroadcastPickler: ReadWriter[TxBroadcastNotification] = { readwriter[ujson.Obj].bimap( writeWalletNotification(_), - readWalletNotification(_).asInstanceOf[TxBroadcastNotification]) + readWalletNotification(_).asInstanceOf[TxBroadcastNotification] + ) } implicit val reservedUtxosPickler: ReadWriter[ReservedUtxosNotification] = { readwriter[ujson.Obj].bimap( writeWalletNotification(_), - readWalletNotification(_).asInstanceOf[ReservedUtxosNotification]) + readWalletNotification(_).asInstanceOf[ReservedUtxosNotification] + ) } implicit val rescanPickler: ReadWriter[RescanComplete] = { @@ -313,8 +327,8 @@ object WsPicklers { ) } - implicit val dlcNodeNotificationPickler: ReadWriter[ - DLCNodeNotification[_]] = { + implicit val dlcNodeNotificationPickler + : ReadWriter[DLCNodeNotification[_]] = { readwriter[ujson.Obj] .bimap(writeDLCNodeNotification, readDLCNodeNotification) } @@ -334,8 +348,8 @@ object WsPicklers { ) } - implicit val compactFilterHeaderProcessedPickler: ReadWriter[ - CompactFilterHeaderProcessedNotification] = { + implicit val compactFilterHeaderProcessedPickler + : ReadWriter[CompactFilterHeaderProcessedNotification] = { readwriter[ujson.Obj].bimap( writeChainNotification(_), readChainNotification(_) @@ -343,16 +357,16 @@ object WsPicklers { ) } - implicit val compactFilterProcessedPickler: ReadWriter[ - CompactFilterProcessedNotification] = { + implicit val compactFilterProcessedPickler + : ReadWriter[CompactFilterProcessedNotification] = { readwriter[ujson.Obj].bimap( writeChainNotification(_), readChainNotification(_).asInstanceOf[CompactFilterProcessedNotification] ) } - implicit val syncFlagChangedPickler: ReadWriter[ - SyncFlagChangedNotification] = { + implicit val syncFlagChangedPickler + : ReadWriter[SyncFlagChangedNotification] = { readwriter[ujson.Obj].bimap( writeChainNotification(_), readChainNotification(_).asInstanceOf[SyncFlagChangedNotification] @@ -362,83 +376,96 @@ object WsPicklers { implicit val dlcStateChangePickler: ReadWriter[DLCStateChangeNotification] = { readwriter[ujson.Obj].bimap( writeWalletNotification(_), - readWalletNotification(_).asInstanceOf[DLCStateChangeNotification]) + readWalletNotification(_).asInstanceOf[DLCStateChangeNotification] + ) } implicit val dlcOfferAddPickler: ReadWriter[DLCOfferAddNotification] = { readwriter[ujson.Obj].bimap( writeWalletNotification(_), - readWalletNotification(_).asInstanceOf[DLCOfferAddNotification]) + readWalletNotification(_).asInstanceOf[DLCOfferAddNotification] + ) } implicit val dlcOfferRemovePickler: ReadWriter[DLCOfferRemoveNotification] = { readwriter[ujson.Obj].bimap( writeWalletNotification(_), - readWalletNotification(_).asInstanceOf[DLCOfferRemoveNotification]) + readWalletNotification(_).asInstanceOf[DLCOfferRemoveNotification] + ) } - implicit val torStartedPickler: ReadWriter[ - TorNotification.TorStartedNotification.type] = { + implicit val torStartedPickler + : ReadWriter[TorNotification.TorStartedNotification.type] = { readwriter[ujson.Obj].bimap( writeTorNotification(_), readTorNotification(_) - .asInstanceOf[TorNotification.TorStartedNotification.type]) + .asInstanceOf[TorNotification.TorStartedNotification.type] + ) } - implicit val dlcNodeConnectionInitiatedPickler: ReadWriter[ - DLCNodeConnectionInitiated] = { + implicit val dlcNodeConnectionInitiatedPickler + : ReadWriter[DLCNodeConnectionInitiated] = { readwriter[ujson.Obj].bimap( writeDLCNodeNotification(_), - readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionInitiated]) + readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionInitiated] + ) } - implicit val dlcNodeConnectionFailedPickler: ReadWriter[ - DLCNodeConnectionFailed] = { + implicit val dlcNodeConnectionFailedPickler + : ReadWriter[DLCNodeConnectionFailed] = { readwriter[ujson.Obj].bimap( writeDLCNodeNotification(_), - readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionFailed]) + readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionFailed] + ) } - implicit val dlcNodeConnectionEstablishedPickler: ReadWriter[ - DLCNodeConnectionEstablished] = { + implicit val dlcNodeConnectionEstablishedPickler + : ReadWriter[DLCNodeConnectionEstablished] = { readwriter[ujson.Obj].bimap( writeDLCNodeNotification(_), - readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionEstablished]) + readDLCNodeNotification(_).asInstanceOf[DLCNodeConnectionEstablished] + ) } implicit val dlcAcceptSucceedPickler: ReadWriter[DLCAcceptSucceed] = { readwriter[ujson.Obj].bimap( writeDLCNodeNotification(_), - readDLCNodeNotification(_).asInstanceOf[DLCAcceptSucceed]) + readDLCNodeNotification(_).asInstanceOf[DLCAcceptSucceed] + ) } implicit val dlcAcceptFailedPickler: ReadWriter[DLCAcceptFailed] = { readwriter[ujson.Obj].bimap( writeDLCNodeNotification(_), - readDLCNodeNotification(_).asInstanceOf[DLCAcceptFailed]) + readDLCNodeNotification(_).asInstanceOf[DLCAcceptFailed] + ) } implicit val dlcSignSucceedPickler: ReadWriter[DLCSignSucceed] = { readwriter[ujson.Obj].bimap( writeDLCNodeNotification(_), - readDLCNodeNotification(_).asInstanceOf[DLCSignSucceed]) + readDLCNodeNotification(_).asInstanceOf[DLCSignSucceed] + ) } implicit val dlcSignFailedPickler: ReadWriter[DLCSignFailed] = { readwriter[ujson.Obj].bimap( writeDLCNodeNotification(_), - readDLCNodeNotification(_).asInstanceOf[DLCSignFailed]) + readDLCNodeNotification(_).asInstanceOf[DLCSignFailed] + ) } implicit val dlcOfferSendSucceedPickler: ReadWriter[DLCOfferSendSucceed] = { readwriter[ujson.Obj].bimap( writeDLCNodeNotification(_), - readDLCNodeNotification(_).asInstanceOf[DLCOfferSendSucceed]) + readDLCNodeNotification(_).asInstanceOf[DLCOfferSendSucceed] + ) } implicit val dlcOfferSendFailedPickler: ReadWriter[DLCOfferSendFailed] = { readwriter[ujson.Obj].bimap( writeDLCNodeNotification(_), - readDLCNodeNotification(_).asInstanceOf[DLCOfferSendFailed]) + readDLCNodeNotification(_).asInstanceOf[DLCOfferSendFailed] + ) } } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirParser.scala b/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirParser.scala index 111ee94ff9..85eca3fcb8 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirParser.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirParser.scala @@ -5,14 +5,15 @@ import org.bitcoins.commons.config.AppConfig import java.nio.file.{Path, Paths} -/** Parses the correct datadir given the possible input sources for datadir config - * 1. The --datadir command line flag - * 2. Inferring the datadir based on the bitcoin network configured - * 3. ??? Anything else i'm forgetting ???? +/** Parses the correct datadir given the possible input sources for datadir + * config + * 1. The --datadir command line flag 2. Inferring the datadir based on the + * bitcoin network configured 3. ??? Anything else i'm forgetting ???? */ case class DatadirParser( serverArgs: ServerArgParser, - customFinalDirOpt: Option[String]) { + customFinalDirOpt: Option[String] +) { /** Sets the default data dir, overridden by the --datadir option */ private lazy val datadirPath: Path = serverArgs.datadirOpt match { @@ -22,7 +23,8 @@ case class DatadirParser( lazy val datadirConfig: Config = ConfigFactory.parseString( - s"bitcoin-s.datadir = ${AppConfig.safePathToString(datadirPath)}") + s"bitcoin-s.datadir = ${AppConfig.safePathToString(datadirPath)}" + ) lazy val networkConfig: Config = serverArgs.networkOpt match { case Some(network) => @@ -35,9 +37,11 @@ case class DatadirParser( serverArgs.configOpt match { case None => AppConfig - .getBaseConfig(datadirPath, - AppConfig.DEFAULT_BITCOIN_S_CONF_FILE, - Vector(networkConfig)) + .getBaseConfig( + datadirPath, + AppConfig.DEFAULT_BITCOIN_S_CONF_FILE, + Vector(networkConfig) + ) .withFallback(datadirConfig) .resolve() case Some(config) => @@ -55,11 +59,8 @@ case class DatadirParser( lazy val datadir: Path = Paths.get(baseConfig.getString("bitcoin-s.datadir")) - /** Directory specific for current network or custom dir - * Examples are - * HOME/.bitcoin-s/mainnet - * HOME/.bitcoin-s/testnet3 - * HOME/.bitcoin-s/oracle + /** Directory specific for current network or custom dir Examples are + * HOME/.bitcoin-s/mainnet HOME/.bitcoin-s/testnet3 HOME/.bitcoin-s/oracle */ def networkDir: Path = DatadirUtil.getFinalDatadir(datadir, baseConfig, customFinalDirOpt) diff --git a/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirUtil.scala b/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirUtil.scala index 377f3228f8..f47d26e7e0 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirUtil.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/util/DatadirUtil.scala @@ -30,15 +30,15 @@ object DatadirUtil { } } - /** Sets the final datadir for our applicatoin. - * We allow useres to pass in a --datadir command line - * flag that needs to be used instead of the [[datadir]] - * specified in bitcoin-s.conf + /** Sets the final datadir for our applicatoin. We allow useres to pass in a + * --datadir command line flag that needs to be used instead of the + * [[datadir]] specified in bitcoin-s.conf */ def getFinalDatadir( datadir: Path, baseConfig: Config, - customFinalDirOpt: Option[String] = None): Path = { + customFinalDirOpt: Option[String] = None + ): Path = { // $HOME is not set for windows, need to manually set it if (Properties.isWin) { diff --git a/app-commons/src/main/scala/org/bitcoins/commons/util/NativeProcessFactory.scala b/app-commons/src/main/scala/org/bitcoins/commons/util/NativeProcessFactory.scala index fe417c43ec..00421cf474 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/util/NativeProcessFactory.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/util/NativeProcessFactory.scala @@ -30,7 +30,7 @@ trait NativeProcessFactory extends BitcoinSLogger { def startBinary(): Future[Unit] = FutureUtil.makeAsync { () => processOpt match { case Some(p) => - //don't do anything as it is already started + // don't do anything as it is already started logger.info(s"Binary was already started! process=$p") () case None => @@ -46,8 +46,8 @@ trait NativeProcessFactory extends BitcoinSLogger { /** Stops the binary by destroying the underlying operating system process * - * If the client is a remote client (not started on the host operating system) - * this method is a no-op + * If the client is a remote client (not started on the host operating + * system) this method is a no-op */ def stopBinary(): Future[Unit] = FutureUtil.makeAsync { () => processOpt match { @@ -58,7 +58,7 @@ trait NativeProcessFactory extends BitcoinSLogger { processOpt = None case None => logger.info(s"No process found, binary wasn't started!") - //no process running, nothing to do + // no process running, nothing to do () } } diff --git a/app-commons/src/main/scala/org/bitcoins/commons/util/ServerArgParser.scala b/app-commons/src/main/scala/org/bitcoins/commons/util/ServerArgParser.scala index ad0f658431..40c0292e54 100644 --- a/app-commons/src/main/scala/org/bitcoins/commons/util/ServerArgParser.scala +++ b/app-commons/src/main/scala/org/bitcoins/commons/util/ServerArgParser.scala @@ -7,8 +7,9 @@ import org.bitcoins.core.config._ import java.nio.file.{Path, Paths} import scala.util.Properties -/** Parses arguments passed to the bitcoin-s app server as command line arguments - * This does NOT consider things that exist in reference.conf or application.conf files +/** Parses arguments passed to the bitcoin-s app server as command line + * arguments This does NOT consider things that exist in reference.conf or + * application.conf files */ case class ServerArgParser(commandLineArgs: Vector[String]) { @@ -70,10 +71,10 @@ case class ServerArgParser(commandLineArgs: Vector[String]) { /** The datadir passed in as a command line arg using --datadir */ lazy val datadirOpt: Option[Path] = dataDirIndexOpt.map { case (_, idx) => val str = commandLineArgs(idx + 1) - //we only want the replace ~ if it is first in the file path - //otherwise windows gets mangled as it can have parts of the file path containing ~ - //https://stackoverflow.com/a/7163455/967713 - //C:\Users\RUNNER~1\AppData\Local\Temp\bitcoin-s-13391384540028797275 + // we only want the replace ~ if it is first in the file path + // otherwise windows gets mangled as it can have parts of the file path containing ~ + // https://stackoverflow.com/a/7163455/967713 + // C:\Users\RUNNER~1\AppData\Local\Temp\bitcoin-s-13391384540028797275 val usableStr = str.replaceFirst("^~", Properties.userHome) Paths.get(usableStr) } @@ -91,9 +92,9 @@ case class ServerArgParser(commandLineArgs: Vector[String]) { } } - /** Converts the given command line args into a Config object. - * There is one exclusion to this, we cannot write the --conf - * flag to the config file as that is self referential + /** Converts the given command line args into a Config object. There is one + * exclusion to this, we cannot write the --conf flag to the config file as + * that is self referential */ def toConfig: Config = { val rpcPortString = rpcPortOpt match { @@ -126,7 +127,7 @@ case class ServerArgParser(commandLineArgs: Vector[String]) { case None => "" } - //omitting configOpt as i don't know if we can do anything with that? + // omitting configOpt as i don't know if we can do anything with that? val all = rpcPortString + diff --git a/app/cli/src/main/scala/org/bitcoins/cli/Cli.scala b/app/cli/src/main/scala/org/bitcoins/cli/Cli.scala index d4c5bff5bf..21990058b2 100644 --- a/app/cli/src/main/scala/org/bitcoins/cli/Cli.scala +++ b/app/cli/src/main/scala/org/bitcoins/cli/Cli.scala @@ -18,7 +18,8 @@ object Cli extends App { } catch { case _: ConnectException => printerr( - "Connection refused! Check that the server is running and configured correctly.") + "Connection refused! Check that the server is running and configured correctly." + ) sys.exit(1) } } diff --git a/app/cli/src/main/scala/org/bitcoins/cli/CliReaders.scala b/app/cli/src/main/scala/org/bitcoins/cli/CliReaders.scala index c668d5cc97..c5e09ea9f0 100644 --- a/app/cli/src/main/scala/org/bitcoins/cli/CliReaders.scala +++ b/app/cli/src/main/scala/org/bitcoins/cli/CliReaders.scala @@ -103,8 +103,8 @@ object CliReaders { EnumEventDescriptorV0TLV.fromHex } - implicit val digitDecompEventDescriptorReads: Read[ - DigitDecompositionEventDescriptorV0TLV] = + implicit val digitDecompEventDescriptorReads + : Read[DigitDecompositionEventDescriptorV0TLV] = new Read[DigitDecompositionEventDescriptorV0TLV] { override def arity: Int = 1 @@ -124,7 +124,8 @@ object CliReaders { override def arity: Int = 1 override def reads: String => ContractDescriptorTLV = { str => upickle.default.read[ContractDescriptorV0TLV](str)( - Picklers.contractDescriptorV0) + Picklers.contractDescriptorV0 + ) } } } @@ -239,14 +240,16 @@ object CliReaders { val reads: String => BlockStamp = { case dateRe(year, month, day) => - val time = ZonedDateTime.of(year.toInt, - month.toInt, - day.toInt, - 0, - 0, - 0, - 0, - ZoneId.of("UTC")) + val time = ZonedDateTime.of( + year.toInt, + month.toInt, + day.toInt, + 0, + 0, + 0, + 0, + ZoneId.of("UTC") + ) BlockTime(time) case str => BlockStamp.fromString(str) } @@ -310,8 +313,8 @@ object CliReaders { val reads: String => Sha256DigestBE = Sha256DigestBE.fromHex } - implicit val lockUnspentOutputParametersReads: Read[ - Vector[LockUnspentOutputParameter]] = + implicit val lockUnspentOutputParametersReads + : Read[Vector[LockUnspentOutputParameter]] = new Read[Vector[LockUnspentOutputParameter]] { override val arity: Int = 1 diff --git a/app/cli/src/main/scala/org/bitcoins/cli/ConsoleCli.scala b/app/cli/src/main/scala/org/bitcoins/cli/ConsoleCli.scala index 6a0c7d26cd..d32be9ddf5 100644 --- a/app/cli/src/main/scala/org/bitcoins/cli/ConsoleCli.scala +++ b/app/cli/src/main/scala/org/bitcoins/cli/ConsoleCli.scala @@ -92,7 +92,8 @@ object ConsoleCli extends BitcoinSLogger { conf.copy(command = conf.command match { case gbh: GetBlockHeader => gbh.copy(hash = hash) case other => other - }))), + })) + ), cmd("getmediantimepast") .action((_, conf) => conf.copy(command = GetMedianTimePast)) .text(s"Get the median time past"), @@ -109,16 +110,20 @@ object ConsoleCli extends BitcoinSLogger { case decode: DecodeRawTransaction => decode.copy(tx = tx) case other => other - }))), + })) + ), note(sys.props("line.separator") + "=== Wallet ==="), cmd("rescan") .action((_, conf) => conf.copy( - command = Rescan(batchSize = Option.empty, - startBlock = Option.empty, - endBlock = Option.empty, - force = false, - ignoreCreationTime = false))) + command = Rescan( + batchSize = Option.empty, + startBlock = Option.empty, + endBlock = Option.empty, + force = false, + ignoreCreationTime = false + ) + )) .text(s"Rescan for wallet UTXOs") .children( opt[Unit]("force") @@ -148,8 +153,8 @@ object ConsoleCli extends BitcoinSLogger { // Need to ignoreCreationTime so we try to call // rescan with rescanNeutrinoWallet with a block // and a creation time - rescan.copy(startBlock = Option(start), - ignoreCreationTime = true) + rescan + .copy(startBlock = Option(start), ignoreCreationTime = true) case other => other })), opt[BlockStamp]("end") @@ -162,7 +167,9 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), opt[Unit]("ignorecreationtime") - .text("Ignores the wallet creation date and will instead do a full rescan") + .text( + "Ignores the wallet creation date and will instead do a full rescan" + ) .optional() .action((_, conf) => conf.copy(command = conf.command match { @@ -248,7 +255,8 @@ object ConsoleCli extends BitcoinSLogger { cmd("getspentaddresses") .action((_, conf) => conf.copy(command = GetSpentAddresses)) .text( - "Returns list of all wallet addresses that have received funds and been spent"), + "Returns list of all wallet addresses that have received funds and been spent" + ), cmd("getfundedaddresses") .action((_, conf) => conf.copy(command = GetFundedAddresses)) .text("Returns list of all wallet addresses that are holding funds"), @@ -428,7 +436,8 @@ object ConsoleCli extends BitcoinSLogger { cmd("sendfromoutpoints") .action((_, conf) => conf.copy( - command = SendFromOutPoints(Vector.empty, null, 0.bitcoin, None))) + command = SendFromOutPoints(Vector.empty, null, 0.bitcoin, None) + )) .text("Send money to the given address") .children( arg[Seq[TransactionOutPoint]]("outpoints") @@ -472,7 +481,8 @@ object ConsoleCli extends BitcoinSLogger { .action((_, conf) => conf.copy(command = SendWithAlgo(null, 0.bitcoin, None, null))) .text( - "Send money to the given address using a specific coin selection algo") + "Send money to the given address using a specific coin selection algo" + ) .children( arg[BitcoinAddress]("address") .text("Address to send to") @@ -536,7 +546,9 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("signpsbt") .action((_, conf) => conf.copy(command = SignPSBT(PSBT.empty))) - .text("Signs the PSBT's inputs with keys that are associated with the wallet") + .text( + "Signs the PSBT's inputs with keys that are associated with the wallet" + ) .children( arg[PSBT]("psbt") .text("PSBT to sign") @@ -585,7 +597,9 @@ object ConsoleCli extends BitcoinSLogger { .action((_, conf) => conf.copy(command = BumpFeeCPFP(DoubleSha256DigestBE.empty, SatoshisPerVirtualByte.zero))) - .text("Bump the fee of the given transaction id with a child tx using the given fee rate") + .text( + "Bump the fee of the given transaction id with a child tx using the given fee rate" + ) .children( arg[DoubleSha256DigestBE]("txid") .text("Id of transaction to bump fee") @@ -649,11 +663,15 @@ object ConsoleCli extends BitcoinSLogger { cmd("lockunspent") .action((_, conf) => conf.copy(command = LockUnspent(unlock = false, Vector.empty))) - .text("Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs." + - "\nIf no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.") + .text( + "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs." + + "\nIf no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked." + ) .children( arg[Boolean]("unlock") - .text("Whether to unlock (true) or lock (false) the specified transactions") + .text( + "Whether to unlock (true) or lock (false) the specified transactions" + ) .required() .action((unlock, conf) => conf.copy(command = conf.command match { @@ -662,7 +680,9 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[Vector[LockUnspentOutputParameter]]("transactions") - .text("The transaction outpoints to unlock/lock, empty to apply to all utxos") + .text( + "The transaction outpoints to unlock/lock, empty to apply to all utxos" + ) .optional() .action((outputParam, conf) => conf.copy(command = conf.command match { @@ -849,7 +869,8 @@ object ConsoleCli extends BitcoinSLogger { .children( opt[String]("walletname") .text( - "Wallet's name (the default wallet will be loaded if omitted)") + "Wallet's name (the default wallet will be loaded if omitted)" + ) .optional() .action((walletName, conf) => conf.copy(command = conf.command match { @@ -889,7 +910,8 @@ object ConsoleCli extends BitcoinSLogger { case decode: DecodeContractInfo => decode.copy(contractInfo = contractInfo) case other => other - }))), + })) + ), cmd("decodeoffer") .action((_, conf) => conf.copy(command = DecodeOffer(null))) .text("Decodes an offer message into json") @@ -902,7 +924,8 @@ object ConsoleCli extends BitcoinSLogger { case decode: DecodeOffer => decode.copy(offer = offer) case other => other - }))), + })) + ), cmd("decodeannouncement") .action((_, conf) => conf.copy(command = DecodeAnnouncement(null))) .text("Decodes an oracle announcement message into json") @@ -915,7 +938,8 @@ object ConsoleCli extends BitcoinSLogger { case decode: DecodeAnnouncement => decode.copy(announcement = ann) case other => other - }))), + })) + ), cmd("decodeattestments") .action((_, conf) => conf.copy(command = DecodeAttestments(null))) .text("Decodes an oracle attestments message into json") @@ -928,21 +952,25 @@ object ConsoleCli extends BitcoinSLogger { case decode: DecodeAttestments => decode.copy(sigs = attestments) case other => other - }))), + })) + ), cmd("getdlchostaddress") .action((_, conf) => conf.copy(command = GetDLCHostAddress)) .text("Returns the public listening address of the DLC Node"), cmd("createdlcoffer") .action((_, conf) => conf.copy( - command = CreateDLCOffer(ContractInfoV0TLV.dummy, - Satoshis.zero, - None, - None, - UInt32.zero, - None, - None, - None))) + command = CreateDLCOffer( + ContractInfoV0TLV.dummy, + Satoshis.zero, + None, + None, + UInt32.zero, + None, + None, + None + ) + )) .text("Creates a DLC offer that another party can accept") .children( arg[ContractInfoV0TLV]("contractInfo") @@ -964,7 +992,9 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[SatoshisPerVirtualByte]("feerate") - .text("Fee rate for both funding and closing transactions, in sats/vbytes") + .text( + "Fee rate for both funding and closing transactions, in sats/vbytes" + ) .optional() .action((feeRate, conf) => conf.copy(command = conf.command match { @@ -993,11 +1023,12 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("acceptdlc") .action((_, conf) => - conf.copy(command = - AcceptDLC(null, - InetSocketAddress.createUnresolved("localhost", 0), - None, - None))) + conf.copy(command = AcceptDLC( + null, + InetSocketAddress.createUnresolved("localhost", 0), + None, + None + ))) .text("Accepts a DLC offer given from another party") .children( arg[LnMessage[DLCOfferTLV]]("offer") @@ -1128,7 +1159,9 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("adddlcsigsandbroadcast") .action((_, conf) => conf.copy(command = AddDLCSigsAndBroadcast(null))) - .text("Adds DLC Signatures into the database and broadcasts the funding transaction") + .text( + "Adds DLC Signatures into the database and broadcasts the funding transaction" + ) .children( arg[LnMessage[DLCSignTLV]]("sigs") .text("Hex encoded dlc sign message") @@ -1144,7 +1177,9 @@ object ConsoleCli extends BitcoinSLogger { .action((_, conf) => conf.copy(command = AddDLCSigsAndBroadcastFromFile(new File("").toPath))) - .text("Adds DLC Signatures into the database and broadcasts the funding transaction") + .text( + "Adds DLC Signatures into the database and broadcasts the funding transaction" + ) .children( arg[Path]("path") .text("Path to dlc sign file") @@ -1158,7 +1193,9 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("getdlcfundingtx") .action((_, conf) => conf.copy(command = GetDLCFundingTx(null))) - .text("Returns the Funding Tx corresponding to the DLC with the given contractId") + .text( + "Returns the Funding Tx corresponding to the DLC with the given contractId" + ) .children( arg[ByteVector]("contractId") .text("ContractId of the DLC") @@ -1172,7 +1209,9 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("broadcastdlcfundingtx") .action((_, conf) => conf.copy(command = BroadcastDLCFundingTx(null))) - .text("Broadcasts the funding Tx corresponding to the DLC with the given contractId") + .text( + "Broadcasts the funding Tx corresponding to the DLC with the given contractId" + ) .children( arg[ByteVector]("contractId") .text("ContractId of the DLC") @@ -1270,7 +1309,8 @@ object ConsoleCli extends BitcoinSLogger { conf.copy(command = conf.command match { case _: GetDLC => GetDLC(dlcId) case other => other - }))), + })) + ), cmd("contact-add") .action((_, conf) => conf.copy(command = ContactAdd.empty)) .text("Add a contact to your DLC wallet") @@ -1312,7 +1352,8 @@ object ConsoleCli extends BitcoinSLogger { .children( arg[InetSocketAddress]("address") .text( - "The address of the contact we want to remove from the wallet") + "The address of the contact we want to remove from the wallet" + ) .required() .action((address, conf) => conf.copy(command = conf.command match { @@ -1323,7 +1364,9 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("createcontractinfo") .action((_, conf) => conf.copy(command = CreateContractInfo.empty)) - .text("Create a contract info from an announcement, total collateral, and contract descriptor") + .text( + "Create a contract info from an announcement, total collateral, and contract descriptor" + ) .children( arg[OracleAnnouncementTLV]("announcement") .text("The announcement we are creating a contract info for") @@ -1335,7 +1378,9 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[Satoshis]("totalCollateral") - .text("The total collateral in the DLC. This is your collateral + counterparty collateral") + .text( + "The total collateral in the DLC. This is your collateral + counterparty collateral" + ) .required() .action((totalCollateral, conf) => conf.copy(command = conf.command match { @@ -1344,7 +1389,9 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[ContractDescriptorTLV]("contractDescriptor") - .text("The contract descriptor in the DLC. This is expected to be of format [[outcome1, payout1], [outcome2, payout2], ...]") + .text( + "The contract descriptor in the DLC. This is expected to be of format [[outcome1, payout1], [outcome2, payout2], ...]" + ) .required() .action((contractDescriptor, conf) => conf.copy(command = conf.command match { @@ -1424,7 +1471,9 @@ object ConsoleCli extends BitcoinSLogger { note(sys.props("line.separator") + "=== PSBT ==="), cmd("decodepsbt") .action((_, conf) => conf.copy(command = DecodePSBT(PSBT.empty))) - .text("Return a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.") + .text( + "Return a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction." + ) .children( arg[PSBT]("psbt") .text("PSBT serialized in hex or base64 format") @@ -1434,10 +1483,13 @@ object ConsoleCli extends BitcoinSLogger { case decode: DecodePSBT => decode.copy(psbt = psbt) case other => other - }))), + })) + ), cmd("analyzepsbt") .action((_, conf) => conf.copy(command = AnalyzePSBT(PSBT.empty))) - .text("Analyzes and provides information about the current status of a PSBT and its inputs") + .text( + "Analyzes and provides information about the current status of a PSBT and its inputs" + ) .children( arg[PSBT]("psbt") .text("PSBT serialized in hex or base64 format") @@ -1549,7 +1601,9 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[Date]("maturationtime") - .text("The earliest expected time an outcome will be signed, given in ISO 8601 format") + .text( + "The earliest expected time an outcome will be signed, given in ISO 8601 format" + ) .required() .action((date, conf) => conf.copy(command = conf.command match { @@ -1569,14 +1623,17 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("createnumericannouncement") .action((_, conf) => - conf.copy(command = CreateNumericAnnouncement(eventName = "", - maturationTime = - new Date(), - minValue = 0, - maxValue = 0, - unit = "", - precision = 0))) - .text("Registers an oracle announcement that uses digit decomposition when signing the number") + conf.copy(command = CreateNumericAnnouncement( + eventName = "", + maturationTime = new Date(), + minValue = 0, + maxValue = 0, + unit = "", + precision = 0 + ))) + .text( + "Registers an oracle announcement that uses digit decomposition when signing the number" + ) .children( arg[String]("name") .text("Name for this announcement") @@ -1588,7 +1645,9 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[Date]("maturationtime") - .text("The earliest expected time an outcome will be signed, given in ISO 8601 format") + .text( + "The earliest expected time an outcome will be signed, given in ISO 8601 format" + ) .required() .action((date, conf) => conf.copy(command = conf.command match { @@ -1623,9 +1682,11 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[Int]("precision") - .text("The precision of the outcome representing the " + - "base exponent by which to multiply the number represented by " + - "the composition of the digits to obtain the actual outcome value.") + .text( + "The precision of the outcome representing the " + + "base exponent by which to multiply the number represented by " + + "the composition of the digits to obtain the actual outcome value." + ) .action((precision, conf) => conf.copy(command = conf.command match { case createNumericEvent: CreateNumericAnnouncement => @@ -1635,14 +1696,18 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("createdigitdecompannouncement") .action((_, conf) => - conf.copy(command = CreateDigitDecompAnnouncement("", - Instant.MIN, - 0, - isSigned = false, - 0, - "", - 0))) - .text("Registers an oracle announcement that uses digit decomposition when signing the number") + conf.copy(command = CreateDigitDecompAnnouncement( + "", + Instant.MIN, + 0, + isSigned = false, + 0, + "", + 0 + ))) + .text( + "Registers an oracle announcement that uses digit decomposition when signing the number" + ) .children( arg[String]("name") .text("Name for this announcement") @@ -1654,7 +1719,9 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[Instant]("maturationtime") - .text("The earliest expected time an outcome will be signed, given in epoch second") + .text( + "The earliest expected time an outcome will be signed, given in epoch second" + ) .required() .action((time, conf) => conf.copy(command = conf.command match { @@ -1696,9 +1763,11 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[Int]("precision") - .text("The precision of the outcome representing the " + - "base exponent by which to multiply the number represented by " + - "the composition of the digits to obtain the actual outcome value.") + .text( + "The precision of the outcome representing the " + + "base exponent by which to multiply the number represented by " + + "the composition of the digits to obtain the actual outcome value." + ) .action((precision, conf) => conf.copy(command = conf.command match { case createLargeRangedEvent: CreateDigitDecompAnnouncement => @@ -1708,7 +1777,9 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("deleteannouncement") .action((_, conf) => conf.copy(command = DeleteAnnouncement(""))) - .text("Delete an announcement. WARNING: THIS CAN LEAD TO DLCs NOT SETTLING IF USERS HAVE BUILT DLCS OFF OF THIS ANNOUNCEMENT. USE WITH CARE.") + .text( + "Delete an announcement. WARNING: THIS CAN LEAD TO DLCs NOT SETTLING IF USERS HAVE BUILT DLCS OFF OF THIS ANNOUNCEMENT. USE WITH CARE." + ) .children( arg[String]("eventName") .text("The event's name") @@ -1722,7 +1793,9 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("deleteattestation") .action((_, conf) => conf.copy(command = DeleteAttestation(""))) - .text("Delete an announcement. WARNING THIS CAN LEAD TO PRIVATE KEY LEAK IF YOU SIGN ANOTHER ATTESTATION AFTER DELETING A PREVIOUS ONE. USE WITH CARE.") + .text( + "Delete an announcement. WARNING THIS CAN LEAD TO PRIVATE KEY LEAK IF YOU SIGN ANOTHER ATTESTATION AFTER DELETING A PREVIOUS ONE. USE WITH CARE." + ) .children( arg[String]("eventName") .text("The event's name") @@ -1810,7 +1883,9 @@ object ConsoleCli extends BitcoinSLogger { ), cmd("signmessage") .action((_, conf) => conf.copy(command = SignMessage(""))) - .text("Signs the SHA256 hash of the given string using the oracle's signing key") + .text( + "Signs the SHA256 hash of the given string using the oracle's signing key" + ) .children( arg[String]("message") .text("Message to hash and sign") @@ -1857,7 +1932,9 @@ object ConsoleCli extends BitcoinSLogger { cmd("createmultisig") .action((_, conf) => conf.copy(command = CreateMultisig(0, Vector.empty, SegWit))) - .text("Creates a multi-signature address with n signature of m keys required.") + .text( + "Creates a multi-signature address with n signature of m keys required." + ) .children( arg[Int]("nrequired") .text("The number of required signatures out of the n keys.") @@ -1878,7 +1955,9 @@ object ConsoleCli extends BitcoinSLogger { case other => other })), arg[AddressType]("address_type") - .text("The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"") + .text( + "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"" + ) .optional() .action((addrType, conf) => conf.copy(command = conf.command match { @@ -1894,7 +1973,8 @@ object ConsoleCli extends BitcoinSLogger { .action((_, conf) => conf.copy(command = ZipDataDir(new File("").toPath))) .text( - "zips the bitcoin-s datadir and places the file at the given path") + "zips the bitcoin-s datadir and places the file at the given path" + ) .children( arg[Path]("path") .text("Location of final zip file") @@ -1904,7 +1984,8 @@ object ConsoleCli extends BitcoinSLogger { case zipDataDir: ZipDataDir => zipDataDir.copy(path = path) case other => other - }))), + })) + ), checkConfig { case Config(org.bitcoins.commons.rpc.CliCommand.NoCommand, _, _, _) => failure("You need to provide a command!") @@ -1927,19 +2008,19 @@ object ConsoleCli extends BitcoinSLogger { Failure(new RuntimeException(message)) } - /** Gets the given key from jsObj if it exists - * and is not null + /** Gets the given key from jsObj if it exists and is not null */ private def getKey( key: String, - jsObjT: Try[mutable.LinkedHashMap[String, ujson.Value]]): Option[ - ujson.Value] = { - jsObjT.toOption.flatMap(_.get(key).flatMap(result => - if (result.isNull) None else Some(result))) + jsObjT: Try[mutable.LinkedHashMap[String, ujson.Value]] + ): Option[ujson.Value] = { + jsObjT.toOption.flatMap( + _.get(key).flatMap(result => if (result.isNull) None else Some(result)) + ) } - /** Converts a `ujson.Value` to String, making an - * effort to avoid preceding and trailing `"`s + /** Converts a `ujson.Value` to String, making an effort to avoid preceding + * and trailing `"`s */ private def jsValueToString(value: ujson.Value): String = { value match { @@ -1958,7 +2039,8 @@ object ConsoleCli extends BitcoinSLogger { def exec( command: org.bitcoins.commons.rpc.CliCommand, - config: Config): Try[String] = { + config: Config + ): Try[String] = { val requestParam = CliCommand.buildRequest(command) import sttp.client3._ @@ -1992,18 +2074,21 @@ object ConsoleCli extends BitcoinSLogger { case Right(response) => response } Iterator.apply() - val jsObjT: Try[ - scala.collection.mutable.LinkedHashMap[String, ujson.Value]] = { + val jsObjT + : Try[scala.collection.mutable.LinkedHashMap[String, ujson.Value]] = { Try(ujson.read(rawBody).obj) .transform[scala.collection.mutable.LinkedHashMap[String, ujson.Value]]( { case v: upickle.core.LinkedHashMap[String, ujson.Value] => Success( - scala.collection.mutable.LinkedHashMap.from(v.iterator.toVector)) + scala.collection.mutable.LinkedHashMap.from(v.iterator.toVector) + ) }, _ => Success( scala.collection.mutable.LinkedHashMap[String, ujson.Value]( - "error" -> Str(rawBody))) + "error" -> Str(rawBody) + ) + ) ) } @@ -2023,7 +2108,8 @@ object ConsoleCli extends BitcoinSLogger { case class RequestParam( method: String, - params: Seq[ujson.Value.Value] = Nil) { + params: Seq[ujson.Value.Value] = Nil + ) { lazy val toJsonMap: Map[String, ujson.Value] = { if (params.isEmpty) @@ -2039,7 +2125,8 @@ case class Config( org.bitcoins.commons.rpc.CliCommand.NoCommand, network: Option[NetworkParameters] = None, rpcPortOpt: Option[Int] = None, - rpcPassword: String = "") { + rpcPassword: String = "" +) { val rpcPort: Int = rpcPortOpt match { case Some(port) => port @@ -2085,7 +2172,8 @@ object CliCommand { case ContactAdd(alias, address, memo) => RequestParam( "contact-add", - Seq(up.writeJs(alias), up.writeJs(address), up.writeJs(memo))) + Seq(up.writeJs(alias), up.writeJs(address), up.writeJs(memo)) + ) case ContactsList => RequestParam("contacts-list", Seq.empty) case ContactRemove(address) => @@ -2106,14 +2194,16 @@ object CliCommand { case GetDLCs => RequestParam("getdlcs") case GetDLC(dlcId) => RequestParam("getdlc", Seq(up.writeJs(dlcId))) - case CreateDLCOffer(contractInfoTLV, - collateral, - feeRateOpt, - locktimeOpt, - refundLocktime, - externalPayoutAddressOpt, - externalChangeAddressOpt, - peerAddressOpt) => + case CreateDLCOffer( + contractInfoTLV, + collateral, + feeRateOpt, + locktimeOpt, + refundLocktime, + externalPayoutAddressOpt, + externalChangeAddressOpt, + peerAddressOpt + ) => RequestParam( "createdlcoffer", Seq( @@ -2127,27 +2217,41 @@ object CliCommand { up.writeJs(peerAddressOpt) ) ) - case AcceptDLC(offer, - peerAddr, - externalPayoutAddressOpt, - externalChangeAddressOpt) => - RequestParam("acceptdlc", - Seq(up.writeJs(offer), - up.writeJs(peerAddr), - up.writeJs(externalPayoutAddressOpt), - up.writeJs(externalChangeAddressOpt))) - case AcceptDLCOffer(offer, - peerAddr, - externalPayoutAddressOpt, - externalChangeAddressOpt) => - RequestParam("acceptdlcoffer", - Seq(up.writeJs(offer), - up.writeJs(peerAddr), - up.writeJs(externalPayoutAddressOpt), - up.writeJs(externalChangeAddressOpt))) + case AcceptDLC( + offer, + peerAddr, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) => + RequestParam( + "acceptdlc", + Seq( + up.writeJs(offer), + up.writeJs(peerAddr), + up.writeJs(externalPayoutAddressOpt), + up.writeJs(externalChangeAddressOpt) + ) + ) + case AcceptDLCOffer( + offer, + peerAddr, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) => + RequestParam( + "acceptdlcoffer", + Seq( + up.writeJs(offer), + up.writeJs(peerAddr), + up.writeJs(externalPayoutAddressOpt), + up.writeJs(externalChangeAddressOpt) + ) + ) case AcceptDLCOfferFromFile(path, dest) => - RequestParam("acceptdlcofferfromfile", - Seq(up.writeJs(path), up.writeJs(dest))) + RequestParam( + "acceptdlcofferfromfile", + Seq(up.writeJs(path), up.writeJs(dest)) + ) case SignDLC(accept) => RequestParam("signdlc", Seq(up.writeJs(accept))) case SignDLCFromFile(path, dest) => @@ -2161,17 +2265,23 @@ object CliCommand { case AddDLCSigsAndBroadcastFromFile(path) => RequestParam("adddlcsigsandbroadcastfromfile", Seq(up.writeJs(path))) case ExecuteDLC(contractId, oracleSigs, noBroadcast) => - RequestParam("executedlc", - Seq(up.writeJs(contractId), - up.writeJs(oracleSigs), - up.writeJs(noBroadcast))) + RequestParam( + "executedlc", + Seq( + up.writeJs(contractId), + up.writeJs(oracleSigs), + up.writeJs(noBroadcast) + ) + ) case GetDLCFundingTx(contractId) => RequestParam("getdlcfundingtx", Seq(up.writeJs(contractId))) case BroadcastDLCFundingTx(contractId) => RequestParam("broadcastdlcfundingtx", Seq(up.writeJs(contractId))) case ExecuteDLCRefund(contractId, noBroadcast) => - RequestParam("executedlcrefund", - Seq(up.writeJs(contractId), up.writeJs(noBroadcast))) + RequestParam( + "executedlcrefund", + Seq(up.writeJs(contractId), up.writeJs(noBroadcast)) + ) case CancelDLC(dlcId) => RequestParam("canceldlc", Seq(up.writeJs(dlcId))) // Wallet @@ -2188,11 +2298,15 @@ object CliCommand { case GetNewAddress(labelOpt) => RequestParam("getnewaddress", Seq(up.writeJs(labelOpt))) case LockUnspent(unlock, outPoints) => - RequestParam("lockunspent", - Seq(up.writeJs(unlock), up.writeJs(outPoints))) + RequestParam( + "lockunspent", + Seq(up.writeJs(unlock), up.writeJs(outPoints)) + ) case LabelAddress(address, label) => - RequestParam("labeladdress", - Seq(up.writeJs(address), up.writeJs(label))) + RequestParam( + "labeladdress", + Seq(up.writeJs(address), up.writeJs(label)) + ) case GetAddressTags(address) => RequestParam("getaddresstags", Seq(up.writeJs(address))) case GetAddressLabel(address) => @@ -2200,94 +2314,144 @@ object CliCommand { case GetAddressLabels => RequestParam("getaddresslabels") case DropAddressLabel(address, label) => - RequestParam("dropaddresslabel", - Seq(up.writeJs(address), ujson.Str(label))) + RequestParam( + "dropaddresslabel", + Seq(up.writeJs(address), ujson.Str(label)) + ) case DropAddressLabels(address) => RequestParam("dropaddresslabels", Seq(up.writeJs(address))) - case Rescan(addressBatchSize, - startBlock, - endBlock, - force, - ignoreCreationTime) => - RequestParam("rescan", - Seq(up.writeJs(addressBatchSize), - up.writeJs(startBlock), - up.writeJs(endBlock), - up.writeJs(force), - up.writeJs(ignoreCreationTime))) + case Rescan( + addressBatchSize, + startBlock, + endBlock, + force, + ignoreCreationTime + ) => + RequestParam( + "rescan", + Seq( + up.writeJs(addressBatchSize), + up.writeJs(startBlock), + up.writeJs(endBlock), + up.writeJs(force), + up.writeJs(ignoreCreationTime) + ) + ) case GetTransaction(txId) => RequestParam("gettransaction", Seq(up.writeJs(txId))) - case SendToAddress(address, - bitcoins, - satoshisPerVirtualByte, - noBroadcast) => - RequestParam("sendtoaddress", - Seq(up.writeJs(address), - up.writeJs(bitcoins), - up.writeJs(satoshisPerVirtualByte), - up.writeJs(noBroadcast))) + case SendToAddress( + address, + bitcoins, + satoshisPerVirtualByte, + noBroadcast + ) => + RequestParam( + "sendtoaddress", + Seq( + up.writeJs(address), + up.writeJs(bitcoins), + up.writeJs(satoshisPerVirtualByte), + up.writeJs(noBroadcast) + ) + ) case SendFromOutPoints(outPoints, address, bitcoins, feeRateOpt) => - RequestParam("sendfromoutpoints", - Seq(up.writeJs(outPoints), - up.writeJs(address), - up.writeJs(bitcoins), - up.writeJs(feeRateOpt))) + RequestParam( + "sendfromoutpoints", + Seq( + up.writeJs(outPoints), + up.writeJs(address), + up.writeJs(bitcoins), + up.writeJs(feeRateOpt) + ) + ) case SweepWallet(address, feeRateOpt) => - RequestParam("sweepwallet", - Seq(up.writeJs(address), up.writeJs(feeRateOpt))) + RequestParam( + "sweepwallet", + Seq(up.writeJs(address), up.writeJs(feeRateOpt)) + ) case SendWithAlgo(address, bitcoins, feeRateOpt, algo) => - RequestParam("sendwithalgo", - Seq(up.writeJs(address), - up.writeJs(bitcoins), - up.writeJs(feeRateOpt), - up.writeJs(algo))) + RequestParam( + "sendwithalgo", + Seq( + up.writeJs(address), + up.writeJs(bitcoins), + up.writeJs(feeRateOpt), + up.writeJs(algo) + ) + ) case BumpFeeCPFP(txId, feeRate) => RequestParam("bumpfeecpfp", Seq(up.writeJs(txId), up.writeJs(feeRate))) case BumpFeeRBF(txId, feeRate) => RequestParam("bumpfeerbf", Seq(up.writeJs(txId), up.writeJs(feeRate))) case OpReturnCommit(message, hashMessage, satoshisPerVirtualByte) => - RequestParam("opreturncommit", - Seq(up.writeJs(message), - up.writeJs(hashMessage), - up.writeJs(satoshisPerVirtualByte))) + RequestParam( + "opreturncommit", + Seq( + up.writeJs(message), + up.writeJs(hashMessage), + up.writeJs(satoshisPerVirtualByte) + ) + ) case SignPSBT(psbt) => RequestParam("signpsbt", Seq(up.writeJs(psbt))) case KeyManagerPassphraseChange(oldPassword, newPassword) => - RequestParam("keymanagerpassphrasechange", - Seq(up.writeJs(oldPassword), up.writeJs(newPassword))) + RequestParam( + "keymanagerpassphrasechange", + Seq(up.writeJs(oldPassword), up.writeJs(newPassword)) + ) case KeyManagerPassphraseSet(password) => RequestParam("keymanagerpassphraseset", Seq(up.writeJs(password))) case ImportSeed(walletNameOpt, mnemonic, passwordOpt) => - RequestParam("importseed", - Seq(walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), - up.writeJs(mnemonic), - passwordOpt.map(p => up.writeJs(p)).getOrElse(Null))) + RequestParam( + "importseed", + Seq( + walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), + up.writeJs(mnemonic), + passwordOpt.map(p => up.writeJs(p)).getOrElse(Null) + ) + ) case ExportSeed(walletNameOpt, passwordOpt) => - RequestParam("exportseed", - Seq(walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), - passwordOpt.map(p => up.writeJs(p)).getOrElse(Null))) + RequestParam( + "exportseed", + Seq( + walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), + passwordOpt.map(p => up.writeJs(p)).getOrElse(Null) + ) + ) case MarkSeedAsBackedUp(walletNameOpt, passwordOpt) => - RequestParam("markseedasbackedup", - Seq(walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), - passwordOpt.map(p => up.writeJs(p)).getOrElse(Null))) + RequestParam( + "markseedasbackedup", + Seq( + walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), + passwordOpt.map(p => up.writeJs(p)).getOrElse(Null) + ) + ) case GetSeedBackupTime(walletNameOpt, passwordOpt) => - RequestParam("getseedbackuptime", - Seq(walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), - passwordOpt.map(p => up.writeJs(p)).getOrElse(Null))) + RequestParam( + "getseedbackuptime", + Seq( + walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), + passwordOpt.map(p => up.writeJs(p)).getOrElse(Null) + ) + ) case ImportXprv(walletNameOpt, xprv, passwordOpt) => - RequestParam("importxprv", - Seq(walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), - up.writeJs(xprv), - passwordOpt.map(p => up.writeJs(p)).getOrElse(Null))) + RequestParam( + "importxprv", + Seq( + walletNameOpt.map(w => up.writeJs(w)).getOrElse(Null), + up.writeJs(xprv), + passwordOpt.map(p => up.writeJs(p)).getOrElse(Null) + ) + ) case LoadWallet(walletNameOpt, passwordOpt, bip39PasswordOpt) => RequestParam( @@ -2352,42 +2516,53 @@ object CliCommand { case CreateEnumAnnouncement(label, time, outcomes) => RequestParam( "createenumannouncement", - Seq(up.writeJs(label), up.writeJs(time), up.writeJs(outcomes))) - case CreateNumericAnnouncement(eventName, - time, - minValue, - maxValue, - unit, - precision) => + Seq(up.writeJs(label), up.writeJs(time), up.writeJs(outcomes)) + ) + case CreateNumericAnnouncement( + eventName, + time, + minValue, + maxValue, + unit, + precision + ) => RequestParam( "createnumericannouncement", - Seq(up.writeJs(eventName), - up.writeJs(time), - up.writeJs(minValue), - up.writeJs(maxValue), - up.writeJs(unit), - up.writeJs(precision)) + Seq( + up.writeJs(eventName), + up.writeJs(time), + up.writeJs(minValue), + up.writeJs(maxValue), + up.writeJs(unit), + up.writeJs(precision) + ) ) - case CreateDigitDecompAnnouncement(eventName, - time, - base, - isSigned, - numDigits, - unit, - precision) => + case CreateDigitDecompAnnouncement( + eventName, + time, + base, + isSigned, + numDigits, + unit, + precision + ) => RequestParam( "createdigitdecompannouncement", - Seq(up.writeJs(eventName), - up.writeJs(time), - up.writeJs(base), - up.writeJs(isSigned), - up.writeJs(numDigits), - up.writeJs(unit), - up.writeJs(precision)) + Seq( + up.writeJs(eventName), + up.writeJs(time), + up.writeJs(base), + up.writeJs(isSigned), + up.writeJs(numDigits), + up.writeJs(unit), + up.writeJs(precision) + ) ) case SignEnum(eventName, outcome) => - RequestParam("signenum", - Seq(up.writeJs(eventName), up.writeJs(outcome))) + RequestParam( + "signenum", + Seq(up.writeJs(eventName), up.writeJs(outcome)) + ) case SignDigits(eventName, num) => RequestParam("signdigits", Seq(up.writeJs(eventName), up.writeJs(num))) case GetSignatures(eventName) => @@ -2404,10 +2579,14 @@ object CliCommand { RequestParam("backuporacle", Seq(up.writeJs(dest))) case CreateMultisig(requiredKeys, keys, addressType) => - RequestParam("createmultisig", - Seq(up.writeJs(requiredKeys), - up.writeJs(keys), - up.writeJs(addressType))) + RequestParam( + "createmultisig", + Seq( + up.writeJs(requiredKeys), + up.writeJs(keys), + up.writeJs(addressType) + ) + ) case EstimateFee => RequestParam("estimatefee") case ZipDataDir(path) => RequestParam("zipdatadir", Seq(up.writeJs(path))) @@ -2417,9 +2596,11 @@ object CliCommand { case GetVersion => RequestParam("getversion", Seq.empty) case CreateContractInfo(ann, totalCollateral, contractDescriptor) => - val args = Seq(up.writeJs(ann), - up.writeJs(totalCollateral), - up.writeJs(contractDescriptor)) + val args = Seq( + up.writeJs(ann), + up.writeJs(totalCollateral), + up.writeJs(contractDescriptor) + ) RequestParam("createcontractinfo", args) case AddDLCOffer(offer, peer, message) => @@ -2472,8 +2653,8 @@ object CliCommand { case class AddDLCOffer( offer: LnMessage[DLCOfferTLV], peer: String, - message: String) - extends AppServerCliCommand + message: String + ) extends AppServerCliCommand case class RemoveDLCOffer(offerHash: Sha256Digest) extends AppServerCliCommand @@ -2528,8 +2709,8 @@ object CliCommand { case class CreateEnumAnnouncement( label: String, maturationTime: Date, - outcomes: Seq[String]) - extends OracleServerCliCommand + outcomes: Seq[String] + ) extends OracleServerCliCommand case class CreateNumericAnnouncement( eventName: String, @@ -2537,8 +2718,8 @@ object CliCommand { minValue: Long, maxValue: Long, unit: String, - precision: Int) - extends OracleServerCliCommand + precision: Int + ) extends OracleServerCliCommand case class CreateDigitDecompAnnouncement( eventName: String, @@ -2547,8 +2728,8 @@ object CliCommand { isSigned: Boolean, numDigits: Int, unit: String, - precision: Int) - extends OracleServerCliCommand + precision: Int + ) extends OracleServerCliCommand case class SignEnum(eventName: String, outcome: String) extends OracleServerCliCommand diff --git a/app/oracle-server-test/src/test/scala/org/bitcoins/oracle/server/OracleRoutesSpec.scala b/app/oracle-server-test/src/test/scala/org/bitcoins/oracle/server/OracleRoutesSpec.scala index ad01885073..695771e1c7 100644 --- a/app/oracle-server-test/src/test/scala/org/bitcoins/oracle/server/OracleRoutesSpec.scala +++ b/app/oracle-server-test/src/test/scala/org/bitcoins/oracle/server/OracleRoutesSpec.scala @@ -74,7 +74,8 @@ class OracleRoutesSpec Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":"${key.hex}","error":null}""") + responseAs[String] == s"""{"result":"${key.hex}","error":null}""" + ) } } @@ -90,7 +91,8 @@ class OracleRoutesSpec Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":"$testAddress","error":null}""") + responseAs[String] == s"""{"result":"$testAddress","error":null}""" + ) } } @@ -105,7 +107,10 @@ class OracleRoutesSpec Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":["${dummyOracleEvent.eventName}"],"error":null}""") + responseAs[ + String + ] == s"""{"result":["${dummyOracleEvent.eventName}"],"error":null}""" + ) } } @@ -117,7 +122,8 @@ class OracleRoutesSpec .returning(Future.successful(Some(dummyOracleEvent))) val route = oracleRoutes.handleCommand( - ServerCommand("getannouncement", Arr(eventName))) + ServerCommand("getannouncement", Arr(eventName)) + ) val expected = s""" @@ -141,7 +147,7 @@ class OracleRoutesSpec | "error":null |} |""".stripMargin - .replaceAll("\\s", "") //strip whitespace + .replaceAll("\\s", "") // strip whitespace val expectedJson: ujson.Value = ujson.read(Readable.fromString(expected)) Post() ~> route ~> check { @@ -160,15 +166,19 @@ class OracleRoutesSpec val route = oracleRoutes.handleCommand( - ServerCommand("createenumannouncement", - Arr(Str("id"), - Str("2021-02-04T00:00:00Z"), - Arr(Str("1"), Str("2"))))) + ServerCommand( + "createenumannouncement", + Arr(Str("id"), Str("2021-02-04T00:00:00Z"), Arr(Str("1"), Str("2"))) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""" + ) } } @@ -182,118 +192,159 @@ class OracleRoutesSpec oracleRoutes.handleCommand( ServerCommand( "createenumannouncement", - Arr(Str("id"), Str("2021-02-04"), Arr(Str("1"), Str("2"))))) + Arr(Str("id"), Str("2021-02-04"), Arr(Str("1"), Str("2"))) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""" + ) } } "create numeric announcement" in { (mockOracleApi - .createNewDigitDecompAnnouncement(_: String, - _: Instant, - _: UInt16, - _: Boolean, - _: Int, - _: String, - _: Int32)) - .expects("id", - Instant.ofEpochSecond(1612396800), - UInt16(2), - false, - 17, - "units", - Int32.zero) + .createNewDigitDecompAnnouncement( + _: String, + _: Instant, + _: UInt16, + _: Boolean, + _: Int, + _: String, + _: Int32 + )) + .expects( + "id", + Instant.ofEpochSecond(1612396800), + UInt16(2), + false, + 17, + "units", + Int32.zero + ) .returning(Future.successful(OracleAnnouncementV0TLV.dummy)) val route = oracleRoutes.handleCommand( - ServerCommand("createnumericannouncement", - Arr(Str("id"), - Str("2021-02-04T00:00:00Z"), - Num(0), - Num(131000), - Str("units"), - Num(0)))) + ServerCommand( + "createnumericannouncement", + Arr( + Str("id"), + Str("2021-02-04T00:00:00Z"), + Num(0), + Num(131000), + Str("units"), + Num(0) + ) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""" + ) } } "create numeric announcement with just date" in { (mockOracleApi - .createNewDigitDecompAnnouncement(_: String, - _: Instant, - _: UInt16, - _: Boolean, - _: Int, - _: String, - _: Int32)) - .expects("id", - Instant.ofEpochSecond(1612396800), - UInt16(2), - true, - 17, - "units", - Int32.zero) + .createNewDigitDecompAnnouncement( + _: String, + _: Instant, + _: UInt16, + _: Boolean, + _: Int, + _: String, + _: Int32 + )) + .expects( + "id", + Instant.ofEpochSecond(1612396800), + UInt16(2), + true, + 17, + "units", + Int32.zero + ) .returning(Future.successful(OracleAnnouncementV0TLV.dummy)) val route = oracleRoutes.handleCommand( - ServerCommand("createnumericannouncement", - Arr(Str("id"), - Str("2021-02-04"), - Num(-1), - Num(131000), - Str("units"), - Num(0)))) + ServerCommand( + "createnumericannouncement", + Arr( + Str("id"), + Str("2021-02-04"), + Num(-1), + Num(131000), + Str("units"), + Num(0) + ) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""" + ) } } "create digit decomp announcement" in { (mockOracleApi - .createNewDigitDecompAnnouncement(_: String, - _: Instant, - _: UInt16, - _: Boolean, - _: Int, - _: String, - _: Int32)) - .expects("id", - Instant.ofEpochSecond(1612396800), - UInt16(2), - true, - 17, - "units", - Int32.zero) + .createNewDigitDecompAnnouncement( + _: String, + _: Instant, + _: UInt16, + _: Boolean, + _: Int, + _: String, + _: Int32 + )) + .expects( + "id", + Instant.ofEpochSecond(1612396800), + UInt16(2), + true, + 17, + "units", + Int32.zero + ) .returning(Future.successful(OracleAnnouncementV0TLV.dummy)) val route = oracleRoutes.handleCommand( - ServerCommand("createdigitdecompannouncement", - Arr(Str("id"), - Num(1612396800), - Num(2), - Bool(true), - Num(17), - Str("units"), - Num(0)))) + ServerCommand( + "createdigitdecompannouncement", + Arr( + Str("id"), + Num(1612396800), + Num(2), + Bool(true), + Num(17), + Str("units"), + Num(0) + ) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${OracleAnnouncementV0TLV.dummy.hex}","error":null}""" + ) } } @@ -305,12 +356,16 @@ class OracleRoutesSpec val route = oracleRoutes.handleCommand( - ServerCommand("signenum", Arr(Str("id"), Str("outcome")))) + ServerCommand("signenum", Arr(Str("id"), Str("outcome"))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""" + ) } } @@ -322,12 +377,16 @@ class OracleRoutesSpec val route = oracleRoutes.handleCommand( - ServerCommand("signdigits", Arr(Str("id"), Num(123)))) + ServerCommand("signdigits", Arr(Str("id"), Num(123))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""" + ) } } @@ -339,12 +398,16 @@ class OracleRoutesSpec val route = oracleRoutes.handleCommand( - ServerCommand("getsignatures", Arr(Str("id")))) + ServerCommand("getsignatures", Arr(Str("id"))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""" + ) } } @@ -356,12 +419,14 @@ class OracleRoutesSpec val route = oracleRoutes.handleCommand( - ServerCommand("signmessage", Arr(Str("message")))) + ServerCommand("signmessage", Arr(Str("message"))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":"${sig.hex}","error":null}""") + responseAs[String] == s"""{"result":"${sig.hex}","error":null}""" + ) } } @@ -376,8 +441,11 @@ class OracleRoutesSpec val route = oracleRoutes.handleCommand(cmd) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${dummyOracleEvent.announcementTLV.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${dummyOracleEvent.announcementTLV.hex}","error":null}""" + ) } } @@ -393,8 +461,11 @@ class OracleRoutesSpec Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"${dummyOracleEvent.announcementTLV.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${dummyOracleEvent.announcementTLV.hex}","error":null}""" + ) } } @@ -409,7 +480,8 @@ class OracleRoutesSpec Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":"oracle name","error":null}""") + responseAs[String] == s"""{"result":"oracle name","error":null}""" + ) } } @@ -421,12 +493,14 @@ class OracleRoutesSpec val route = oracleRoutes.handleCommand( - ServerCommand("setoraclename", Arr(Str("oracle name")))) + ServerCommand("setoraclename", Arr(Str("oracle name"))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":"oracle name","error":null}""") + responseAs[String] == s"""{"result":"oracle name","error":null}""" + ) } } } diff --git a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleRoutes.scala b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleRoutes.scala index de7fbf4058..d19f5ca4b9 100644 --- a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleRoutes.scala +++ b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleRoutes.scala @@ -19,8 +19,8 @@ import scala.util.{Failure, Success} case class OracleRoutes(oracle: DLCOracleApi)(implicit system: ActorSystem, - conf: DLCOracleAppConfig) - extends ServerRoute { + conf: DLCOracleAppConfig +) extends ServerRoute { import system.dispatcher override def handleCommand: PartialFunction[ServerCommand, StandardRoute] = { @@ -71,12 +71,15 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit case Failure(exception) => reject(ValidationRejection("failure", Some(exception))) case Success( - CreateNumericAnnouncement(eventName, - maturationTime, - minValue, - maxValue, - unit, - precision)) => + CreateNumericAnnouncement( + eventName, + maturationTime, + minValue, + maxValue, + unit, + precision + ) + ) => complete { val isSigned = minValue < 0 @@ -84,13 +87,15 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit Math.ceil(Math.log(maxValue.toDouble) / Math.log(2)).toInt oracle - .createNewDigitDecompAnnouncement(eventName, - maturationTime, - UInt16(2), - isSigned, - numDigits, - unit, - Int32(precision)) + .createNewDigitDecompAnnouncement( + eventName, + maturationTime, + UInt16(2), + isSigned, + numDigits, + unit, + Int32(precision) + ) .map { announcementTLV => Server.httpSuccess(announcementTLV.hex) } @@ -105,22 +110,27 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit case Failure(exception) => reject(ValidationRejection("failure", Some(exception))) case Success( - CreateDigitDecompAnnouncement(eventName, - maturationTime, - base, - isSigned, - numDigits, - unit, - precision)) => + CreateDigitDecompAnnouncement( + eventName, + maturationTime, + base, + isSigned, + numDigits, + unit, + precision + ) + ) => complete { oracle - .createNewDigitDecompAnnouncement(eventName, - maturationTime, - UInt16(base), - isSigned, - numDigits, - unit, - Int32(precision)) + .createNewDigitDecompAnnouncement( + eventName, + maturationTime, + UInt16(base), + isSigned, + numDigits, + unit, + Int32(precision) + ) .map { announcementTLV => Server.httpSuccess(announcementTLV.hex) } @@ -179,9 +189,11 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit "signingVersion" -> Str(event.signingVersion.toString), "maturationTime" -> Str(event.maturationTime.toString), "maturationTimeEpoch" -> Num( - event.maturationTime.getEpochSecond.toDouble), + event.maturationTime.getEpochSecond.toDouble + ), "announcementSignature" -> Str( - event.announcementSignature.hex), + event.announcementSignature.hex + ), "eventDescriptorTLV" -> Str(event.eventDescriptorTLV.hex), "eventTLV" -> Str(event.eventTLV.hex), "announcementTLV" -> Str(event.announcementTLV.hex), @@ -269,9 +281,11 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit case Success(KeyManagerPassphraseChange(oldPassword, newPassword)) => complete { val path = conf.seedPath - WalletStorage.changeAesPassword(path, - Some(oldPassword), - Some(newPassword)) + WalletStorage.changeAesPassword( + path, + Some(oldPassword), + Some(newPassword) + ) Server.httpSuccess(ujson.Null) } diff --git a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleServerMain.scala b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleServerMain.scala index 8e1fb3df52..84786f64ef 100644 --- a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleServerMain.scala +++ b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/OracleServerMain.scala @@ -13,8 +13,8 @@ import scala.concurrent.{Await, Future} class OracleServerMain(override val serverArgParser: ServerArgParser)(implicit override val system: ActorSystem, - conf: DLCOracleAppConfig) - extends BitcoinSServerRunner[Unit] { + conf: DLCOracleAppConfig +) extends BitcoinSServerRunner[Unit] { override def start(): Future[Unit] = { @@ -31,21 +31,25 @@ class OracleServerMain(override val serverArgParser: ServerArgParser)(implicit routes = Seq(OracleRoutes(oracle), commonRoutes).map(Future.successful) server = serverArgParser.rpcPortOpt match { case Some(rpcport) => - Server(conf = conf, - handlersF = routes, - rpcbindOpt = bindConfOpt, - rpcport = rpcport, - rpcPassword = conf.rpcPassword, - None, - Source.empty) + Server( + conf = conf, + handlersF = routes, + rpcbindOpt = bindConfOpt, + rpcport = rpcport, + rpcPassword = conf.rpcPassword, + None, + Source.empty + ) case None => - Server(conf = conf, - handlersF = routes, - rpcbindOpt = bindConfOpt, - rpcport = conf.rpcPort, - rpcPassword = conf.rpcPassword, - None, - Source.empty) + Server( + conf = conf, + handlersF = routes, + rpcbindOpt = bindConfOpt, + rpcport = conf.rpcPort, + rpcPassword = conf.rpcPassword, + None, + Source.empty + ) } bindings <- server.start() @@ -88,14 +92,16 @@ object OracleServerMain extends BitcoinSAppScalaDaemon { implicit lazy val conf: DLCOracleAppConfig = DLCOracleAppConfig(datadirParser.datadir, Vector(datadirParser.baseConfig))( - system.dispatcher) + system.dispatcher + ) val m = new OracleServerMain(serverCmdLineArgs) m.run() sys.addShutdownHook { logger.info( - s"@@@@@@@@@@@@@@@@@@@@@ Shutting down ${getClass.getSimpleName} @@@@@@@@@@@@@@@@@@@@@") + s"@@@@@@@@@@@@@@@@@@@@@ Shutting down ${getClass.getSimpleName} @@@@@@@@@@@@@@@@@@@@@" + ) Await.result(m.stop(), 10.seconds) } } diff --git a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/ServerJsonModels.scala b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/ServerJsonModels.scala index 6bcf258c26..c7c5073508 100644 --- a/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/ServerJsonModels.scala +++ b/app/oracle-server/src/main/scala/org/bitcoins/oracle/server/ServerJsonModels.scala @@ -30,7 +30,9 @@ object SignMessage extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -38,7 +40,8 @@ object SignMessage extends ServerJsonModels { case class CreateAnnouncement( label: String, maturationTime: Instant, - outcomes: Vector[String]) + outcomes: Vector[String] +) object CreateAnnouncement extends ServerJsonModels { @@ -54,11 +57,14 @@ object CreateAnnouncement extends ServerJsonModels { } case Nil => Failure( - new IllegalArgumentException("Missing label and outcome arguments")) + new IllegalArgumentException("Missing label and outcome arguments") + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -69,7 +75,8 @@ case class CreateNumericAnnouncement( minValue: Long, maxValue: Long, unit: String, - precision: Int) + precision: Int +) object CreateNumericAnnouncement extends ServerJsonModels { @@ -84,20 +91,27 @@ object CreateNumericAnnouncement extends ServerJsonModels { val unit = unitJs.str val precision = precisionJs.num.toInt - CreateNumericAnnouncement(label, - maturationTime, - minValue, - maxValue, - unit, - precision) + CreateNumericAnnouncement( + label, + maturationTime, + minValue, + maxValue, + unit, + precision + ) } case Nil => - Failure(new IllegalArgumentException( - "Missing label, maturationTime, minValue, maxValue, units, and precision arguments")) + Failure( + new IllegalArgumentException( + "Missing label, maturationTime, minValue, maxValue, units, and precision arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 6")) + s"Bad number of arguments: ${other.length}. Expected: 6" + ) + ) } } } @@ -109,7 +123,8 @@ case class CreateDigitDecompAnnouncement( isSigned: Boolean, numDigits: Int, unit: String, - precision: Int) + precision: Int +) object CreateDigitDecompAnnouncement extends ServerJsonModels { @@ -126,21 +141,28 @@ object CreateDigitDecompAnnouncement extends ServerJsonModels { val unit = unitJs.str val precision = precisionJs.num.toInt - CreateDigitDecompAnnouncement(label, - maturationTime, - base, - isSigned, - numDigits, - unit, - precision) + CreateDigitDecompAnnouncement( + label, + maturationTime, + base, + isSigned, + numDigits, + unit, + precision + ) } case Nil => - Failure(new IllegalArgumentException( - "Missing label, maturationTime, base, isSigned, numDigits, units, and precision arguments")) + Failure( + new IllegalArgumentException( + "Missing label, maturationTime, base, isSigned, numDigits, units, and precision arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 7")) + s"Bad number of arguments: ${other.length}. Expected: 7" + ) + ) } } } @@ -160,11 +182,15 @@ object SignEnum extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing oracle event tlv and outcome arguments")) + "Missing oracle event tlv and outcome arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -182,7 +208,8 @@ object SignDigits extends ServerJsonModels { case str: Str => str.value.toDouble case _: Value => throw new IllegalArgumentException( - s"Unable to parse $numJs as a number") + s"Unable to parse $numJs as a number" + ) } SignDigits(nameJs.str, num.toLong) @@ -190,11 +217,15 @@ object SignDigits extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing oracle event tlv and num arguments")) + "Missing oracle event tlv and num arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -204,8 +235,10 @@ case class GetAnnouncement(eventName: String) object GetAnnouncement extends ServerJsonModels { def fromJsArr(jsArr: ujson.Arr): Try[GetAnnouncement] = { - require(jsArr.arr.size == 1, - s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1") + require( + jsArr.arr.size == 1, + s"Bad number of arguments: ${jsArr.arr.size}. Expected: 1" + ) Try { GetAnnouncement(jsArr.arr.head.str) } @@ -214,7 +247,8 @@ object GetAnnouncement extends ServerJsonModels { case class KeyManagerPassphraseChange( oldPassword: AesPassword, - newPassword: AesPassword) + newPassword: AesPassword +) object KeyManagerPassphraseChange extends ServerJsonModels { @@ -230,11 +264,15 @@ object KeyManagerPassphraseChange extends ServerJsonModels { case Nil => Failure( new IllegalArgumentException( - "Missing old password and new password arguments")) + "Missing old password and new password arguments" + ) + ) case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 2")) + s"Bad number of arguments: ${other.length}. Expected: 2" + ) + ) } } } @@ -256,7 +294,9 @@ object KeyManagerPassphraseSet extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -276,8 +316,11 @@ object DeleteAnnouncement case Vector() => Failure(new IllegalArgumentException(s"Missing event name argument")) case other => - Failure(new IllegalArgumentException( - s"Bad number of arguments to deleteannouncement, got=${other.length} expected: 1")) + Failure( + new IllegalArgumentException( + s"Bad number of arguments to deleteannouncement, got=${other.length} expected: 1" + ) + ) } } @@ -303,7 +346,9 @@ object DeleteAttestation case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } @@ -341,7 +386,8 @@ trait ServerJsonModels { LockUnspentOutputParameter.fromJson(js) def jsToLockUnspentOutputParameters( - js: Value): Seq[LockUnspentOutputParameter] = { + js: Value + ): Seq[LockUnspentOutputParameter] = { js.arr.foldLeft(Seq.empty[LockUnspentOutputParameter])((seq, outPoint) => seq :+ jsToLockUnspentOutputParameter(outPoint)) } diff --git a/app/scripts/src/main/scala/org/bitcoins/scripts/ScanBitcoind.scala b/app/scripts/src/main/scala/org/bitcoins/scripts/ScanBitcoind.scala index 35a35d6d96..a14c590042 100644 --- a/app/scripts/src/main/scala/org/bitcoins/scripts/ScanBitcoind.scala +++ b/app/scripts/src/main/scala/org/bitcoins/scripts/ScanBitcoind.scala @@ -16,15 +16,16 @@ import org.bitcoins.server.util.BitcoinSAppScalaDaemon import java.time.Instant import scala.concurrent.Future -/** Useful script for scanning bitcoind - * This file assumes you have pre-configured the connection - * between bitcoin-s and bitcoind inside of bitcoin-s.conf - * @see https://bitcoin-s.org/docs/config/configuration#example-configuration-file +/** Useful script for scanning bitcoind This file assumes you have + * pre-configured the connection between bitcoin-s and bitcoind inside of + * bitcoin-s.conf + * @see + * https://bitcoin-s.org/docs/config/configuration#example-configuration-file */ class ScanBitcoind()(implicit override val system: ActorSystem, - rpcAppConfig: BitcoindRpcAppConfig) - extends BitcoinSRunner[Unit] { + rpcAppConfig: BitcoindRpcAppConfig +) extends BitcoinSRunner[Unit] { override def start(): Future[Unit] = { @@ -36,7 +37,7 @@ class ScanBitcoind()(implicit val f = for { bitcoind <- bitcoindF endHeight <- endHeightF - //_ <- countWitV1MempoolTxs(bitcoind) + // _ <- countWitV1MempoolTxs(bitcoind) _ <- countTaprootTxsInBlocks(endHeight, 50000, bitcoind) } yield () f.failed.foreach(err => @@ -50,13 +51,15 @@ class ScanBitcoind()(implicit .map(_ => ()) } - /** Searches a given Source[Int] that represents block heights applying f to them and returning a Seq[T] with the results */ + /** Searches a given Source[Int] that represents block heights applying f to + * them and returning a Seq[T] with the results + */ def searchBlocks[T]( bitcoind: BitcoindRpcClient, source: Source[Int, NotUsed], f: Block => T, - numParallelism: Int = Runtime.getRuntime.availableProcessors()): Future[ - Seq[T]] = { + numParallelism: Int = Runtime.getRuntime.availableProcessors() + ): Future[Seq[T]] = { source .mapAsync(parallelism = numParallelism) { height => bitcoind @@ -66,7 +69,8 @@ class ScanBitcoind()(implicit } .mapAsync(numParallelism) { case (block, height) => logger.info( - s"Searching block at height=$height hashBE=${block.blockHeader.hashBE.hex}") + s"Searching block at height=$height hashBE=${block.blockHeader.hashBE.hex}" + ) FutureUtil.makeAsync { () => f(block) } @@ -78,11 +82,12 @@ class ScanBitcoind()(implicit def countSegwitTxs( bitcoind: BitcoindRpcClient, startHeight: Int, - endHeight: Int): Future[Unit] = { + endHeight: Int + ): Future[Unit] = { val startTime = System.currentTimeMillis() val source: Source[Int, NotUsed] = Source(startHeight.to(endHeight)) - //in this simple example, we are going to count the number of witness transactions + // in this simple example, we are going to count the number of witness transactions val countSegwitTxs: Block => Int = { block: Block => block.transactions.count(_.isInstanceOf[WitnessTransaction]) } @@ -96,14 +101,16 @@ class ScanBitcoind()(implicit count <- countF endTime = System.currentTimeMillis() _ = logger.info( - s"Count of segwit txs from height=${startHeight} to endHeight=${endHeight} is ${count}. It took ${endTime - startTime}ms ") + s"Count of segwit txs from height=${startHeight} to endHeight=${endHeight} is ${count}. It took ${endTime - startTime}ms " + ) } yield () } def countTaprootTxsInBlocks( endHeight: Int, lastBlocks: Int, - bitcoind: BitcoindRpcClient): Future[Int] = { + bitcoind: BitcoindRpcClient + ): Future[Int] = { val startTime = System.currentTimeMillis() val startHeight = endHeight - lastBlocks val source: Source[Int, NotUsed] = Source(startHeight.to(endHeight)) @@ -124,7 +131,8 @@ class ScanBitcoind()(implicit count <- countF endTime = System.currentTimeMillis() _ = logger.info( - s"Count of taproot outputs from height=${startHeight} to endHeight=${endHeight} is ${count}. It took ${endTime - startTime}ms ") + s"Count of taproot outputs from height=${startHeight} to endHeight=${endHeight} is ${count}. It took ${endTime - startTime}ms " + ) } yield count } @@ -135,12 +143,14 @@ class ScanBitcoind()(implicit }) countF.foreach(c => logger.info( - s"Found $c mempool transactions with witness v1 outputs at ${Instant.now}")) + s"Found $c mempool transactions with witness v1 outputs at ${Instant.now}" + )) countF } def getMemPoolSource( - bitcoind: BitcoindRpcClient): Future[Source[Transaction, NotUsed]] = { + bitcoind: BitcoindRpcClient + ): Future[Source[Transaction, NotUsed]] = { val mempoolF = bitcoind.getRawMemPool val sourceF: Future[Source[DoubleSha256DigestBE, NotUsed]] = mempoolF.map(Source(_)) diff --git a/app/scripts/src/main/scala/org/bitcoins/scripts/ZipDatadir.scala b/app/scripts/src/main/scala/org/bitcoins/scripts/ZipDatadir.scala index 605a76a60e..332fdf8135 100644 --- a/app/scripts/src/main/scala/org/bitcoins/scripts/ZipDatadir.scala +++ b/app/scripts/src/main/scala/org/bitcoins/scripts/ZipDatadir.scala @@ -10,15 +10,17 @@ import org.bitcoins.server.util.BitcoinSAppScalaDaemon import java.nio.file.Paths import scala.concurrent.Future -/** This script zips your $HOME/.bitcoin-s/ directory to a specified path, excluding chaindb.sqlite */ +/** This script zips your $HOME/.bitcoin-s/ directory to a specified path, + * excluding chaindb.sqlite + */ class ZipDatadir(override val serverArgParser: ServerArgParser)(implicit override val system: ActorSystem, - conf: BitcoinSAppConfig) - extends BitcoinSServerRunner[Unit] { + conf: BitcoinSAppConfig +) extends BitcoinSServerRunner[Unit] { override def start(): Future[Unit] = { - //replace the line below with where you want to zip too + // replace the line below with where you want to zip too val path = Paths.get("/tmp", "bitcoin-s.zip") val target = DatadirUtil.zipDatadir(conf.baseDatadir, path) logger.info(s"Done zipping to $target!") @@ -46,7 +48,8 @@ object Zip extends BitcoinSAppScalaDaemon { implicit lazy val conf: BitcoinSAppConfig = BitcoinSAppConfig(datadirParser.datadir, Vector(datadirParser.baseConfig))( - system) + system + ) new ZipDatadir(serverCmdLineArgs).run() } diff --git a/app/server-routes/src/main/scala/de/heikoseeberger/akkahttpupickle/UpickleSupport.scala b/app/server-routes/src/main/scala/de/heikoseeberger/akkahttpupickle/UpickleSupport.scala index c94841e5a9..bc74f228c9 100644 --- a/app/server-routes/src/main/scala/de/heikoseeberger/akkahttpupickle/UpickleSupport.scala +++ b/app/server-routes/src/main/scala/de/heikoseeberger/akkahttpupickle/UpickleSupport.scala @@ -31,11 +31,13 @@ import upickle.default.{read, write, Reader, Writer} import scala.collection.immutable.Seq -/** Automatic to and from JSON marshalling/unmarshalling using *upickle* protocol. +/** Automatic to and from JSON marshalling/unmarshalling using *upickle* + * protocol. */ object UpickleSupport extends UpickleSupport -/** Automatic to and from JSON marshalling/unmarshalling using *upickle* protocol. +/** Automatic to and from JSON marshalling/unmarshalling using *upickle* + * protocol. */ trait UpickleSupport { @@ -58,16 +60,20 @@ trait UpickleSupport { /** HTTP entity => `A` * - * @tparam A type to decode - * @return unmarshaller for `A` + * @tparam A + * type to decode + * @return + * unmarshaller for `A` */ implicit def unmarshaller[A: Reader]: FromEntityUnmarshaller[A] = jsonStringUnmarshaller.map(read(_)) /** `A` => HTTP entity * - * @tparam A type to encode - * @return marshaller for any `A` value + * @tparam A + * type to encode + * @return + * marshaller for any `A` value */ implicit def marshaller[A: Writer]: ToEntityMarshaller[A] = jsonStringMarshaller.compose(write(_)) diff --git a/app/server-routes/src/main/scala/org/bitcoins/server/routes/BitcoinSRunner.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/BitcoinSRunner.scala index cbdb25bdcf..ec3be796a0 100644 --- a/app/server-routes/src/main/scala/org/bitcoins/server/routes/BitcoinSRunner.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/BitcoinSRunner.scala @@ -15,16 +15,17 @@ trait BitcoinSRunner[T] extends StartStopAsync[T] with BitcoinSLogger { // start everything! final def run(): Future[T] = { - //We need to set the system property before any logger instances - //are in instantiated. If we don't do this, we will not log to - //the correct location - //see: https://github.com/bitcoin-s/bitcoin-s/issues/2496 - //System.setProperty("bitcoins.log.location", usedDir.toAbsolutePath.toString) + // We need to set the system property before any logger instances + // are in instantiated. If we don't do this, we will not log to + // the correct location + // see: https://github.com/bitcoin-s/bitcoin-s/issues/2496 + // System.setProperty("bitcoins.log.location", usedDir.toAbsolutePath.toString) logger.info( - s"version=${EnvUtil.getVersion} jdkVersion=${EnvUtil.getJdkVersion}") + s"version=${EnvUtil.getVersion} jdkVersion=${EnvUtil.getJdkVersion}" + ) - //logger.info(s"using directory ${usedDir.toAbsolutePath.toString}") + // logger.info(s"using directory ${usedDir.toAbsolutePath.toString}") val runner: Future[T] = start() runner.failed.foreach { err => logger.error(s"Failed to startup server!", err) diff --git a/app/server-routes/src/main/scala/org/bitcoins/server/routes/CORSHandler.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/CORSHandler.scala index 7562f5752a..f7a364e212 100644 --- a/app/server-routes/src/main/scala/org/bitcoins/server/routes/CORSHandler.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/CORSHandler.scala @@ -8,28 +8,33 @@ import org.apache.pekko.http.scaladsl.server.Directives._ import org.apache.pekko.http.scaladsl.server.Route /** Add CORS handling for accessing backend over localhost from modern browsers - * @see dzone.com/articles/handling-cors-in-akka-http + * @see + * dzone.com/articles/handling-cors-in-akka-http */ trait CORSHandler { private val corsResponseHeaders = List( `Access-Control-Allow-Origin`.*, `Access-Control-Allow-Credentials`(true), - `Access-Control-Allow-Headers`("Authorization", - "Content-Type", - "X-Requested-With") + `Access-Control-Allow-Headers`( + "Authorization", + "Content-Type", + "X-Requested-With" + ) ) - //this directive adds access control headers to normal responses + // this directive adds access control headers to normal responses private def addAccessControlHeaders: Directive0 = { respondWithHeaders(corsResponseHeaders) } - //this handles preflight OPTIONS requests. + // this handles preflight OPTIONS requests. private def preflightRequestHandler: Route = options { complete( HttpResponse(StatusCodes.OK).withHeaders( - `Access-Control-Allow-Methods`(OPTIONS, POST, PUT, GET, DELETE))) + `Access-Control-Allow-Methods`(OPTIONS, POST, PUT, GET, DELETE) + ) + ) } // Wrap the Route with this method to enable adding of CORS headers diff --git a/app/server-routes/src/main/scala/org/bitcoins/server/routes/CommonRoutes.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/CommonRoutes.scala index 463df0443b..9ad6f28ec2 100644 --- a/app/server-routes/src/main/scala/org/bitcoins/server/routes/CommonRoutes.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/CommonRoutes.scala @@ -51,7 +51,9 @@ object ZipDataDir { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } diff --git a/app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpError.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpError.scala index 3e33f1bfc9..cfc3489e92 100644 --- a/app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpError.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/HttpError.scala @@ -1,8 +1,7 @@ package org.bitcoins.server.routes -/** HTTP errors our server knows how to handle. - * These gets picked up by the exceptions handler - * in Main +/** HTTP errors our server knows how to handle. These gets picked up by the + * exceptions handler in Main */ sealed abstract class HttpError extends Error diff --git a/app/server-routes/src/main/scala/org/bitcoins/server/routes/Server.scala b/app/server-routes/src/main/scala/org/bitcoins/server/routes/Server.scala index bea76400a3..2563b6cc51 100644 --- a/app/server-routes/src/main/scala/org/bitcoins/server/routes/Server.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/routes/Server.scala @@ -52,7 +52,8 @@ case class Server( rpcport: Int, rpcPassword: String, wsConfigOpt: Option[WsServerConfig], - wsSource: Source[WsNotification[_], NotUsed])(implicit system: ActorSystem) + wsSource: Source[WsNotification[_], NotUsed] +)(implicit system: ActorSystem) extends HttpLogger { import system.dispatcher @@ -61,8 +62,10 @@ case class Server( if (rpchost == "localhost" || rpchost == "127.0.0.1") { logger.warn(s"RPC password is not set (rpchost=$rpchost)") } else { - require(rpcPassword.nonEmpty, - s"RPC password must be set (rpchost=$rpchost)") + require( + rpcPassword.nonEmpty, + s"RPC password must be set (rpchost=$rpchost)" + ) } } @@ -81,7 +84,8 @@ case class Server( complete { Server.httpError( """Resource not found. Hint: all RPC calls are made against root ('/')""", - StatusCodes.BadRequest) + StatusCodes.BadRequest + ) } } .result() @@ -89,8 +93,11 @@ case class Server( val exceptionHandler = ExceptionHandler { case HttpError.MethodNotFound(method) => complete( - Server.httpError(s"'$method' is not a valid method", - StatusCodes.BadRequest)) + Server.httpError( + s"'$method' is not a valid method", + StatusCodes.BadRequest + ) + ) case err: Throwable => logger.error(s"Unhandled error in server:", err) complete(Server.httpError(err.getMessage)) @@ -173,7 +180,8 @@ case class Server( } DebuggingDirectives.logRequestResult( - ("http-rpc-server", Logging.DebugLevel)) { + ("http-rpc-server", Logging.DebugLevel) + ) { authenticatedRoute } } @@ -250,7 +258,8 @@ object Server extends BitcoinSLogger { // TODO id parameter case class Response( result: Option[ujson.Value] = None, - error: Option[String] = None) { + error: Option[String] = None + ) { def toJsonMap: Map[String, ujson.Value] = { Map( @@ -267,8 +276,9 @@ object Server extends BitcoinSLogger { } /** Creates a HTTP response with the given body as a JSON response */ - def httpSuccess[T](body: T)(implicit - writer: up.Writer[T]): HttpEntity.Strict = { + def httpSuccess[T]( + body: T + )(implicit writer: up.Writer[T]): HttpEntity.Strict = { val response = Response(result = Some(up.writeJs(body))) HttpEntity( ContentTypes.`application/json`, @@ -276,8 +286,9 @@ object Server extends BitcoinSLogger { ) } - def httpSuccessOption[T](bodyOpt: Option[T])(implicit - writer: up.Writer[T]): HttpEntity.Strict = { + def httpSuccessOption[T]( + bodyOpt: Option[T] + )(implicit writer: up.Writer[T]): HttpEntity.Strict = { val response = Response(result = bodyOpt.map(body => up.writeJs(body))) HttpEntity( ContentTypes.`application/json`, diff --git a/app/server-routes/src/main/scala/org/bitcoins/server/util/AppConfigMarker.scala b/app/server-routes/src/main/scala/org/bitcoins/server/util/AppConfigMarker.scala index a56f7a7e2e..f655c4a4c0 100644 --- a/app/server-routes/src/main/scala/org/bitcoins/server/util/AppConfigMarker.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/util/AppConfigMarker.scala @@ -2,13 +2,17 @@ package org.bitcoins.server.util import scala.concurrent.Future -/** A trait used to indicated when different parts of [[BitcoinSAppConfig]] are started */ +/** A trait used to indicated when different parts of [[BitcoinSAppConfig]] are + * started + */ sealed trait AppConfigMarker /** This class represents when BitcoinSAppConfig modules are started - * @param torStartedF this future is completed when all tor dependent modules are fully started - * the reason this is needed is because tor startup time is so variable - * @see https://github.com/bitcoin-s/bitcoin-s/issues/4210 + * @param torStartedF + * this future is completed when all tor dependent modules are fully started + * the reason this is needed is because tor startup time is so variable + * @see + * https://github.com/bitcoin-s/bitcoin-s/issues/4210 */ case class StartedBitcoinSAppConfig(torStartedF: Future[Unit]) extends AppConfigMarker diff --git a/app/server-routes/src/main/scala/org/bitcoins/server/util/BitcoinSApp.scala b/app/server-routes/src/main/scala/org/bitcoins/server/util/BitcoinSApp.scala index 042c10b697..35716272e9 100644 --- a/app/server-routes/src/main/scala/org/bitcoins/server/util/BitcoinSApp.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/util/BitcoinSApp.scala @@ -10,7 +10,9 @@ trait BitcoinSApp { def commandLineArgs: Array[String] - /** Useful for projects like the oracle server to specify a custom directory inside of ~./bitcoin-s */ + /** Useful for projects like the oracle server to specify a custom directory + * inside of ~./bitcoin-s + */ def customFinalDirOpt: Option[String] } diff --git a/app/server-routes/src/main/scala/org/bitcoins/server/util/ServerBindings.scala b/app/server-routes/src/main/scala/org/bitcoins/server/util/ServerBindings.scala index 2617d48ac4..d392525eff 100644 --- a/app/server-routes/src/main/scala/org/bitcoins/server/util/ServerBindings.scala +++ b/app/server-routes/src/main/scala/org/bitcoins/server/util/ServerBindings.scala @@ -8,8 +8,8 @@ import scala.concurrent.{ExecutionContext, Future} case class ServerBindings( httpServer: Http.ServerBinding, - webSocketServerOpt: Option[Http.ServerBinding]) - extends BitcoinSLogger { + webSocketServerOpt: Option[Http.ServerBinding] +) extends BitcoinSLogger { private val terminateTimeout = 5.seconds diff --git a/app/server-test/src/test/scala/org/bitcoins/server/BitcoinSServerMainBitcoindTest.scala b/app/server-test/src/test/scala/org/bitcoins/server/BitcoinSServerMainBitcoindTest.scala index f0881fd3ca..06466ff6ae 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/BitcoinSServerMainBitcoindTest.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/BitcoinSServerMainBitcoindTest.scala @@ -27,8 +27,10 @@ class BitcoinSServerMainBitcoindTest config: BitcoinSAppConfig => val server = new BitcoinSServerMain(ServerArgParser.empty)(system, config) - val cliConfig = Config(rpcPortOpt = Some(config.rpcPort), - rpcPassword = config.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(config.rpcPort), + rpcPassword = config.rpcPassword + ) for { _ <- server.start() @@ -38,7 +40,7 @@ class BitcoinSServerMainBitcoindTest addr = exec(GetNewAddress(labelOpt = None), cliConfig) blockHash = ConsoleCli.exec(CliCommand.GetBestBlockHash, cliConfig) _ <- AsyncUtil.nonBlockingSleep(1.second) - _ <- server.stop() //stop to free all resources + _ <- server.stop() // stop to free all resources } yield { assert(info.isSuccess) assert(balance.isSuccess) @@ -54,8 +56,10 @@ class BitcoinSServerMainBitcoindTest val server = new BitcoinSServerMain(ServerArgParser.empty)(system, config) - val cliConfig = Config(rpcPortOpt = Some(config.rpcPort), - rpcPassword = config.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(config.rpcPort), + rpcPassword = config.rpcPassword + ) val mnemonic = MnemonicCode.fromEntropy(ECPrivateKey.freshPrivateKey.bytes.toBitVector) @@ -136,7 +140,8 @@ class BitcoinSServerMainBitcoindTest assert(infoT.isFailure) assert( infoT.failed.get.getMessage - .contains("The supplied authentication is invalid")) + .contains("The supplied authentication is invalid") + ) } failF diff --git a/app/server-test/src/test/scala/org/bitcoins/server/BitcoinSServerMainBitcoindTorTest.scala b/app/server-test/src/test/scala/org/bitcoins/server/BitcoinSServerMainBitcoindTorTest.scala index 38eb20db8d..4714d21cdc 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/BitcoinSServerMainBitcoindTorTest.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/BitcoinSServerMainBitcoindTorTest.scala @@ -21,8 +21,10 @@ class BitcoinSServerMainBitcoindTorTest config: BitcoinSAppConfig => val server = new BitcoinSServerMain(ServerArgParser.empty)(system, config) - val cliConfig = Config(rpcPortOpt = Some(config.rpcPort), - rpcPassword = config.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(config.rpcPort), + rpcPassword = config.rpcPassword + ) for { _ <- torF @@ -33,7 +35,7 @@ class BitcoinSServerMainBitcoindTorTest addr = exec(GetNewAddress(labelOpt = None), cliConfig) blockHash = ConsoleCli.exec(CliCommand.GetBestBlockHash, cliConfig) _ <- AsyncUtil.nonBlockingSleep(1.second) - _ <- server.stop() //stop to free all resources + _ <- server.stop() // stop to free all resources } yield { assert(info.isSuccess) assert(balance.isSuccess) diff --git a/app/server-test/src/test/scala/org/bitcoins/server/BitcoindRpcAppConfigTest.scala b/app/server-test/src/test/scala/org/bitcoins/server/BitcoindRpcAppConfigTest.scala index 04ab3ac4ae..9a466ad039 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/BitcoindRpcAppConfigTest.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/BitcoindRpcAppConfigTest.scala @@ -30,7 +30,8 @@ class BitcoindRpcAppConfigTest extends BitcoinSAsyncTest { assert(withOther.rpcPort == 5555) val mainnetConf = ConfigFactory.parseString( - s"bitcoin-s.bitcoind-rpc.rpcport = ${MainNet.rpcPort}") + s"bitcoin-s.bitcoind-rpc.rpcport = ${MainNet.rpcPort}" + ) val mainnet = withOther.withOverrides(mainnetConf) assert(mainnet.rpcPort == MainNet.rpcPort) } diff --git a/app/server-test/src/test/scala/org/bitcoins/server/CallBackUtilTest.scala b/app/server-test/src/test/scala/org/bitcoins/server/CallBackUtilTest.scala index 6f0b0572df..8afe136bc0 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/CallBackUtilTest.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/CallBackUtilTest.scala @@ -51,8 +51,8 @@ class CallBackUtilTest extends BitcoinSWalletTest { _ <- callbacks .executeOnTxReceivedCallbacks(tx2) .recoverWith { case _: StreamDetachedException => - //expect the stream to be detatched because we stopped - //the stream with callbacks.stop() + // expect the stream to be detatched because we stopped + // the stream with callbacks.stop() Future.unit } balance3 <- wallet.getBalance() @@ -92,8 +92,8 @@ class CallBackUtilTest extends BitcoinSWalletTest { _ <- callbacks .executeOnTxReceivedCallbacks(tx2) .recoverWith { case _: StreamDetachedException => - //expect the stream to be detatched because we stopped - //the stream with callbacks.stop() + // expect the stream to be detatched because we stopped + // the stream with callbacks.stop() Future.unit } balance3 <- wallet.getBalance() diff --git a/app/server-test/src/test/scala/org/bitcoins/server/CommonRoutesSpec.scala b/app/server-test/src/test/scala/org/bitcoins/server/CommonRoutesSpec.scala index 586f9b8256..26774d883d 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/CommonRoutesSpec.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/CommonRoutesSpec.scala @@ -54,7 +54,8 @@ class CommonRoutesSpec val route = commonRoutes.handleCommand( - ServerCommand("zipdatadir", ujson.Arr(target.toString))) + ServerCommand("zipdatadir", ujson.Arr(target.toString)) + ) Post() ~> route ~> check { assert(contentType == ContentTypes.`application/json`) diff --git a/app/server-test/src/test/scala/org/bitcoins/server/DLCRoutesSpec.scala b/app/server-test/src/test/scala/org/bitcoins/server/DLCRoutesSpec.scala index c09273c5e7..2364f35a58 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/DLCRoutesSpec.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/DLCRoutesSpec.scala @@ -32,20 +32,22 @@ class DLCRoutesSpec val dlcRoutes = DLCRoutes(mockNodeApi) - //https://test.oracle.suredbits.com/announcement/8863cd80e1d37f668e27b84cbfed48541d671b4fed1462b86d547e7f13b5a9e4 + // https://test.oracle.suredbits.com/announcement/8863cd80e1d37f668e27b84cbfed48541d671b4fed1462b86d547e7f13b5a9e4 val announcement = OracleAnnouncementTLV.fromHex( - "fdd824c3988fabec9820690f366271c9ceac00fbec1412075f9b319bb0db1f86460519dd9c61478949f2c00c35aeb8e53a1507616072cb802891e2c189a9fa65a0493de5d3b04a6d7b90c9c43c09ebe5250d583e1c3fc423219b26f6a02ec394a130000afdd8225f0001ae3e30df5a203ad10ee89a909df0c8ccea4836e94e0a5d34c3cdab758fcaee1460189600fdd8062400030e52657075626c6963616e5f77696e0c44656d6f637261745f77696e056f7468657210323032302d75732d656c656374696f6e") + "fdd824c3988fabec9820690f366271c9ceac00fbec1412075f9b319bb0db1f86460519dd9c61478949f2c00c35aeb8e53a1507616072cb802891e2c189a9fa65a0493de5d3b04a6d7b90c9c43c09ebe5250d583e1c3fc423219b26f6a02ec394a130000afdd8225f0001ae3e30df5a203ad10ee89a909df0c8ccea4836e94e0a5d34c3cdab758fcaee1460189600fdd8062400030e52657075626c6963616e5f77696e0c44656d6f637261745f77696e056f7468657210323032302d75732d656c656374696f6e" + ) - //https://test.oracle.suredbits.com/announcement/362ae482860fc93bac5cbcca3f1f0e49b3c94eac92224a008bd81ef81292f43a + // https://test.oracle.suredbits.com/announcement/362ae482860fc93bac5cbcca3f1f0e49b3c94eac92224a008bd81ef81292f43a val numericAnnouncement = OracleAnnouncementTLV.fromHex( "fdd824fd02b9659e890eef1b223ba45c9993f88c7997859302fd5510ac23f4cac0d4ee8232a77ecbdf50c07f093794370e6a506a836f6b0fb54b45f1fb662e1307166d2e57030574f77305826939fa9124d19bfa8a8b2f00f000586b8c58c79ee8b77969a949fdd822fd025300114762c188048a953803f0edeeeb68c69e6cdc1d371ba8d517003accfe05afc4d6588c3ea326512bc66c26a841adffa68330b8c723da442792e731fb19fda94274a7766bb48e520f118c100bbe62dc3806a8d05a63d92e23683a04b0b8c24148cd166585a6b33b995b3d6c083523a8435b156c05100d88f449f4754310d5574d5e88aad09af1b8ba942cfd305e728044ec6360d847254453ec05b1b518a36660e2238360e02f3a004663a7f3a3534973d8b66a2646c1386779aa820672b6361b88a8696395c0add87840b460dfd8a8c0d520017efc6bf58267d4c9d2a225c5d0e5719068a7dda5d630d7432239b6c9d921d5f3842b584503460ca52612ac2e64337d299513690372e8f4770eb8a28080e8d7c29920ca32af470d65d6f916ee81e3ac15ce02684ba6d2522a9ffea1de7e202b4b699ef7ec4f089dda07f3de5b7d1f853b2c56471999be4efca82674a651c80f047ba3a2b9e6f9999f0cd4062c533d1ae29cab2a5e33cbe98728b7b4271c67f7c5cd6e12e39128b9971e08496cbd84cfa99c77c88867d33e73acef37022ba4422a5221776991d45416db71fb54bc6c104f6a8e50e8905161709215104a7e7b97e866f32cf43233ffd615cab66699832ec607cf59c85a7f56fa957aa5f5d7ec9f46d84d5d4b777122d41ad76c6f4968aeedca243f2030d4f502e58f4181130e9afb75309ac21637bcfd0717528bfb82ffe1b6c9fadee6ba70357210990539184bcc913a0ec65837a736733a2fb6172d601b3900fdd80a11000200074254432f55534400000000001117626974636f696e2d732d70726963652d6578616d706c65" ) - //https://test.oracle.suredbits.com/contract/enum/5fbc1d037bacd9ece32ff4b591143bce7fa1c22e0aec2fa8437cc336feb95138 + // https://test.oracle.suredbits.com/contract/enum/5fbc1d037bacd9ece32ff4b591143bce7fa1c22e0aec2fa8437cc336feb95138 val expectedContractInfo = ContractInfo.fromHex( - "fdd82efd01120000000005f5e100fda7103b030e52657075626c6963616e5f77696e00000000000000000c44656d6f637261745f77696e0000000005f5e100056f746865720000000003938700fda712c7fdd824c3988fabec9820690f366271c9ceac00fbec1412075f9b319bb0db1f86460519dd9c61478949f2c00c35aeb8e53a1507616072cb802891e2c189a9fa65a0493de5d3b04a6d7b90c9c43c09ebe5250d583e1c3fc423219b26f6a02ec394a130000afdd8225f0001ae3e30df5a203ad10ee89a909df0c8ccea4836e94e0a5d34c3cdab758fcaee1460189600fdd8062400030e52657075626c6963616e5f77696e0c44656d6f637261745f77696e056f7468657210323032302d75732d656c656374696f6e") + "fdd82efd01120000000005f5e100fda7103b030e52657075626c6963616e5f77696e00000000000000000c44656d6f637261745f77696e0000000005f5e100056f746865720000000003938700fda712c7fdd824c3988fabec9820690f366271c9ceac00fbec1412075f9b319bb0db1f86460519dd9c61478949f2c00c35aeb8e53a1507616072cb802891e2c189a9fa65a0493de5d3b04a6d7b90c9c43c09ebe5250d583e1c3fc423219b26f6a02ec394a130000afdd8225f0001ae3e30df5a203ad10ee89a909df0c8ccea4836e94e0a5d34c3cdab758fcaee1460189600fdd8062400030e52657075626c6963616e5f77696e0c44656d6f637261745f77696e056f7468657210323032302d75732d656c656374696f6e" + ) - //https://test.oracle.suredbits.com/contract/numeric/d4d4df2892fb2cfd2e8f030f0e69a568e19668b5d355e7713f69853db09a4c33 + // https://test.oracle.suredbits.com/contract/numeric/d4d4df2892fb2cfd2e8f030f0e69a568e19668b5d355e7713f69853db09a4c33 val expectedNumericContractInfo = ContractInfo.fromHex( "fdd82efd032500000000000186a0fda720540011fda72648000501000000000000000000000001fd9c400000000000000000000001fda604000000000000c350000001fdafc800000000000186a0000001fe0001ffff00000000000186a00000fda724020000fda712fd02bffdd824fd02b9659e890eef1b223ba45c9993f88c7997859302fd5510ac23f4cac0d4ee8232a77ecbdf50c07f093794370e6a506a836f6b0fb54b45f1fb662e1307166d2e57030574f77305826939fa9124d19bfa8a8b2f00f000586b8c58c79ee8b77969a949fdd822fd025300114762c188048a953803f0edeeeb68c69e6cdc1d371ba8d517003accfe05afc4d6588c3ea326512bc66c26a841adffa68330b8c723da442792e731fb19fda94274a7766bb48e520f118c100bbe62dc3806a8d05a63d92e23683a04b0b8c24148cd166585a6b33b995b3d6c083523a8435b156c05100d88f449f4754310d5574d5e88aad09af1b8ba942cfd305e728044ec6360d847254453ec05b1b518a36660e2238360e02f3a004663a7f3a3534973d8b66a2646c1386779aa820672b6361b88a8696395c0add87840b460dfd8a8c0d520017efc6bf58267d4c9d2a225c5d0e5719068a7dda5d630d7432239b6c9d921d5f3842b584503460ca52612ac2e64337d299513690372e8f4770eb8a28080e8d7c29920ca32af470d65d6f916ee81e3ac15ce02684ba6d2522a9ffea1de7e202b4b699ef7ec4f089dda07f3de5b7d1f853b2c56471999be4efca82674a651c80f047ba3a2b9e6f9999f0cd4062c533d1ae29cab2a5e33cbe98728b7b4271c67f7c5cd6e12e39128b9971e08496cbd84cfa99c77c88867d33e73acef37022ba4422a5221776991d45416db71fb54bc6c104f6a8e50e8905161709215104a7e7b97e866f32cf43233ffd615cab66699832ec607cf59c85a7f56fa957aa5f5d7ec9f46d84d5d4b777122d41ad76c6f4968aeedca243f2030d4f502e58f4181130e9afb75309ac21637bcfd0717528bfb82ffe1b6c9fadee6ba70357210990539184bcc913a0ec65837a736733a2fb6172d601b3900fdd80a11000200074254432f55534400000000001117626974636f696e2d732d70726963652d6578616d706c65" ) @@ -84,8 +86,11 @@ class DLCRoutesSpec Post() ~> route ~> check { assert(contentType == ContentTypes.`application/json`) - assert(responseAs[ - String] == s"""{"result":"${expectedContractInfo.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${expectedContractInfo.hex}","error":null}""" + ) } } @@ -147,8 +152,11 @@ class DLCRoutesSpec Post() ~> route ~> check { assert(contentType == ContentTypes.`application/json`) - assert(responseAs[ - String] == s"""{"result":"${expectedNumericContractInfo.hex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"${expectedNumericContractInfo.hex}","error":null}""" + ) } } @@ -222,7 +230,8 @@ class DLCRoutesSpec Post() ~> route ~> check { assert(contentType == ContentTypes.`application/json`) assert( - responseAs[String] == s"""{"result":{"dlcId":"0000000000000000000000000000000000000000000000000000000000000000","contactId":"i3bfhauurptgypgnolqmj7xxv7pcs5c6udtzthbgojc7eaxx6zbbjyad.onion:2862"},"error":null}""") + responseAs[String] == s"""{"result":{"dlcId":"0000000000000000000000000000000000000000000000000000000000000000","contactId":"i3bfhauurptgypgnolqmj7xxv7pcs5c6udtzthbgojc7eaxx6zbbjyad.onion:2862"},"error":null}""" + ) } } diff --git a/app/server-test/src/test/scala/org/bitcoins/server/DLCWalletBitcoindBackendLoaderTest.scala b/app/server-test/src/test/scala/org/bitcoins/server/DLCWalletBitcoindBackendLoaderTest.scala index e3b36fdc81..65a28d05d1 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/DLCWalletBitcoindBackendLoaderTest.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/DLCWalletBitcoindBackendLoaderTest.scala @@ -34,38 +34,41 @@ class DLCWalletBitcoindBackendLoaderTest extends WalletLoaderFixtures { it must "track rescan state accurately" in { walletHolderWithLoader => val loader = walletHolderWithLoader.loaderApi val bitcoind = walletHolderWithLoader.bitcoind - //need some blocks to make rescans last longer for the test case + // need some blocks to make rescans last longer for the test case val blocksF = bitcoind.generate(250) val loadedWalletF = loader.load(walletNameOpt = None, aesPasswordOpt = None) val walletConfigF = loadedWalletF.map(_._2) - //as a hack, set rescanning to true, so next time we load it starts a rescan + // as a hack, set rescanning to true, so next time we load it starts a rescan val setRescanF = for { _ <- blocksF walletConfig <- walletConfigF - descriptorDAO = WalletStateDescriptorDAO()(system.dispatcher, - walletConfig) + descriptorDAO = WalletStateDescriptorDAO()( + system.dispatcher, + walletConfig + ) set <- descriptorDAO.compareAndSetRescanning(false, true) } yield assert(set) - //now that we have set rescanning, we should see a rescan next time we load wallet + // now that we have set rescanning, we should see a rescan next time we load wallet for { _ <- setRescanF (loadWallet2, _, _) <- loader.load( walletNameOpt = None, aesPasswordOpt = None - ) //load wallet again + ) // load wallet again isRescanning <- loadWallet2.isRescanning() _ = assert(isRescanning) _ = assert(loader.isRescanStateDefined) - //wait until rescanning is done + // wait until rescanning is done _ <- AsyncUtil.retryUntilSatisfiedF( { () => loadWallet2.isRescanning().map(isRescanning => isRescanning == false) }, - 1.second) + 1.second + ) } yield { assert(loader.isRescanStateEmpty) } diff --git a/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala b/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala index 62b8cbe117..214e960ed4 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala @@ -82,10 +82,12 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val feeRateApi = ConstantFeeRateProvider(SatoshisPerVirtualByte.one) val walletLoader: DLCWalletNeutrinoBackendLoader = { - DLCWalletNeutrinoBackendLoader(walletHolder, - mockChainApi, - mockNode, - feeRateApi) + DLCWalletNeutrinoBackendLoader( + walletHolder, + mockChainApi, + mockNode, + feeRateApi + ) } val walletRoutes: WalletRoutes = @@ -98,89 +100,115 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { "combine PSBTs" in { val psbt1 = PSBT( - "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f00") + "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f00" + ) val psbt2 = PSBT( - "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f00") + "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f00" + ) val expected = PSBT( - "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f00") + "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f00" + ) val route = coreRoutes.handleCommand( - ServerCommand("combinepsbts", - Arr(Arr(Str(psbt1.base64), Str(psbt2.base64))))) + ServerCommand( + "combinepsbts", + Arr(Arr(Str(psbt1.base64), Str(psbt2.base64))) + ) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${expected.base64}","error":null}""") + String + ] == s"""{"result":"${expected.base64}","error":null}""" + ) } val joinRoute = coreRoutes.handleCommand( - ServerCommand("joinpsbts", - Arr(Arr(Str(psbt1.base64), Str(psbt2.base64))))) + ServerCommand( + "joinpsbts", + Arr(Arr(Str(psbt1.base64), Str(psbt2.base64))) + ) + ) Get() ~> joinRoute ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${expected.base64}","error":null}""") + String + ] == s"""{"result":"${expected.base64}","error":null}""" + ) } } "finalize a PSBT" in { val psbt = PSBT( - "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000002202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d201220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000002202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d201220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) val expected = PSBT( - "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000000107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000000107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) val route = coreRoutes.handleCommand( - ServerCommand("finalizepsbt", Arr(Str(psbt.hex)))) + ServerCommand("finalizepsbt", Arr(Str(psbt.hex))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${expected.base64}","error":null}""") + String + ] == s"""{"result":"${expected.base64}","error":null}""" + ) } } "extract a transaction from a PSBT" in { val psbt = PSBT( - "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) val expected = Transaction( - "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000") + "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000" + ) val route = coreRoutes.handleCommand( - ServerCommand("extractfrompsbt", Arr(Str(psbt.hex)))) + ServerCommand("extractfrompsbt", Arr(Str(psbt.hex))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[ - String] == s"""{"result":"${expected.hex}","error":null}""") + responseAs[String] == s"""{"result":"${expected.hex}","error":null}""" + ) } } "convert a transaction to a PSBT" in { val tx = Transaction( - "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000") + "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000" + ) val expected = PSBT( - "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000") + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000" + ) val route = coreRoutes.handleCommand( - ServerCommand("converttopsbt", Arr(Str(tx.hex)))) + ServerCommand("converttopsbt", Arr(Str(tx.hex))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${expected.base64}","error":null}""") + String + ] == s"""{"result":"${expected.base64}","error":null}""" + ) } } @@ -238,16 +266,20 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""") + responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""" + ) } } val blockHeader = BlockHeader( - "00e0002094c6692e100ed20d14f8c325c897259749e781d55ed1b7eb1000000000000000309a90b49f5f5a14ffdb2857557f6f27a136943603fb29e65e283dcb27fd886124fee25f57e53019886c0e8b") + "00e0002094c6692e100ed20d14f8c325c897259749e781d55ed1b7eb1000000000000000309a90b49f5f5a14ffdb2857557f6f27a136943603fb29e65e283dcb27fd886124fee25f57e53019886c0e8b" + ) val blockHeaderDb = - BlockHeaderDbHelper.fromBlockHeader(height = 1899697, - chainWork = BigInt(12345), - bh = blockHeader) + BlockHeaderDbHelper.fromBlockHeader( + height = 1899697, + chainWork = BigInt(12345), + bh = blockHeader + ) "get a block header" in { val chainworkStr = { @@ -275,12 +307,16 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = chainRoutes.handleCommand( - ServerCommand("getblockheader", Arr(Str(blockHeader.hashBE.hex)))) + ServerCommand("getblockheader", Arr(Str(blockHeader.hashBE.hex))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":{"raw":"${blockHeader.hex}","hash":"${blockHeader.hashBE.hex}","confirmations":0,"height":1899697,"version":${blockHeader.version.toLong},"versionHex":"${blockHeader.version.hex}","merkleroot":"${blockHeader.merkleRootHashBE.hex}","time":${blockHeader.time.toLong},"mediantime":${blockHeaderDb.time.toLong},"nonce":${blockHeader.nonce.toLong},"bits":"${blockHeader.nBits.hex}","difficulty":${blockHeader.difficulty.toDouble},"chainwork":"$chainworkStr","previousblockhash":"${blockHeader.previousBlockHashBE.hex}","nextblockhash":null},"error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":{"raw":"${blockHeader.hex}","hash":"${blockHeader.hashBE.hex}","confirmations":0,"height":1899697,"version":${blockHeader.version.toLong},"versionHex":"${blockHeader.version.hex}","merkleroot":"${blockHeader.merkleRootHashBE.hex}","time":${blockHeader.time.toLong},"mediantime":${blockHeaderDb.time.toLong},"nonce":${blockHeader.nonce.toLong},"bits":"${blockHeader.nBits.hex}","difficulty":${blockHeader.difficulty.toDouble},"chainwork":"$chainworkStr","previousblockhash":"${blockHeader.previousBlockHashBE.hex}","nextblockhash":null},"error":null}""" + ) } } @@ -306,7 +342,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("getbalance", Arr(Bool(false)))) + ServerCommand("getbalance", Arr(Bool(false))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) @@ -336,7 +373,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("getconfirmedbalance", Arr(Bool(false)))) + ServerCommand("getconfirmedbalance", Arr(Bool(false))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) @@ -351,7 +389,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("getconfirmedbalance", Arr(Bool(true)))) + ServerCommand("getconfirmedbalance", Arr(Bool(true))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) @@ -366,7 +405,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("getunconfirmedbalance", Arr(Bool(false)))) + ServerCommand("getunconfirmedbalance", Arr(Bool(false))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) @@ -392,12 +432,14 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("getbalances", Arr(Bool(false)))) + ServerCommand("getbalances", Arr(Bool(false))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":{"confirmed":50,"unconfirmed":50,"reserved":1,"total":101},"error":null}""") + responseAs[String] == """{"result":{"confirmed":50,"unconfirmed":50,"reserved":1,"total":101},"error":null}""" + ) } } @@ -417,12 +459,14 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("getbalances", Arr(Bool(true)))) + ServerCommand("getbalances", Arr(Bool(true))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":{"confirmed":5000000000,"unconfirmed":5000000000,"reserved":100000000,"total":10100000000},"error":null}""") + responseAs[String] == """{"result":{"confirmed":5000000000,"unconfirmed":5000000000,"reserved":100000000,"total":10100000000},"error":null}""" + ) } } @@ -433,7 +477,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("getunconfirmedbalance", Arr(Bool(true)))) + ServerCommand("getunconfirmedbalance", Arr(Bool(true))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) @@ -467,7 +512,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":[{"outpoint":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","vout":0},"value":100000000}],"error":null}""") + responseAs[String] == """{"result":[{"outpoint":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","vout":0},"value":100000000}],"error":null}""" + ) } } @@ -484,7 +530,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":[{"outpoint":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","vout":0},"value":100000000}],"error":null}""") + responseAs[String] == """{"result":[{"outpoint":{"txid":"0000000000000000000000000000000000000000000000000000000000000000","vout":0},"value":100000000}],"error":null}""" + ) } } @@ -507,7 +554,10 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":["""" + testAddressStr + """"],"error":null}""") + responseAs[ + String + ] == """{"result":["""" + testAddressStr + """"],"error":null}""" + ) } } @@ -530,7 +580,10 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":["""" + testAddressStr + """"],"error":null}""") + responseAs[ + String + ] == """{"result":["""" + testAddressStr + """"],"error":null}""" + ) } } @@ -552,8 +605,10 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[String] == - s"""{"result":[{"address":"$testAddressStr","value":0}],"error":null}""".stripMargin) + assert( + responseAs[String] == + s"""{"result":[{"address":"$testAddressStr","value":0}],"error":null}""".stripMargin + ) } } @@ -576,19 +631,25 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":["""" + testAddressStr + """"],"error":null}""") + responseAs[ + String + ] == """{"result":["""" + testAddressStr + """"],"error":null}""" + ) } } "return the wallet accounts" in { val xpub = ExtPublicKey .fromString( - "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8") + "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" + ) val accountDb = - AccountDb(xpub = xpub, - hdAccount = - HDAccount(HDCoin(HDPurposes.Legacy, HDCoinType.Testnet), 0)) + AccountDb( + xpub = xpub, + hdAccount = + HDAccount(HDCoin(HDPurposes.Legacy, HDCoinType.Testnet), 0) + ) (() => mockWalletApi.listAccounts()) .expects() @@ -599,8 +660,11 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == """{"result":["""" + xpub.toString + """"],"error":null}""") + assert( + responseAs[ + String + ] == """{"result":["""" + xpub.toString + """"],"error":null}""" + ) } } @@ -614,8 +678,11 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == """{"result":"""" + testAddressStr + """","error":null}""") + assert( + responseAs[ + String + ] == """{"result":"""" + testAddressStr + """","error":null}""" + ) } } @@ -631,12 +698,16 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("getaddressinfo", Arr(Str(testAddressStr)))) + ServerCommand("getaddressinfo", Arr(Str(testAddressStr))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":{"pubkey":"${key.hex}","path":"${hdPath.toString}"},"error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":{"pubkey":"${key.hex}","path":"${hdPath.toString}"},"error":null}""" + ) } } @@ -648,12 +719,16 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("getnewaddress", Arr(Str(testLabel.name)))) + ServerCommand("getnewaddress", Arr(Str(testLabel.name))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == """{"result":"""" + testAddressStr + """","error":null}""") + assert( + responseAs[ + String + ] == """{"result":"""" + testAddressStr + """","error":null}""" + ) } } @@ -683,7 +758,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route1 = walletRoutes.handleCommand( - ServerCommand("lockunspent", Arr(Bool(false), Arr()))) + ServerCommand("lockunspent", Arr(Bool(false), Arr())) + ) Get() ~> route1 ~> check { assert(contentType == `application/json`) @@ -692,7 +768,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route2 = walletRoutes.handleCommand( - ServerCommand("lockunspent", Arr(Bool(true), Arr()))) + ServerCommand("lockunspent", Arr(Bool(true), Arr())) + ) Get() ~> route2 ~> check { assert(contentType == `application/json`) @@ -706,7 +783,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route3 = walletRoutes.handleCommand( - ServerCommand("lockunspent", Arr(Bool(true), Arr(obj)))) + ServerCommand("lockunspent", Arr(Bool(true), Arr(obj))) + ) Get() ~> route3 ~> check { assert(contentType == `application/json`) @@ -715,7 +793,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route4 = walletRoutes.handleCommand( - ServerCommand("lockunspent", Arr(Bool(true), Arr(obj)))) + ServerCommand("lockunspent", Arr(Bool(true), Arr(obj))) + ) Get() ~> route4 ~> check { assert(contentType == `application/json`) @@ -731,13 +810,19 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("labeladdress", - Arr(Str(testAddressStr), Str(testLabel.name)))) + ServerCommand( + "labeladdress", + Arr(Str(testAddressStr), Str(testLabel.name)) + ) + ) Get() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == """{"result":"""" + s"Added label \'${testLabel.name}\' to $testAddressStr" + """","error":null}""") + assert( + responseAs[ + String + ] == """{"result":"""" + s"Added label \'${testLabel.name}\' to $testAddressStr" + """","error":null}""" + ) } } @@ -746,16 +831,21 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .getAddressTags(_: BitcoinAddress)) .expects(testAddress) .returning( - Future.successful(Vector(AddressTagDb(testAddress, testLabel)))) + Future.successful(Vector(AddressTagDb(testAddress, testLabel))) + ) val route = walletRoutes.handleCommand( - ServerCommand("getaddresstags", Arr(Str(testAddressStr)))) + ServerCommand("getaddresstags", Arr(Str(testAddressStr))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":["""" + testLabel.name + """"],"error":null}""") + responseAs[ + String + ] == """{"result":["""" + testLabel.name + """"],"error":null}""" + ) } } @@ -764,16 +854,21 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .getAddressTags(_: BitcoinAddress, _: AddressTagType)) .expects(testAddress, AddressLabelTagType) .returning( - Future.successful(Vector(AddressTagDb(testAddress, testLabel)))) + Future.successful(Vector(AddressTagDb(testAddress, testLabel))) + ) val route = walletRoutes.handleCommand( - ServerCommand("getaddresslabel", Arr(Str(testAddressStr)))) + ServerCommand("getaddresslabel", Arr(Str(testAddressStr))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":["""" + testLabel.name + """"],"error":null}""") + responseAs[ + String + ] == """{"result":["""" + testLabel.name + """"],"error":null}""" + ) } } @@ -781,7 +876,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { (() => mockWalletApi.getAddressTags()) .expects() .returning( - Future.successful(Vector(AddressTagDb(testAddress, testLabel)))) + Future.successful(Vector(AddressTagDb(testAddress, testLabel))) + ) val route = walletRoutes.handleCommand(ServerCommand("getaddresslabels", Arr())) @@ -789,7 +885,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":[{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","labels":["test"]}],"error":null}""") + responseAs[String] == """{"result":[{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa","labels":["test"]}],"error":null}""" + ) } } @@ -802,13 +899,19 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("dropaddresslabel", - Arr(Str(testAddressStr), Str(labelName)))) + ServerCommand( + "dropaddresslabel", + Arr(Str(testAddressStr), Str(labelName)) + ) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"""" + "1 label dropped" + """","error":null}""") + responseAs[ + String + ] == """{"result":"""" + "1 label dropped" + """","error":null}""" + ) } } @@ -820,12 +923,14 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("dropaddresslabels", Arr(Str(testAddressStr)))) + ServerCommand("dropaddresslabels", Arr(Str(testAddressStr))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"""" + "Address had no labels" + """","error":null}""") + responseAs[String] == """{"result":"""" + "Address had no labels" + """","error":null}""" + ) } } @@ -837,12 +942,16 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("dropaddresslabels", Arr(Str(testAddressStr)))) + ServerCommand("dropaddresslabels", Arr(Str(testAddressStr))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"""" + "1 label dropped" + """","error":null}""") + responseAs[ + String + ] == """{"result":"""" + "1 label dropped" + """","error":null}""" + ) } } @@ -854,18 +963,23 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("dropaddresslabels", Arr(Str(testAddressStr)))) + ServerCommand("dropaddresslabels", Arr(Str(testAddressStr))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"""" + "2 labels dropped" + """","error":null}""") + responseAs[ + String + ] == """{"result":"""" + "2 labels dropped" + """","error":null}""" + ) } } "send a raw transaction" in { val tx = Transaction( - "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000") + "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000" + ) (mockWalletApi .broadcastTransaction(_: Transaction)) @@ -875,19 +989,23 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("sendrawtransaction", Arr(Str(tx.hex)))) + ServerCommand("sendrawtransaction", Arr(Str(tx.hex))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${tx.txIdBE.hex}","error":null}""") + String + ] == s"""{"result":"${tx.txIdBE.hex}","error":null}""" + ) } } "get a transaction" in { val tx = Transaction( - "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000") + "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000" + ) val txDb = TransactionDbHelper.fromTransaction(tx, None) @@ -899,7 +1017,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("gettransaction", Arr(Str(tx.txIdBE.hex)))) + ServerCommand("gettransaction", Arr(Str(tx.txIdBE.hex))) + ) Get() ~> route ~> check { assert(contentType == `application/json`) @@ -908,14 +1027,17 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { } val contractInfoDigests = - Vector("ffbbcde836cee437a2fa4ef7db1ea3d79ca71c0c821d2a197dda51bc6534f562", - "e770f42c578084a4a096ce1085f7fe508f8d908d2c5e6e304b2c3eab9bc973ea") + Vector( + "ffbbcde836cee437a2fa4ef7db1ea3d79ca71c0c821d2a197dda51bc6534f562", + "e770f42c578084a4a096ce1085f7fe508f8d908d2c5e6e304b2c3eab9bc973ea" + ) val contractDesc = EnumContractDescriptor.fromStringVec( Vector( (contractInfoDigests.head, Satoshis(5)), (contractInfoDigests.last, Satoshis(4)) - )) + ) + ) val contractMaturity = 1580323752 val contractTimeout = 1581323752 @@ -932,13 +1054,16 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { } val dummyOracleSig = SchnorrDigitalSignature( - "65ace55b5d073cc7a1c783fa8c254692c421270fa988247e3c87627ffe804ed06c20bf779da91f82da3311b1d9e0a3a513409a15c66f25201280751177dad24c") + "65ace55b5d073cc7a1c783fa8c254692c421270fa988247e3c87627ffe804ed06c20bf779da91f82da3311b1d9e0a3a513409a15c66f25201280751177dad24c" + ) val dummyOracleAttestment = - OracleAttestmentV0TLV("eventId", - dummyPubKey.schnorrPublicKey, - OrderedSchnorrSignatures(dummyOracleSig).toVector, - Vector("outcome")) + OracleAttestmentV0TLV( + "eventId", + dummyPubKey.schnorrPublicKey, + OrderedSchnorrSignatures(dummyOracleSig).toVector, + Vector("outcome") + ) lazy val winStr: String = "WIN" @@ -950,19 +1075,23 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { DLCPublicKeys(dummyPubKey, BitcoinAddress(dummyAddress)) val paramHash = Sha256DigestBE( - "de462f212d95ca4cf5db54eee08f14be0ee934e9ecfc6e9b7014ecfa51ba7b66") + "de462f212d95ca4cf5db54eee08f14be0ee934e9ecfc6e9b7014ecfa51ba7b66" + ) val contractId = ByteVector.fromValidHex( - "4c6eb53573aae186dbb1a93274cc00c795473d7cfe2cb69e7d185ee28a39b919") + "4c6eb53573aae186dbb1a93274cc00c795473d7cfe2cb69e7d185ee28a39b919" + ) val wtx: WitnessTransaction = WitnessTransaction( - "02000000000101a2619b5d58b209439c937e563018efcf174063ca011e4f177a5b14e5ba76211c0100000017160014614e9b96cbc7477eda98f0936385ded6b636f74efeffffff024e3f57c4000000001600147cf00288c2c1b3c5cdf275db532a1c15c514bb2fae1112000000000016001440efb02597b9e9d9bc968f12cec3347e2e264c570247304402205768c2ac8178539fd44721e2a7541bedd6b55654f095143514624203c133f7e8022060d51f33fc2b5c1f51f26c7f703de21be6246dbb5fb7e1c6919aae6d442610c6012102b99a63f166ef53ca67a5c55ae969e80c33456e07189f8457e3438f000be42c19307d1900") + "02000000000101a2619b5d58b209439c937e563018efcf174063ca011e4f177a5b14e5ba76211c0100000017160014614e9b96cbc7477eda98f0936385ded6b636f74efeffffff024e3f57c4000000001600147cf00288c2c1b3c5cdf275db532a1c15c514bb2fae1112000000000016001440efb02597b9e9d9bc968f12cec3347e2e264c570247304402205768c2ac8178539fd44721e2a7541bedd6b55654f095143514624203c133f7e8022060d51f33fc2b5c1f51f26c7f703de21be6246dbb5fb7e1c6919aae6d442610c6012102b99a63f166ef53ca67a5c55ae969e80c33456e07189f8457e3438f000be42c19307d1900" + ) val fundingInput: DLCFundingInputP2WPKHV0 = DLCFundingInputP2WPKHV0(UInt64.zero, wtx, UInt32.zero, UInt32.zero) val announcementTLV = OracleAnnouncementV0TLV( - "fdd824fd0118c6a52b0901a23fe7d2febbb492e66d4cd4783483aeec1cae374c3e8e6bf779dc471104aa249f7904732d0a87e9c6aa51ff5705cf46b41bc2d55d83ad1fac998ae096a7f99df21b4a43eb92b07110dbab3aa53c81b9ba08755653512ac5246a09fdd822b40001aec3c6498dfedb0db322644e97be338417f5a552c4487b037130bf19f01a069b00000000fdd806840002406666626263646538333663656534333761326661346566376462316561336437396361373163306338323164326131393764646135316263363533346635363240653737306634326335373830383461346130393663653130383566376665353038663864393038643263356536653330346232633365616239626339373365610564756d6d79") + "fdd824fd0118c6a52b0901a23fe7d2febbb492e66d4cd4783483aeec1cae374c3e8e6bf779dc471104aa249f7904732d0a87e9c6aa51ff5705cf46b41bc2d55d83ad1fac998ae096a7f99df21b4a43eb92b07110dbab3aa53c81b9ba08755653512ac5246a09fdd822b40001aec3c6498dfedb0db322644e97be338417f5a552c4487b037130bf19f01a069b00000000fdd806840002406666626263646538333663656534333761326661346566376462316561336437396361373163306338323164326131393764646135316263363533346635363240653737306634326335373830383461346130393663653130383566376665353038663864393038643263356536653330346232633365616239626339373365610564756d6d79" + ) val oracleInfo = EnumSingleOracleInfo(announcementTLV) @@ -970,10 +1099,12 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Vector( EnumOracleOutcome( Vector(oracleInfo), - EnumOutcome(winStr)).sigPoint -> ECAdaptorSignature.dummy, + EnumOutcome(winStr) + ).sigPoint -> ECAdaptorSignature.dummy, EnumOracleOutcome( Vector(oracleInfo), - EnumOutcome(loseStr)).sigPoint -> ECAdaptorSignature.dummy + EnumOutcome(loseStr) + ).sigPoint -> ECAdaptorSignature.dummy ) val contractInfo = SingleContractInfo(contractDesc, oracleInfo) @@ -1031,12 +1162,14 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Num(contractMaturity), Num(contractTimeout) ) - )) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert(responseAs[String] == s"""{"result":"${LnMessage( - offer.toTLV).hex}","error":null}""") + offer.toTLV + ).hex}","error":null}""") } val badRoute = walletRoutes.handleCommand( @@ -1049,13 +1182,17 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { Str("abcd"), Num(contractTimeout) ) - )) + ) + ) Post() ~> badRoute ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) - assert(responseAs[ - String] == s"""{"result":null,"error":"For input string: \\"abcd\\""}""") + assert( + responseAs[ + String + ] == s"""{"result":null,"error":"For input string: \\"abcd\\""}""" + ) } } @@ -1075,20 +1212,24 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { "accept a dlc offer" in { (mockWalletApi - .acceptDLCOffer(_: DLCOfferTLV, - _: Option[InetSocketAddress], - _: Option[BitcoinAddress], - _: Option[BitcoinAddress])) + .acceptDLCOffer( + _: DLCOfferTLV, + _: Option[InetSocketAddress], + _: Option[BitcoinAddress], + _: Option[BitcoinAddress] + )) .expects(offer.toTLV, None, None, None) .returning(Future.successful(accept)) val route = walletRoutes.handleCommand( - ServerCommand("acceptdlcoffer", Arr(Str(LnMessage(offer.toTLV).hex)))) + ServerCommand("acceptdlcoffer", Arr(Str(LnMessage(offer.toTLV).hex))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert(responseAs[String] == s"""{"result":"${LnMessage( - accept.toTLV).hex}","error":null}""") + accept.toTLV + ).hex}","error":null}""") } } @@ -1107,12 +1248,14 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .returning(Future.successful(sign)) val route = walletRoutes.handleCommand( - ServerCommand("signdlc", Arr(Str(LnMessage(accept.toTLV).hex)))) + ServerCommand("signdlc", Arr(Str(LnMessage(accept.toTLV).hex))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert(responseAs[String] == s"""{"result":"${LnMessage( - sign.toTLV).hex}","error":null}""") + sign.toTLV + ).hex}","error":null}""") } } @@ -1120,16 +1263,23 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { (mockWalletApi .addDLCSigs(_: DLCSignTLV)) .expects(sign.toTLV) - .returning(Future.successful( - DLCWalletUtil.sampleDLCDb.copy(contractIdOpt = Some(contractId)))) + .returning( + Future.successful( + DLCWalletUtil.sampleDLCDb.copy(contractIdOpt = Some(contractId)) + ) + ) val route = walletRoutes.handleCommand( - ServerCommand("adddlcsigs", Arr(Str(LnMessage(sign.toTLV).hex)))) + ServerCommand("adddlcsigs", Arr(Str(LnMessage(sign.toTLV).hex))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) - assert(responseAs[ - String] == s"""{"result":"Successfully added sigs to DLC ${contractId.toHex}","error":null}""") + assert( + responseAs[ + String + ] == s"""{"result":"Successfully added sigs to DLC ${contractId.toHex}","error":null}""" + ) } } @@ -1137,8 +1287,11 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { (mockWalletApi .addDLCSigs(_: DLCSignTLV)) .expects(sign.toTLV) - .returning(Future.successful( - DLCWalletUtil.sampleDLCDb.copy(contractIdOpt = Some(contractId)))) + .returning( + Future.successful( + DLCWalletUtil.sampleDLCDb.copy(contractIdOpt = Some(contractId)) + ) + ) (mockWalletApi .broadcastDLCFundingTx(_: ByteVector)) @@ -1146,13 +1299,19 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .returning(Future.successful(EmptyTransaction)) val route = walletRoutes.handleCommand( - ServerCommand("adddlcsigsandbroadcast", - Arr(Str(LnMessage(sign.toTLV).hex)))) + ServerCommand( + "adddlcsigsandbroadcast", + Arr(Str(LnMessage(sign.toTLV).hex)) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":"${EmptyTransaction.txIdBE.hex}","error":null}""") + responseAs[ + String + ] == s"""{"result":"${EmptyTransaction.txIdBE.hex}","error":null}""" + ) } } @@ -1163,13 +1322,16 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .returning(Future.successful(EmptyTransaction)) val route = walletRoutes.handleCommand( - ServerCommand("getdlcfundingtx", Arr(Str(contractId.toHex)))) + ServerCommand("getdlcfundingtx", Arr(Str(contractId.toHex))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${EmptyTransaction.hex}","error":null}""") + String + ] == s"""{"result":"${EmptyTransaction.hex}","error":null}""" + ) } } @@ -1180,12 +1342,16 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .returning(Future.successful(EmptyTransaction)) val route = walletRoutes.handleCommand( - ServerCommand("broadcastdlcfundingtx", Arr(Str(contractId.toHex)))) + ServerCommand("broadcastdlcfundingtx", Arr(Str(contractId.toHex))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":"${EmptyTransaction.txIdBE.hex}","error":null}""") + responseAs[ + String + ] == s"""{"result":"${EmptyTransaction.txIdBE.hex}","error":null}""" + ) } } @@ -1196,16 +1362,23 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .returning(Future.successful(Some(EmptyTransaction))) val route = walletRoutes.handleCommand( - ServerCommand("executedlc", - Arr(Str(contractId.toHex), - Arr(Str(dummyOracleAttestment.hex)), - Bool(true)))) + ServerCommand( + "executedlc", + Arr( + Str(contractId.toHex), + Arr(Str(dummyOracleAttestment.hex)), + Bool(true) + ) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${EmptyTransaction.hex}","error":null}""") + String + ] == s"""{"result":"${EmptyTransaction.hex}","error":null}""" + ) } } @@ -1216,37 +1389,53 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .returning(Future.successful(None)) val route = walletRoutes.handleCommand( - ServerCommand("executedlc", - Arr(Str(contractId.toHex), - Arr(Str(dummyOracleAttestment.hex)), - Bool(true)))) + ServerCommand( + "executedlc", + Arr( + Str(contractId.toHex), + Arr(Str(dummyOracleAttestment.hex)), + Bool(true) + ) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":null,"error":"Cannot execute DLC with contractId=${contractId.toHex}"}""") + responseAs[ + String + ] == s"""{"result":null,"error":"Cannot execute DLC with contractId=${contractId.toHex}"}""" + ) } } "execute a dlc with multiple sigs" in { (mockWalletApi .executeDLC(_: ByteVector, _: Seq[OracleAttestmentTLV])) - .expects(contractId, - Vector(dummyOracleAttestment, dummyOracleAttestment)) + .expects( + contractId, + Vector(dummyOracleAttestment, dummyOracleAttestment) + ) .returning(Future.successful(Some(EmptyTransaction))) val route = walletRoutes.handleCommand( - ServerCommand("executedlc", - Arr(Str(contractId.toHex), - Arr(Str(dummyOracleAttestment.hex), - Str(dummyOracleAttestment.hex)), - Bool(true)))) + ServerCommand( + "executedlc", + Arr( + Str(contractId.toHex), + Arr(Str(dummyOracleAttestment.hex), Str(dummyOracleAttestment.hex)), + Bool(true) + ) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${EmptyTransaction.hex}","error":null}""") + String + ] == s"""{"result":"${EmptyTransaction.hex}","error":null}""" + ) } } @@ -1262,15 +1451,23 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .anyNumberOfTimes() val route = walletRoutes.handleCommand( - ServerCommand("executedlc", - Arr(Str(contractId.toHex), - Arr(Str(dummyOracleAttestment.hex)), - Bool(false)))) + ServerCommand( + "executedlc", + Arr( + Str(contractId.toHex), + Arr(Str(dummyOracleAttestment.hex)), + Bool(false) + ) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":"${EmptyTransaction.txIdBE.hex}","error":null}""") + responseAs[ + String + ] == s"""{"result":"${EmptyTransaction.txIdBE.hex}","error":null}""" + ) } } @@ -1281,14 +1478,19 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .returning(Future.successful(EmptyTransaction)) val route = walletRoutes.handleCommand( - ServerCommand("executedlcrefund", - Arr(Str(contractId.toHex), Bool(true)))) + ServerCommand( + "executedlcrefund", + Arr(Str(contractId.toHex), Bool(true)) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${EmptyTransaction.hex}","error":null}""") + String + ] == s"""{"result":"${EmptyTransaction.hex}","error":null}""" + ) } } @@ -1304,13 +1506,19 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .anyNumberOfTimes() val route = walletRoutes.handleCommand( - ServerCommand("executedlcrefund", - Arr(Str(contractId.toHex), Bool(false)))) + ServerCommand( + "executedlcrefund", + Arr(Str(contractId.toHex), Bool(false)) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == s"""{"result":"${EmptyTransaction.txIdBE.hex}","error":null}""") + responseAs[ + String + ] == s"""{"result":"${EmptyTransaction.txIdBE.hex}","error":null}""" + ) } } @@ -1319,7 +1527,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { (mockWalletApi .sendToAddress(_: BitcoinAddress, _: CurrencyUnit, _: Option[FeeUnit])( - _: ExecutionContext)) + _: ExecutionContext + )) .expects(testAddress, Bitcoins(100), *, executor) .returning(Future.successful(EmptyTransaction)) @@ -1329,57 +1538,77 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .anyNumberOfTimes() val route = walletRoutes.handleCommand( - ServerCommand("sendtoaddress", - Arr(Str(testAddressStr), Num(100), Num(4), Bool(false)))) + ServerCommand( + "sendtoaddress", + Arr(Str(testAddressStr), Num(100), Num(4), Bool(false)) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""") + responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""" + ) } // negative cases val route1 = walletRoutes.handleCommand( - ServerCommand("sendtoaddress", Arr(Null, Null, Null, Bool(false)))) + ServerCommand("sendtoaddress", Arr(Null, Null, Null, Bool(false))) + ) Post() ~> route1 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Str (data: null)"}""") + responseAs[ + String + ] == s"""{"result":null,"error":"Expected ujson.Str (data: null)"}""" + ) } val route2 = walletRoutes.handleCommand( - ServerCommand("sendtoaddress", Arr("Null", Null, Null, Bool(false)))) + ServerCommand("sendtoaddress", Arr("Null", Null, Null, Bool(false))) + ) Post() ~> route2 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected a valid address (data: \\"Null\\")"}""") + responseAs[String] == s"""{"result":null,"error":"Expected a valid address (data: \\"Null\\")"}""" + ) } val route3 = walletRoutes.handleCommand( - ServerCommand("sendtoaddress", - Arr(Str(testAddressStr), Null, Null, Bool(false)))) + ServerCommand( + "sendtoaddress", + Arr(Str(testAddressStr), Null, Null, Bool(false)) + ) + ) Post() ~> route3 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Num (data: null)"}""") + responseAs[ + String + ] == s"""{"result":null,"error":"Expected ujson.Num (data: null)"}""" + ) } val route4 = walletRoutes.handleCommand( - ServerCommand("sendtoaddress", - Arr(Str(testAddressStr), Str("abc"), Null, Bool(false)))) + ServerCommand( + "sendtoaddress", + Arr(Str(testAddressStr), Str("abc"), Null, Bool(false)) + ) + ) Post() ~> route4 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Num (data: \\"abc\\")"}""") + responseAs[String] == s"""{"result":null,"error":"Expected ujson.Num (data: \\"abc\\")"}""" + ) } } @@ -1388,15 +1617,19 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { // positive cases (mockWalletApi - .sendFromOutPoints(_: Vector[TransactionOutPoint], - _: BitcoinAddress, - _: CurrencyUnit, - _: Option[FeeUnit])(_: ExecutionContext)) - .expects(Vector.empty[TransactionOutPoint], - testAddress, - Bitcoins(100), - *, - executor) + .sendFromOutPoints( + _: Vector[TransactionOutPoint], + _: BitcoinAddress, + _: CurrencyUnit, + _: Option[FeeUnit] + )(_: ExecutionContext)) + .expects( + Vector.empty[TransactionOutPoint], + testAddress, + Bitcoins(100), + *, + executor + ) .returning(Future.successful(EmptyTransaction)) (mockWalletApi.broadcastTransaction _) @@ -1405,75 +1638,102 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .anyNumberOfTimes() val route = walletRoutes.handleCommand( - ServerCommand("sendfromoutpoints", - Arr(Arr(), Str(testAddressStr), Num(100), Num(4)))) + ServerCommand( + "sendfromoutpoints", + Arr(Arr(), Str(testAddressStr), Num(100), Num(4)) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""") + responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""" + ) } // negative cases val route1 = walletRoutes.handleCommand( - ServerCommand("sendfromoutpoints", Arr(Arr(), Null, Null, Null))) + ServerCommand("sendfromoutpoints", Arr(Arr(), Null, Null, Null)) + ) Post() ~> route1 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Str (data: null)"}""") + responseAs[ + String + ] == s"""{"result":null,"error":"Expected ujson.Str (data: null)"}""" + ) } val route2 = walletRoutes.handleCommand( - ServerCommand("sendfromoutpoints", Arr(Arr(), "Null", Null, Null))) + ServerCommand("sendfromoutpoints", Arr(Arr(), "Null", Null, Null)) + ) Post() ~> route2 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected a valid address (data: \\"Null\\")"}""") + responseAs[String] == s"""{"result":null,"error":"Expected a valid address (data: \\"Null\\")"}""" + ) } val route3 = walletRoutes.handleCommand( - ServerCommand("sendfromoutpoints", - Arr(Arr(), Str(testAddressStr), Null, Null))) + ServerCommand( + "sendfromoutpoints", + Arr(Arr(), Str(testAddressStr), Null, Null) + ) + ) Post() ~> route3 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Num (data: null)"}""") + responseAs[ + String + ] == s"""{"result":null,"error":"Expected ujson.Num (data: null)"}""" + ) } val route4 = walletRoutes.handleCommand( - ServerCommand("sendfromoutpoints", - Arr(Arr(), Str(testAddressStr), Str("abc"), Null))) + ServerCommand( + "sendfromoutpoints", + Arr(Arr(), Str(testAddressStr), Str("abc"), Null) + ) + ) Post() ~> route4 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Num (data: \\"abc\\")"}""") + responseAs[String] == s"""{"result":null,"error":"Expected ujson.Num (data: \\"abc\\")"}""" + ) } val route5 = walletRoutes.handleCommand( - ServerCommand("sendfromoutpoints", - Arr(Null, Str(testAddressStr), Num(100), Num(4)))) + ServerCommand( + "sendfromoutpoints", + Arr(Null, Str(testAddressStr), Num(100), Num(4)) + ) + ) Post() ~> route5 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Arr (data: null)"}""") + responseAs[ + String + ] == s"""{"result":null,"error":"Expected ujson.Arr (data: null)"}""" + ) } } "sweep wallet" in { (mockWalletApi .sweepWallet(_: BitcoinAddress, _: Option[FeeUnit])( - _: ExecutionContext)) + _: ExecutionContext + )) .expects(testAddress, *, executor) .returning(Future.successful(EmptyTransaction)) @@ -1483,12 +1743,14 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .anyNumberOfTimes() val route = walletRoutes.handleCommand( - ServerCommand("sweepwallet", Arr(Str(testAddressStr), Num(4)))) + ServerCommand("sweepwallet", Arr(Str(testAddressStr), Num(4))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""") + responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""" + ) } } @@ -1496,15 +1758,19 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { // positive cases (mockWalletApi - .sendWithAlgo(_: BitcoinAddress, - _: CurrencyUnit, - _: Option[FeeUnit], - _: CoinSelectionAlgo)(_: ExecutionContext)) - .expects(testAddress, - Bitcoins(100), - Some(SatoshisPerVirtualByte(Satoshis(4))), - CoinSelectionAlgo.AccumulateSmallestViable, - executor) + .sendWithAlgo( + _: BitcoinAddress, + _: CurrencyUnit, + _: Option[FeeUnit], + _: CoinSelectionAlgo + )(_: ExecutionContext)) + .expects( + testAddress, + Bitcoins(100), + Some(SatoshisPerVirtualByte(Satoshis(4))), + CoinSelectionAlgo.AccumulateSmallestViable, + executor + ) .returning(Future.successful(EmptyTransaction)) (mockWalletApi.broadcastTransaction _) @@ -1513,77 +1779,106 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .anyNumberOfTimes() val route = walletRoutes.handleCommand( - ServerCommand("sendwithalgo", - Arr(Str(testAddressStr), - Num(100), - Num(4), - Str("AccumulateSmallestViable")))) + ServerCommand( + "sendwithalgo", + Arr( + Str(testAddressStr), + Num(100), + Num(4), + Str("AccumulateSmallestViable") + ) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""") + responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""" + ) } // negative cases val route1 = walletRoutes.handleCommand( - ServerCommand("sendwithalgo", Arr(Null, Null, Null, Null))) + ServerCommand("sendwithalgo", Arr(Null, Null, Null, Null)) + ) Post() ~> route1 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Str (data: null)"}""") + responseAs[ + String + ] == s"""{"result":null,"error":"Expected ujson.Str (data: null)"}""" + ) } val route2 = walletRoutes.handleCommand( - ServerCommand("sendwithalgo", Arr("Null", Null, Null, Null))) + ServerCommand("sendwithalgo", Arr("Null", Null, Null, Null)) + ) Post() ~> route2 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected a valid address (data: \\"Null\\")"}""") + responseAs[String] == s"""{"result":null,"error":"Expected a valid address (data: \\"Null\\")"}""" + ) } val route3 = walletRoutes.handleCommand( - ServerCommand("sendwithalgo", - Arr(Str(testAddressStr), Null, Null, Null))) + ServerCommand( + "sendwithalgo", + Arr(Str(testAddressStr), Null, Null, Null) + ) + ) Post() ~> route3 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Num (data: null)"}""") + responseAs[ + String + ] == s"""{"result":null,"error":"Expected ujson.Num (data: null)"}""" + ) } val route4 = walletRoutes.handleCommand( - ServerCommand("sendwithalgo", - Arr(Str(testAddressStr), Str("abc"), Null, Null))) + ServerCommand( + "sendwithalgo", + Arr(Str(testAddressStr), Str("abc"), Null, Null) + ) + ) Post() ~> route4 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Num (data: \\"abc\\")"}""") + responseAs[String] == s"""{"result":null,"error":"Expected ujson.Num (data: \\"abc\\")"}""" + ) } val route5 = walletRoutes.handleCommand( - ServerCommand("sendwithalgo", - Arr(Str(testAddressStr), Num(100), Num(4), Null))) + ServerCommand( + "sendwithalgo", + Arr(Str(testAddressStr), Num(100), Num(4), Null) + ) + ) Post() ~> route5 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected ujson.Str (data: null)"}""") + responseAs[ + String + ] == s"""{"result":null,"error":"Expected ujson.Str (data: null)"}""" + ) } } "sign a psbt" in { val tx = Transaction( - "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000") + "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000" + ) (mockWalletApi .signPSBT(_: PSBT)(_: ExecutionContext)) @@ -1593,13 +1888,14 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { val route = walletRoutes.handleCommand( - ServerCommand("signpsbt", Arr(Str(PSBT.empty.hex)))) + ServerCommand("signpsbt", Arr(Str(PSBT.empty.hex))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert(responseAs[String] == s"""{"result":"${PSBT - .fromUnsignedTx(tx) - .base64}","error":null}""") + .fromUnsignedTx(tx) + .base64}","error":null}""") } } @@ -1609,7 +1905,8 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { (mockWalletApi .makeOpReturnCommitment(_: String, _: Boolean, _: Option[FeeUnit])( - _: ExecutionContext)) + _: ExecutionContext + )) .expects(message, false, *, executor) .returning(Future.successful(EmptyTransaction)) @@ -1619,12 +1916,14 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .anyNumberOfTimes() val route = walletRoutes.handleCommand( - ServerCommand("opreturncommit", Arr(message, Bool(false), Num(4)))) + ServerCommand("opreturncommit", Arr(message, Bool(false), Num(4))) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""") + responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""" + ) } } @@ -1640,13 +1939,17 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .anyNumberOfTimes() val route = walletRoutes.handleCommand( - ServerCommand("bumpfeerbf", - Arr(Str(DoubleSha256DigestBE.empty.hex), Num(1)))) + ServerCommand( + "bumpfeerbf", + Arr(Str(DoubleSha256DigestBE.empty.hex), Num(1)) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""") + responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""" + ) } } @@ -1662,30 +1965,40 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .anyNumberOfTimes() val route = walletRoutes.handleCommand( - ServerCommand("bumpfeecpfp", - Arr(Str(DoubleSha256DigestBE.empty.hex), Num(1)))) + ServerCommand( + "bumpfeecpfp", + Arr(Str(DoubleSha256DigestBE.empty.hex), Num(1)) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""") + responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""" + ) } } "create multisig" in { val key1 = ECPublicKey( - "0369c68f212ecaf3b3be52acb158a6fd87e469bc08726ef98a3b58401b75da3392") + "0369c68f212ecaf3b3be52acb158a6fd87e469bc08726ef98a3b58401b75da3392" + ) val key2 = ECPublicKey( - "02c23222c46b96c5976930319cc4915791fdf5e1ad1203790ff98cb1e7517eed4a") + "02c23222c46b96c5976930319cc4915791fdf5e1ad1203790ff98cb1e7517eed4a" + ) val route = coreRoutes.handleCommand( - ServerCommand("createmultisig", - Arr(Num(1), Arr(Str(key1.hex), Str(key2.hex))))) + ServerCommand( + "createmultisig", + Arr(Num(1), Arr(Str(key1.hex), Str(key2.hex))) + ) + ) Post() ~> route ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":{"address":"bcrt1qjtsq4h0thsy0qftjdfxldxwa4tph7kwuplj6nglvvyehduagqqnssf4l0c","redeemScript":"47512102c23222c46b96c5976930319cc4915791fdf5e1ad1203790ff98cb1e7517eed4a210369c68f212ecaf3b3be52acb158a6fd87e469bc08726ef98a3b58401b75da339252ae"},"error":null}""") + responseAs[String] == """{"result":{"address":"bcrt1qjtsq4h0thsy0qftjdfxldxwa4tph7kwuplj6nglvvyehduagqqnssf4l0c","redeemScript":"47512102c23222c46b96c5976930319cc4915791fdf5e1ad1203790ff98cb1e7517eed4a210369c68f212ecaf3b3be52acb158a6fd87e469bc08726ef98a3b58401b75da339252ae"},"error":null}""" + ) } } @@ -1697,7 +2010,9 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { assert(contentType == `application/json`) assert( responseAs[ - String] == """{"result":"TODO implement getpeers","error":null}""") + String + ] == """{"result":"TODO implement getpeers","error":null}""" + ) } } @@ -1709,135 +2024,181 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { .returning(100) .atLeastOnce() (mockWalletApi - .rescanNeutrinoWallet(_: Option[BlockStamp], - _: Option[BlockStamp], - _: Int, - _: Boolean, - _: Boolean)(_: ExecutionContext)) + .rescanNeutrinoWallet( + _: Option[BlockStamp], + _: Option[BlockStamp], + _: Int, + _: Boolean, + _: Boolean + )(_: ExecutionContext)) .expects(None, None, 100, false, false, executor) .returning( Future.successful( RescanState - .RescanStarted(Promise(), - Future.successful(Vector.empty), - Promise()))) + .RescanStarted( + Promise(), + Future.successful(Vector.empty), + Promise() + ) + ) + ) walletLoader.clearRescanState() val route1 = walletRoutes.handleCommand( - ServerCommand("rescan", Arr(Arr(), Null, Null, true, true))) + ServerCommand("rescan", Arr(Arr(), Null, Null, true, true)) + ) Post() ~> route1 ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"Rescan started.","error":null}""") + responseAs[String] == """{"result":"Rescan started.","error":null}""" + ) } (mockWalletApi - .rescanNeutrinoWallet(_: Option[BlockStamp], - _: Option[BlockStamp], - _: Int, - _: Boolean, - _: Boolean)(_: ExecutionContext)) + .rescanNeutrinoWallet( + _: Option[BlockStamp], + _: Option[BlockStamp], + _: Int, + _: Boolean, + _: Boolean + )(_: ExecutionContext)) .expects( - Some(BlockTime( - ZonedDateTime.of(2018, 10, 27, 12, 34, 56, 0, ZoneId.of("UTC")))), + Some( + BlockTime( + ZonedDateTime.of(2018, 10, 27, 12, 34, 56, 0, ZoneId.of("UTC")) + ) + ), None, 100, false, false, - executor) + executor + ) .returning( Future.successful( RescanState - .RescanStarted(Promise(), - Future.successful(Vector.empty), - Promise()))) + .RescanStarted( + Promise(), + Future.successful(Vector.empty), + Promise() + ) + ) + ) walletLoader.clearRescanState() val route2 = walletRoutes.handleCommand( ServerCommand( "rescan", - Arr(Arr(), Str("2018-10-27T12:34:56Z"), Null, true, true))) + Arr(Arr(), Str("2018-10-27T12:34:56Z"), Null, true, true) + ) + ) Post() ~> route2 ~> check { assert( - responseAs[String] == """{"result":"Rescan started.","error":null}""") + responseAs[String] == """{"result":"Rescan started.","error":null}""" + ) assert(contentType == `application/json`) } (mockWalletApi - .rescanNeutrinoWallet(_: Option[BlockStamp], - _: Option[BlockStamp], - _: Int, - _: Boolean, - _: Boolean)(_: ExecutionContext)) - .expects(None, - Some(BlockHash(DoubleSha256DigestBE.empty)), - 100, - false, - false, - executor) + .rescanNeutrinoWallet( + _: Option[BlockStamp], + _: Option[BlockStamp], + _: Int, + _: Boolean, + _: Boolean + )(_: ExecutionContext)) + .expects( + None, + Some(BlockHash(DoubleSha256DigestBE.empty)), + 100, + false, + false, + executor + ) .returning( Future.successful( RescanState - .RescanStarted(Promise(), - Future.successful(Vector.empty), - Promise()))) + .RescanStarted( + Promise(), + Future.successful(Vector.empty), + Promise() + ) + ) + ) walletLoader.clearRescanState() val route3 = walletRoutes.handleCommand( ServerCommand( "rescan", - Arr(Null, Null, Str(DoubleSha256DigestBE.empty.hex), true, true))) + Arr(Null, Null, Str(DoubleSha256DigestBE.empty.hex), true, true) + ) + ) Post() ~> route3 ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"Rescan started.","error":null}""") + responseAs[String] == """{"result":"Rescan started.","error":null}""" + ) } (mockWalletApi - .rescanNeutrinoWallet(_: Option[BlockStamp], - _: Option[BlockStamp], - _: Int, - _: Boolean, - _: Boolean)(_: ExecutionContext)) - .expects(Some(BlockHeight(12345)), - Some(BlockHeight(67890)), - 100, - false, - false, - executor) + .rescanNeutrinoWallet( + _: Option[BlockStamp], + _: Option[BlockStamp], + _: Int, + _: Boolean, + _: Boolean + )(_: ExecutionContext)) + .expects( + Some(BlockHeight(12345)), + Some(BlockHeight(67890)), + 100, + false, + false, + executor + ) .returning(Future.successful(RescanState.RescanDone)) walletLoader.clearRescanState() val route4 = walletRoutes.handleCommand( - ServerCommand("rescan", - Arr(Arr(), Str("12345"), Num(67890), true, true))) + ServerCommand( + "rescan", + Arr(Arr(), Str("12345"), Num(67890), true, true) + ) + ) Post() ~> route4 ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"Rescan done.","error":null}""") + responseAs[String] == """{"result":"Rescan done.","error":null}""" + ) } // negative cases walletLoader.clearRescanState() val route5 = walletRoutes.handleCommand( - ServerCommand("rescan", - Arr(Null, Str("abcd"), Str("efgh"), true, true))) + ServerCommand( + "rescan", + Arr(Null, Str("abcd"), Str("efgh"), true, true) + ) + ) Post() ~> route5 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) - assert(responseAs[ - String] == s"""{"result":null,"error":"Invalid blockstamp: abcd"}""") + assert( + responseAs[ + String + ] == s"""{"result":null,"error":"Invalid blockstamp: abcd"}""" + ) } walletLoader.clearRescanState() @@ -1845,61 +2206,75 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory { walletRoutes.handleCommand( ServerCommand( "rescan", - Arr(Arr(55), Null, Str("2018-10-27T12:34:56"), true, true))) + Arr(Arr(55), Null, Str("2018-10-27T12:34:56"), true, true) + ) + ) Post() ~> route6 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Invalid blockstamp: 2018-10-27T12:34:56"}""") + responseAs[String] == s"""{"result":null,"error":"Invalid blockstamp: 2018-10-27T12:34:56"}""" + ) } walletLoader.clearRescanState() val route7 = walletRoutes.handleCommand( - ServerCommand("rescan", Arr(Null, Num(-1), Null, true, false))) + ServerCommand("rescan", Arr(Null, Num(-1), Null, true, false)) + ) Post() ~> route7 ~> check { assert(contentType == `application/json`) assert(status == StatusCodes.BadRequest) assert( - responseAs[String] == s"""{"result":null,"error":"Expected a positive integer (data: -1)"}""") + responseAs[String] == s"""{"result":null,"error":"Expected a positive integer (data: -1)"}""" + ) } (mockWalletApi - .rescanNeutrinoWallet(_: Option[BlockStamp], - _: Option[BlockStamp], - _: Int, - _: Boolean, - _: Boolean)(_: ExecutionContext)) + .rescanNeutrinoWallet( + _: Option[BlockStamp], + _: Option[BlockStamp], + _: Int, + _: Boolean, + _: Boolean + )(_: ExecutionContext)) .expects(None, None, 55, false, false, executor) .returning(Future.successful(RescanState.RescanDone)) walletLoader.clearRescanState() val route8 = walletRoutes.handleCommand( - ServerCommand("rescan", - Arr(Arr(55), Arr(), Arr(), Bool(true), Bool(true)))) + ServerCommand( + "rescan", + Arr(Arr(55), Arr(), Arr(), Bool(true), Bool(true)) + ) + ) Post() ~> route8 ~> check { assert(contentType == `application/json`) assert( - responseAs[String] == """{"result":"Rescan done.","error":null}""") + responseAs[String] == """{"result":"Rescan done.","error":null}""" + ) } } "get wallet accounting" in { - val accounting = DLCWalletAccounting(myCollateral = Satoshis.one, - theirCollateral = Satoshis.one, - myPayout = Satoshis(2), - theirPayout = Satoshis.zero) + val accounting = DLCWalletAccounting( + myCollateral = Satoshis.one, + theirCollateral = Satoshis.one, + myPayout = Satoshis(2), + theirPayout = Satoshis.zero + ) (() => mockWalletApi.getWalletAccounting()) .expects() .returning(Future.successful(accounting)) val route = walletRoutes.handleCommand( - ServerCommand("getdlcwalletaccounting", Arr())) + ServerCommand("getdlcwalletaccounting", Arr()) + ) Get() ~> route ~> check { assert(contentType == `application/json`) diff --git a/app/server-test/src/test/scala/org/bitcoins/server/ServerRunTest.scala b/app/server-test/src/test/scala/org/bitcoins/server/ServerRunTest.scala index c181804771..414d9c9d21 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/ServerRunTest.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/ServerRunTest.scala @@ -18,8 +18,8 @@ class ServerRunTest extends BitcoinSAsyncTest { // Note: on this test passing it will output a stack trace // because runMain calls err.printStackTrace() on failure it must "throw errors" in { - //custom configuration to make peers empty - //this should cause an exception in startBitcoinSBackend() + // custom configuration to make peers empty + // this should cause an exception in startBitcoinSBackend() val noPeersConfig = ConfigFactory.parseString(s"""bitcoin-s.node.peers=[]""") implicit val config = @@ -27,10 +27,12 @@ class ServerRunTest extends BitcoinSAsyncTest { val datadir = config.chainConf.datadir val invalidPort = -1 - val args = Vector("--datadir", - datadir.toAbsolutePath.toString, - "--rpcport", - invalidPort.toString) + val args = Vector( + "--datadir", + datadir.toAbsolutePath.toString, + "--rpcport", + invalidPort.toString + ) val serverArgParser = ServerArgParser(args) val main = new BitcoinSServerMain(serverArgParser) diff --git a/app/server-test/src/test/scala/org/bitcoins/server/WalletRoutesSpec.scala b/app/server-test/src/test/scala/org/bitcoins/server/WalletRoutesSpec.scala index 3b0c64d6f6..a7d4787984 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/WalletRoutesSpec.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/WalletRoutesSpec.scala @@ -40,10 +40,12 @@ class WalletRoutesSpec val feeRateApi = ConstantFeeRateProvider(SatoshisPerVirtualByte.one) val walletLoader: DLCWalletNeutrinoBackendLoader = - DLCWalletNeutrinoBackendLoader(walletHolder, - mockChainApi, - mockNode, - feeRateApi) + DLCWalletNeutrinoBackendLoader( + walletHolder, + mockChainApi, + mockNode, + feeRateApi + ) val walletRoutes: WalletRoutes = WalletRoutes(walletLoader)(system, conf.walletConf) @@ -101,7 +103,8 @@ class WalletRoutesSpec ) (mockWalletApi.findDLCByTemporaryContractId: Sha256Digest => Future[ - Option[DLCStatus]]) + Option[DLCStatus] + ]) .expects(tempContractId) .returning(Future.successful(Some(status))) (mockWalletApi.getDLCOffer: Sha256Digest => Future[Option[DLCOffer]]) @@ -110,7 +113,8 @@ class WalletRoutesSpec val route = walletRoutes.handleCommand( - ServerCommand("getdlcoffer", ujson.Arr(tempContractId.hex))) + ServerCommand("getdlcoffer", ujson.Arr(tempContractId.hex)) + ) Get() ~> route ~> check { assert(contentType == `application/json`) @@ -127,23 +131,28 @@ class WalletRoutesSpec LnMessage(TLVGen.dlcAcceptTLV(offer.toTLV).sampleSome) val acceptTLV = DLCAccept.fromTLV(dummyAcceptLnMsg.tlv, offer) (mockWalletApi - .acceptDLCOffer(_: DLCOfferTLV, - _: Option[InetSocketAddress], - _: Option[BitcoinAddress], - _: Option[BitcoinAddress])) + .acceptDLCOffer( + _: DLCOfferTLV, + _: Option[InetSocketAddress], + _: Option[BitcoinAddress], + _: Option[BitcoinAddress] + )) .expects(expectedTlv, None, None, None) .returning(Future.successful(acceptTLV)) val cmd = ServerCommand( "acceptdlcoffer", - ujson.Arr(ujson.Str(tlv), ujson.Null, ujson.Null, ujson.Null)) + ujson.Arr(ujson.Str(tlv), ujson.Null, ujson.Null, ujson.Null) + ) val route = walletRoutes.handleCommand(cmd) Get() ~> route ~> check { assert(contentType == `application/json`) assert( responseAs[ - String] == s"""{"result":"${dummyAcceptLnMsg.hex}","error":null}""") + String + ] == s"""{"result":"${dummyAcceptLnMsg.hex}","error":null}""" + ) } } } diff --git a/app/server-test/src/test/scala/org/bitcoins/server/WebsocketTests.scala b/app/server-test/src/test/scala/org/bitcoins/server/WebsocketTests.scala index c4f31e989b..58197d6296 100644 --- a/app/server-test/src/test/scala/org/bitcoins/server/WebsocketTests.scala +++ b/app/server-test/src/test/scala/org/bitcoins/server/WebsocketTests.scala @@ -56,19 +56,26 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { val sink: Sink[Message, Future[Seq[WsNotification[_]]]] = Flow[Message] .map { case message: TextMessage.Strict => - //we should be able to parse the address message + // we should be able to parse the address message val text = message.text val dlcNodeNotificationOpt: Option[DLCNodeNotification[_]] = Try( upickle.default.read[DLCNodeNotification[_]](text)( - WsPicklers.dlcNodeNotificationPickler)).toOption + WsPicklers.dlcNodeNotificationPickler + ) + ).toOption val walletNotificationOpt: Option[WalletNotification[_]] = Try( upickle.default.read[WalletNotification[_]](text)( - WsPicklers.walletNotificationPickler)).toOption + WsPicklers.walletNotificationPickler + ) + ).toOption val chainNotificationOpt: Option[ChainNotification[_]] = Try( upickle.default.read[ChainNotification[_]](text)( - WsPicklers.chainNotificationPickler)).toOption + WsPicklers.chainNotificationPickler + ) + ).toOption walletNotificationOpt.getOrElse( - chainNotificationOpt.getOrElse(dlcNodeNotificationOpt.get)) + chainNotificationOpt.getOrElse(dlcNodeNotificationOpt.get) + ) case msg => fail(s"Unexpected msg type received in the sink, msg=$msg") } @@ -76,19 +83,27 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { def buildReq( conf: BitcoinSAppConfig, - rpcPassword: Option[String] = None): WebSocketRequest = { + rpcPassword: Option[String] = None + ): WebSocketRequest = { val headers: Vector[HttpHeader] = Vector( Authorization( - BasicHttpCredentials("bitcoins", - rpcPassword.getOrElse(conf.rpcPassword)))) - WebSocketRequest(s"ws://localhost:${conf.wsPort}/events", - extraHeaders = headers) + BasicHttpCredentials( + "bitcoins", + rpcPassword.getOrElse(conf.rpcPassword) + ) + ) + ) + WebSocketRequest( + s"ws://localhost:${conf.wsPort}/events", + extraHeaders = headers + ) } val websocketFlow: Flow[ Message, Message, - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])] = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ] = { Flow .fromSinkAndSourceCoupledMat(sink, Source.maybe[Message])(Keep.both) } @@ -133,26 +148,32 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { } yield { assert(response.response.status == StatusCodes.Unauthorized) - val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort), - rpcPassword = "wrong password") + val cliConfig = Config( + rpcPortOpt = Some(server.conf.rpcPort), + rpcPassword = "wrong password" + ) val cliResponse = exec(GetNewAddress(labelOpt = None), cliConfig) assert(cliResponse.isFailure) assert( - cliResponse.failed.get.getMessage == "The supplied authentication is invalid") + cliResponse.failed.get.getMessage == "The supplied authentication is invalid" + ) } } it must "receive updates when an address is generated" in { serverWithBitcoind => val ServerWithBitcoind(_, server) = serverWithBitcoind - val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort), - rpcPassword = server.conf.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(server.conf.rpcPort), + rpcPassword = server.conf.rpcPassword + ) val req = buildReq(server.conf) val notificationsF: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } @@ -171,20 +192,24 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { notifications <- walletNotificationsF } yield { assert( - notifications.exists(_ == NewAddressNotification(expectedAddress))) + notifications.exists(_ == NewAddressNotification(expectedAddress)) + ) } } it must "receive updates when a transaction is broadcast" in { serverWithBitcoind => val ServerWithBitcoind(bitcoind, server) = serverWithBitcoind - val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort), - rpcPassword = server.conf.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(server.conf.rpcPort), + rpcPassword = server.conf.rpcPassword + ) val req = buildReq(server.conf) val tuple: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } @@ -196,11 +221,12 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { for { address <- addressF - cmd = SendToAddress(destination = address, - amount = Bitcoins.one, - satoshisPerVirtualByte = - Some(SatoshisPerVirtualByte.one), - noBroadcast = false) + cmd = SendToAddress( + destination = address, + amount = Bitcoins.one, + satoshisPerVirtualByte = Some(SatoshisPerVirtualByte.one), + noBroadcast = false + ) txIdStr = ConsoleCli.exec(cmd, cliConfig) expectedTxId = DoubleSha256DigestBE.fromHex(txIdStr.get) getTxCmd = GetTransaction(expectedTxId) @@ -217,13 +243,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { it must "receive updates when a transaction is processed" in { serverWithBitcoind => val ServerWithBitcoind(bitcoind, server) = serverWithBitcoind - val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort), - rpcPassword = server.conf.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(server.conf.rpcPort), + rpcPassword = server.conf.rpcPassword + ) val req = buildReq(server.conf) val tuple: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } @@ -235,11 +264,12 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { for { address <- addressF - cmd = SendToAddress(destination = address, - amount = Bitcoins.one, - satoshisPerVirtualByte = - Some(SatoshisPerVirtualByte.one), - noBroadcast = false) + cmd = SendToAddress( + destination = address, + amount = Bitcoins.one, + satoshisPerVirtualByte = Some(SatoshisPerVirtualByte.one), + noBroadcast = false + ) txIdStr = ConsoleCli.exec(cmd, cliConfig) expectedTxId = DoubleSha256DigestBE.fromHex(txIdStr.get) getTxCmd = GetTransaction(expectedTxId) @@ -255,13 +285,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { it must "receive updates when a block is processed" in { serverWithBitcoind => val ServerWithBitcoind(bitcoind, server) = serverWithBitcoind - val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort), - rpcPassword = server.conf.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(server.conf.rpcPort), + rpcPassword = server.conf.rpcPassword + ) val req = buildReq(server.conf) val tuple: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } @@ -271,20 +304,22 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { val addressF = bitcoind.getNewAddress val timeout = - 15.seconds //any way we can remove this timeout and just check? + 15.seconds // any way we can remove this timeout and just check? for { address <- addressF hashes <- bitcoind.generateToAddress(1, address) cmd = GetBlockHeader(hash = hashes.head) getBlockHeaderResultStr = ConsoleCli.exec(cmd, cliConfig) getBlockHeaderResult = upickle.default.read(getBlockHeaderResultStr.get)( - Picklers.getBlockHeaderResultPickler) + Picklers.getBlockHeaderResultPickler + ) _ <- PekkoUtil.nonBlockingSleep(timeout) _ = promise.success(None) notifications <- notificationsF } yield { val count = notifications.count( - _ == BlockProcessedNotification(getBlockHeaderResult)) + _ == BlockProcessedNotification(getBlockHeaderResult) + ) assert(count == 1, s"count=$count") } } @@ -292,13 +327,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { it must "get notifications for reserving and unreserving utxos" in { serverWithBitcoind => val ServerWithBitcoind(_, server) = serverWithBitcoind - val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort), - rpcPassword = server.conf.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(server.conf.rpcPort), + rpcPassword = server.conf.rpcPassword + ) val req = buildReq(server.conf) val tuple: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } @@ -306,11 +344,11 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { val notificationsF: Future[Seq[WsNotification[_]]] = tuple._2._1 val promise = tuple._2._2 - //lock all utxos + // lock all utxos val lockCmd = LockUnspent(unlock = false, Vector.empty) ConsoleCli.exec(lockCmd, cliConfig) - //unlock all utxos + // unlock all utxos val unlockCmd = LockUnspent(unlock = true, Vector.empty) ConsoleCli.exec(unlockCmd, cliConfig) @@ -319,7 +357,7 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { _ = promise.success(None) notifications <- notificationsF } yield { - //should have two notifications for locking and then unlocking the utxos + // should have two notifications for locking and then unlocking the utxos assert(notifications.count(_.`type` == WalletWsType.ReservedUtxos) == 2) } } @@ -327,13 +365,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { it must "receive updates when an offer is added and removed" in { serverWithBitcoind => val ServerWithBitcoind(_, server) = serverWithBitcoind - val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort), - rpcPassword = server.conf.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(server.conf.rpcPort), + rpcPassword = server.conf.rpcPassword + ) val req = buildReq(server.conf) val notificationsF: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } @@ -348,7 +389,8 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { ConsoleCli .exec( CliCommand.AddDLCOffer(offer = offer, message = "msg", peer = "uri"), - cliConfig) + cliConfig + ) .get ConsoleCli @@ -376,23 +418,28 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { it must "receive updates when a rescan is complete" in { serverWithBitcoind => val ServerWithBitcoind(_, server) = serverWithBitcoind - val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort), - rpcPassword = server.conf.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(server.conf.rpcPort), + rpcPassword = server.conf.rpcPassword + ) val req = buildReq(server.conf) val tuple: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } val notificationsF = tuple._2._1 val promise = tuple._2._2 - val cmd = Rescan(batchSize = None, - startBlock = None, - endBlock = None, - force = true, - ignoreCreationTime = false) + val cmd = Rescan( + batchSize = None, + startBlock = None, + endBlock = None, + force = true, + ignoreCreationTime = false + ) val _ = ConsoleCli.exec(cmd, cliConfig) for { _ <- PekkoUtil.nonBlockingSleep(10.second) @@ -410,7 +457,8 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { val req = buildReq(server.conf) val tuple: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } @@ -434,7 +482,8 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { val req = buildReq(server.conf) val tuple: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } @@ -453,13 +502,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { it must "receive dlc node updates" in { serverWithBitcoind => val ServerWithBitcoind(_, server) = serverWithBitcoind - val cliConfig = Config(rpcPortOpt = Some(server.conf.rpcPort), - rpcPassword = server.conf.rpcPassword) + val cliConfig = Config( + rpcPortOpt = Some(server.conf.rpcPort), + rpcPassword = server.conf.rpcPassword + ) val req = buildReq(server.conf) val notificationsF: ( Future[WebSocketUpgradeResponse], - (Future[Seq[WsNotification[_]]], Promise[Option[Message]])) = { + (Future[Seq[WsNotification[_]]], Promise[Option[Message]]) + ) = { Http() .singleWebSocketRequest(req, websocketFlow) } @@ -474,10 +526,12 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { InetSocketAddress.createUnresolved("127.0.0.1", NetworkUtil.randomPort()) val acceptMsg = { - AcceptDLC(offer = offer, - externalPayoutAddressOpt = None, - externalChangeAddressOpt = None, - peerAddr = peerAddr) + AcceptDLC( + offer = offer, + externalPayoutAddressOpt = None, + externalChangeAddressOpt = None, + peerAddr = peerAddr + ) } for { _ <- setupF @@ -488,13 +542,16 @@ class WebsocketTests extends BitcoinSServerMainBitcoindFixture { } yield { assert(notifications.exists(_ == DLCNodeConnectionInitiated(peerAddr))) assert(notifications.exists(_ == DLCNodeConnectionFailed(peerAddr))) - assert(notifications.exists(n => - n match { - case DLCAcceptFailed((id, error)) => - id == offer.tlv.tempContractId && error.startsWith( - "Connection refused") - case _ => false - })) + assert( + notifications.exists(n => + n match { + case DLCAcceptFailed((id, error)) => + id == offer.tlv.tempContractId && error.startsWith( + "Connection refused" + ) + case _ => false + }) + ) } } diff --git a/app/server-test/src/test/scala/org/bitcoins/wallet/MockWalletApi.scala b/app/server-test/src/test/scala/org/bitcoins/wallet/MockWalletApi.scala index 60cb70cf48..9be23a73eb 100644 --- a/app/server-test/src/test/scala/org/bitcoins/wallet/MockWalletApi.scala +++ b/app/server-test/src/test/scala/org/bitcoins/wallet/MockWalletApi.scala @@ -7,8 +7,8 @@ import org.bitcoins.core.protocol.BitcoinAddress import scala.concurrent.Future -/** ScalaMock cannot stub traits with protected methods, - * so we need to stub them manually. +/** ScalaMock cannot stub traits with protected methods, so we need to stub them + * manually. */ abstract class MockWalletApi extends DLCNeutrinoHDWalletApi { @@ -18,7 +18,8 @@ abstract class MockWalletApi extends DLCNeutrinoHDWalletApi { override def getDefaultAccount(): Future[AccountDb] = stub override def getDefaultAccountForType( - addressType: AddressType): Future[AccountDb] = stub + addressType: AddressType + ): Future[AccountDb] = stub private def stub[T] = Future.failed[T](new RuntimeException("Not implemented")) diff --git a/app/server/src/main/scala/org/bitcoins/server/BitcoinSAppConfig.scala b/app/server/src/main/scala/org/bitcoins/server/BitcoinSAppConfig.scala index 6f54684371..56139804c2 100644 --- a/app/server/src/main/scala/org/bitcoins/server/BitcoinSAppConfig.scala +++ b/app/server/src/main/scala/org/bitcoins/server/BitcoinSAppConfig.scala @@ -27,18 +27,20 @@ import java.util.concurrent.TimeUnit import scala.concurrent.Future import scala.concurrent.duration.{DurationInt, FiniteDuration} -/** A unified config class for all submodules of Bitcoin-S - * that accepts configuration. Thanks to implicit definitions - * in this case class' companion object an instance - * of this class can be passed in anywhere a wallet, - * chain or node config is required. +/** A unified config class for all submodules of Bitcoin-S that accepts + * configuration. Thanks to implicit definitions in this case class' companion + * object an instance of this class can be passed in anywhere a wallet, chain + * or node config is required. * - * @param directory The data directory of this app configuration - * @param confs A sequence of optional configuration overrides + * @param directory + * The data directory of this app configuration + * @param confs + * A sequence of optional configuration overrides */ case class BitcoinSAppConfig( baseDatadir: Path, - configOverrides: Vector[Config])(implicit system: ActorSystem) + configOverrides: Vector[Config] +)(implicit system: ActorSystem) extends StartStopAsync[AppConfigMarker] with BitcoinSLogger { import system.dispatcher @@ -73,8 +75,8 @@ case class BitcoinSAppConfig( /** Initializes the wallet, node and chain projects */ override def start(): Future[StartedBitcoinSAppConfig] = { val start = TimeUtil.currentEpochMs - //configurations that don't depend on tor startup - //start these in parallel as an optimization + // configurations that don't depend on tor startup + // start these in parallel as an optimization val nonTorConfigs = Vector(kmConf, chainConf, walletConf, dlcConf) val torConfig = torConf.start() @@ -84,10 +86,10 @@ case class BitcoinSAppConfig( val dbConfigsDependentOnTor: Vector[DbManagement] = Vector(nodeConf) - //run migrations here to avoid issues like: https://github.com/bitcoin-s/bitcoin-s/issues/4606 - //since we don't require tor dependent configs - //to be fully started before completing the Future returned by this - //method, we need to run them on their own + // run migrations here to avoid issues like: https://github.com/bitcoin-s/bitcoin-s/issues/4606 + // since we don't require tor dependent configs + // to be fully started before completing the Future returned by this + // method, we need to run them on their own val migrateTorDependentDbConfigsF = Future.traverse(dbConfigsDependentOnTor)(dbConfig => Future(dbConfig.migrate())) @@ -109,7 +111,8 @@ case class BitcoinSAppConfig( _ <- startedNonTorConfigsF } yield { logger.info( - s"Done starting BitcoinSAppConfig, it took=${TimeUtil.currentEpochMs - start}ms") + s"Done starting BitcoinSAppConfig, it took=${TimeUtil.currentEpochMs - start}ms" + ) StartedBitcoinSAppConfig(startedTorDependentConfigsF.map(_ => ())) } } @@ -132,9 +135,11 @@ case class BitcoinSAppConfig( /** The underlying config the result of our fields derive from */ lazy val config: Config = { val finalConfig = - AppConfig.getBaseConfig(baseDatadir = baseDatadir, - DEFAULT_BITCOIN_S_CONF_FILE, - configOverrides) + AppConfig.getBaseConfig( + baseDatadir = baseDatadir, + DEFAULT_BITCOIN_S_CONF_FILE, + configOverrides + ) val resolved = finalConfig.resolve() resolved.checkValid(ConfigFactory.defaultReference(), "bitcoin-s") @@ -146,8 +151,8 @@ case class BitcoinSAppConfig( def wsPort: Int = config.getIntOrElse("bitcoin-s.server.wsport", 19999) - /** How long until we forcefully terminate connections to the server - * when shutting down the server + /** How long until we forcefully terminate connections to the server when + * shutting down the server */ def terminationDeadline: FiniteDuration = { val opt = config.getDurationOpt("bitcoin-s.server.termination-deadline") @@ -157,9 +162,10 @@ case class BitcoinSAppConfig( new FiniteDuration(duration.toNanos, TimeUnit.NANOSECONDS) } else { sys.error( - s"Can only have a finite duration for termination deadline, got=$duration") + s"Can only have a finite duration for termination deadline, got=$duration" + ) } - case None => 5.seconds //5 seconds by default + case None => 5.seconds // 5 seconds by default } } @@ -190,13 +196,14 @@ case class BitcoinSAppConfig( } } -/** Implicit conversions that allow a unified configuration - * to be passed in wherever a specializes one is required +/** Implicit conversions that allow a unified configuration to be passed in + * wherever a specializes one is required */ object BitcoinSAppConfig extends BitcoinSLogger { - def fromConfig(config: Config)(implicit - system: ActorSystem): BitcoinSAppConfig = { + def fromConfig( + config: Config + )(implicit system: ActorSystem): BitcoinSAppConfig = { val configDataDir: Path = Paths.get(config.getString("bitcoin-s.datadir")) BitcoinSAppConfig(configDataDir, Vector(config)) } @@ -206,33 +213,36 @@ object BitcoinSAppConfig extends BitcoinSLogger { } def fromDatadir(datadir: Path, confs: Config*)(implicit - system: ActorSystem): BitcoinSAppConfig = { + system: ActorSystem + ): BitcoinSAppConfig = { BitcoinSAppConfig(datadir, confs.toVector) } def fromDatadirWithServerArgs( datadir: Path, - serverArgsParser: ServerArgParser)(implicit - system: ActorSystem): BitcoinSAppConfig = { + serverArgsParser: ServerArgParser + )(implicit system: ActorSystem): BitcoinSAppConfig = { fromDatadir(datadir, serverArgsParser.toConfig) } - /** Constructs an app configuration from the default Bitcoin-S - * data directory and given list of configuration overrides. + /** Constructs an app configuration from the default Bitcoin-S data directory + * and given list of configuration overrides. */ def fromDefaultDatadir(confs: Config*)(implicit - system: ActorSystem): BitcoinSAppConfig = + system: ActorSystem + ): BitcoinSAppConfig = BitcoinSAppConfig(AppConfig.DEFAULT_BITCOIN_S_DATADIR, confs.toVector) - def fromDefaultDatadirWithBundleConf(confs: Vector[Config] = Vector.empty)( - implicit system: ActorSystem): BitcoinSAppConfig = { + def fromDefaultDatadirWithBundleConf( + confs: Vector[Config] = Vector.empty + )(implicit system: ActorSystem): BitcoinSAppConfig = { fromDatadirWithBundleConf(AppConfig.DEFAULT_BITCOIN_S_DATADIR, confs) } def fromDatadirWithBundleConf( datadir: Path, - confs: Vector[Config] = Vector.empty)(implicit - system: ActorSystem): BitcoinSAppConfig = { + confs: Vector[Config] = Vector.empty + )(implicit system: ActorSystem): BitcoinSAppConfig = { val baseConf: BitcoinSAppConfig = fromDatadir(datadir, confs: _*) @@ -250,22 +260,20 @@ object BitcoinSAppConfig extends BitcoinSLogger { } /** Resolve BitcoinSAppConfig in the following order of precedence - * 1. Server args - * 2. bitcoin-s-bundle.conf - * 3. bitcoin-s.conf - * 4. application.conf - * 5. reference.conf + * 1. Server args 2. bitcoin-s-bundle.conf 3. bitcoin-s.conf 4. + * application.conf 5. reference.conf */ def fromDatadirWithBundleConfWithServerArgs( datadir: Path, - serverArgParser: ServerArgParser)(implicit - system: ActorSystem): BitcoinSAppConfig = { + serverArgParser: ServerArgParser + )(implicit system: ActorSystem): BitcoinSAppConfig = { fromDatadirWithBundleConf(datadir, Vector(serverArgParser.toConfig)) } /** Creates a BitcoinSAppConfig the the given daemon args to a server */ - def fromDefaultDatadirWithServerArgs(serverArgParser: ServerArgParser)( - implicit system: ActorSystem): BitcoinSAppConfig = { + def fromDefaultDatadirWithServerArgs( + serverArgParser: ServerArgParser + )(implicit system: ActorSystem): BitcoinSAppConfig = { val config = serverArgParser.toConfig fromConfig(config) } diff --git a/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala b/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala index 8bb4220553..6a53f5e46e 100644 --- a/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala +++ b/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala @@ -51,8 +51,8 @@ import scala.concurrent.{Await, Future, Promise} class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit override val system: ActorSystem, - val conf: BitcoinSAppConfig) - extends BitcoinSServerRunner[WalletHolder] { + val conf: BitcoinSAppConfig +) extends BitcoinSServerRunner[WalletHolder] { implicit lazy val nodeConf: NodeAppConfig = conf.nodeConf implicit lazy val chainConf: ChainAppConfig = conf.chainConf @@ -69,16 +69,18 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit logger.info(s"Start on network $network") startedConfigF.failed.foreach { err => - logger.error(s"Failed to initialize configuration for BitcoinServerMain", - err) + logger.error( + s"Failed to initialize configuration for BitcoinServerMain", + err + ) } for { startedConfig <- startedConfigF chainApi = ChainHandler.fromDatabase() nodeType = nodeConf.nodeType - //on server startup we assume we are out of sync with the bitcoin network - //so we set this flag to true. + // on server startup we assume we are out of sync with the bitcoin network + // so we set this flag to true. _ <- initializeChainState(chainApi, nodeType) start <- { nodeType match { @@ -90,21 +92,23 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit } } yield { logger.info( - s"Done start BitcoinSServerMain, it took=${TimeUtil.currentEpochMs - startTime}ms") + s"Done start BitcoinSServerMain, it took=${TimeUtil.currentEpochMs - startTime}ms" + ) start } } private def initializeChainState( chainHandler: ChainHandler, - nodeType: NodeType): Future[Unit] = { + nodeType: NodeType + ): Future[Unit] = { val syncF = chainHandler.setSyncing(true) val blockCountF = chainHandler.getBlockCount() nodeType match { case NodeType.NeutrinoNode => blockCountF.flatMap { blockCount => if (blockCount == 0) { - //means we are starting a fresh node, set IBD to true + // means we are starting a fresh node, set IBD to true chainHandler .setIBD(true) .map(_ => ()) @@ -113,11 +117,12 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit } } case NodeType.BitcoindBackend => - //don't need to do anything as we outsource chain management to bitcoind + // don't need to do anything as we outsource chain management to bitcoind syncF.map(_ => ()) case NodeType.FullNode => sys.error( - s"Full not is not implemented, not sure what to do with chainstate") + s"Full not is not implemented, not sure what to do with chainstate" + ) } } @@ -147,7 +152,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit _ = logger.info(s"Stopped ${nodeConf.nodeType.shortName} node") } yield { resetState() - //return empty wallet holder + // return empty wallet holder WalletHolder.empty } } @@ -160,21 +165,24 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit } /** Start the bitcoin-s wallet server with a neutrino backend - * @param startedTorConfigF a future that is completed when tor is fully started + * @param startedTorConfigF + * a future that is completed when tor is fully started * @return */ def startBitcoinSBackend( - startedTorConfigF: Future[Unit]): Future[WalletHolder] = { + startedTorConfigF: Future[Unit] + ): Future[WalletHolder] = { logger.info(s"startBitcoinSBackend()") val start = System.currentTimeMillis() val chainApi = ChainHandler.fromDatabase() val creationTime: Instant = conf.walletConf.creationTime - //get a node that isn't started + // get a node that isn't started val nodeF = nodeConf.createNode( peers = nodeConf.peers, - walletCreationTimeOpt = Some(creationTime))(chainConf, system) + walletCreationTimeOpt = Some(creationTime) + )(chainConf, system) val defaultApi = MempoolSpaceProvider(HourFeeTarget, network, torConf.socks5ProxyParams) @@ -183,17 +191,20 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit conf.walletConf.feeProviderNameOpt, conf.walletConf.feeProviderTargetOpt, torConf.socks5ProxyParams, - network) - //get our wallet + network + ) + // get our wallet val walletHolder = WalletHolder.empty val neutrinoWalletLoaderF = { for { node <- nodeF } yield { - val l = DLCWalletNeutrinoBackendLoader(walletHolder, - chainApi, - nodeApi = node, - feeRateApi = feeProvider) + val l = DLCWalletNeutrinoBackendLoader( + walletHolder, + chainApi, + nodeApi = node, + feeRateApi = feeProvider + ) walletLoaderApiOpt = Some(l) l } @@ -208,13 +219,13 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit torConf.addCallbacks(torCallbacks) val isTorStartedF = if (torConf.torProvided) { - //if tor is provided we need to execute the tor started callback immediately + // if tor is provided we need to execute the tor started callback immediately torConf.callBacks.executeOnTorStarted() } else { Future.unit } val startedNodeF = { - //can't start connecting to peers until tor is done starting + // can't start connecting to peers until tor is done starting for { _ <- startedTorConfigF _ <- isTorStartedF @@ -229,7 +240,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit _ <- startedNodeF walletWithConfigs <- neutrinoWalletLoader.load( walletNameOpt = walletNameOpt, - aesPasswordOpt = conf.walletConf.aesPasswordOpt) + aesPasswordOpt = conf.walletConf.aesPasswordOpt + ) } yield { walletWithConfigs } @@ -250,7 +262,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit } yield dlcNode } - //start our http server now that we are synced + // start our http server now that we are synced val startedF = for { _ <- configuredWalletF _ <- startHttpServer( @@ -265,16 +277,18 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit _ = { logger.info( s"Starting ${nodeConf.nodeType.shortName} node sync, it took=${System - .currentTimeMillis() - start}ms") + .currentTimeMillis() - start}ms" + ) } - //make sure callbacks are registered before we start sync + // make sure callbacks are registered before we start sync _ <- callbacksF node <- startedNodeF _ <- startedTorConfigF } yield { nodeOpt = Some(node) logger.info( - s"Done starting Main! It took ${System.currentTimeMillis() - start}ms") + s"Done starting Main! It took ${System.currentTimeMillis() - start}ms" + ) () } @@ -288,7 +302,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit wsQueue: SourceQueueWithComplete[WsNotification[_]], chainApi: ChainApi, walletConf: WalletAppConfig, - dlcConf: DLCAppConfig): Unit = { + dlcConf: DLCAppConfig + ): Unit = { val chainCallbacks = WebsocketUtil.buildChainCallbacks(wsQueue, chainApi) chainConf.addCallbacks(chainCallbacks) @@ -308,10 +323,11 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit () } - /** Returns blockchain info, in case of [[InWarmUp]] exception it retries. + /** Returns blockchain info, in case of [[InWarmUp]] exception it retries. */ private def getBlockChainInfo( - client: BitcoindRpcClient): Future[GetBlockChainInfoResult] = { + client: BitcoindRpcClient + ): Future[GetBlockChainInfoResult] = { val promise = Promise[GetBlockChainInfoResult]() val interval = 1.second val maxTries = 12 @@ -346,11 +362,13 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit private[this] var nodeOpt: Option[Node] = None /** Start the bitcoin-s wallet server with a bitcoind backend - * @param startedTorConfigF a future that is completed when tor is fully started + * @param startedTorConfigF + * a future that is completed when tor is fully started * @return */ private def startBitcoindBackend( - startedTorConfigF: Future[Unit]): Future[WalletHolder] = { + startedTorConfigF: Future[Unit] + ): Future[WalletHolder] = { logger.info(s"startBitcoindBackend()") val bitcoindF = for { client <- bitcoindRpcConf.clientF @@ -365,7 +383,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit val torCallbacks = WebsocketUtil.buildTorCallbacks(wsQueue) val _ = torConf.addCallbacks(torCallbacks) val isTorStartedF = if (torConf.torProvided) { - //if tor is provided we need to emit a tor started event immediately + // if tor is provided we need to emit a tor started event immediately torConf.callBacks.executeOnTorStarted() } else { Future.unit @@ -373,7 +391,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit val walletNameF = for { lastLoadedWallet <- getLastLoadedWalletName() walletName = lastLoadedWallet.getOrElse( - WalletAppConfig.DEFAULT_WALLET_NAME) + WalletAppConfig.DEFAULT_WALLET_NAME + ) } yield walletName val walletHolder = WalletHolder.empty @@ -388,7 +407,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit } yield BitcoindRpcBackendUtil.buildBitcoindNodeApi( bitcoind, Future.successful(walletHolder), - Some(chainCallbacks)) + Some(chainCallbacks) + ) val feeProviderF = bitcoindF.map { bitcoind => FeeProviderFactory.getFeeProviderOrElse( @@ -406,10 +426,12 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit nodeApi <- nodeApiF feeProvider <- feeProviderF } yield { - val l = DLCWalletBitcoindBackendLoader(walletHolder = walletHolder, - bitcoind = bitcoind, - nodeApi = nodeApi, - feeProvider = feeProvider) + val l = DLCWalletBitcoindBackendLoader( + walletHolder = walletHolder, + bitcoind = bitcoind, + nodeApi = nodeApi, + feeProvider = feeProvider + ) walletLoaderApiOpt = Some(l) l @@ -421,8 +443,10 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit _ <- isTorStartedF loadWalletApi <- loadWalletApiF walletName <- walletNameF - result <- loadWalletApi.load(Some(walletName), - conf.walletConf.aesPasswordOpt) + result <- loadWalletApi.load( + Some(walletName), + conf.walletConf.aesPasswordOpt + ) } yield result } @@ -442,7 +466,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit bitcoindNetwork = blockchainInfo.chain _ = require( bitcoindNetwork == network, - s"bitcoind ($bitcoindNetwork) on different network than wallet ($network)") + s"bitcoind ($bitcoindNetwork) on different network than wallet ($network)" + ) _ <- startHttpServer( nodeApiF = Future.successful(bitcoind), chainApi = bitcoind, @@ -453,8 +478,10 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit wsSource = wsSource ) walletName <- walletNameF - walletCallbacks = WebsocketUtil.buildWalletCallbacks(wsQueue, - walletName) + walletCallbacks = WebsocketUtil.buildWalletCallbacks( + wsQueue, + walletName + ) chainCallbacks <- chainCallbacksF (wallet, walletConfig, dlcConfig) <- walletF _ = walletConfig.addCallbacks(walletCallbacks) @@ -462,7 +489,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit bitcoindSyncState <- syncWalletWithBitcoindAndStartPolling( bitcoind, wallet, - Some(chainCallbacks)) + Some(chainCallbacks) + ) _ = { bitcoindSyncStateOpt = Some(bitcoindSyncState) } @@ -477,9 +505,9 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit } } - //don't return the Future that represents the full syncing of the wallet with bitcoind + // don't return the Future that represents the full syncing of the wallet with bitcoind for { - _ <- bitcoindSyncStateF //drop nested Future here + _ <- bitcoindSyncStateF // drop nested Future here walletHolder <- walletF.map(_._1) } yield walletHolder } @@ -493,9 +521,8 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit dlcNodeF: Future[DLCNode], torConfStarted: Future[Unit], serverCmdLineArgs: ServerArgParser, - wsSource: Source[WsNotification[_], NotUsed])(implicit - system: ActorSystem, - conf: BitcoinSAppConfig): Future[Server] = { + wsSource: Source[WsNotification[_], NotUsed] + )(implicit system: ActorSystem, conf: BitcoinSAppConfig): Future[Server] = { implicit val nodeConf: NodeAppConfig = conf.nodeConf implicit val walletConf: WalletAppConfig = conf.walletConf @@ -516,7 +543,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit Future.successful(commonRoutes), Future.successful(coreRoutes), Future.successful(chainRoutes), - //dependent on tor, slow start up + // dependent on tor, slow start up walletRoutesF, nodeRoutesF, dlcRoutesF @@ -543,13 +570,15 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit val server = { serverCmdLineArgs.rpcPortOpt match { case Some(rpcport) => - Server(conf = nodeConf, - handlersF = handlers, - rpcbindOpt = rpcBindConfOpt, - rpcport = rpcport, - rpcPassword = conf.rpcPassword, - wsConfigOpt = Some(wsServerConfig), - wsSource) + Server( + conf = nodeConf, + handlersF = handlers, + rpcbindOpt = rpcBindConfOpt, + rpcport = rpcport, + rpcPassword = conf.rpcPassword, + wsConfigOpt = Some(wsServerConfig), + wsSource + ) case None => Server( conf = nodeConf, @@ -570,29 +599,33 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit } } - /** Syncs the bitcoin-s wallet against bitcoind and then - * starts rpc polling if zmq isn't enabled, otherwise it starts zmq polling. + /** Syncs the bitcoin-s wallet against bitcoind and then starts rpc polling if + * zmq isn't enabled, otherwise it starts zmq polling. * * The key thing this helper method does is it logs errors based on the - * future returned by this method. This is needed because we don't want - * to block the rest of the application from starting if we have to - * do a ton of syncing. However, we don't want to swallow - * exceptions thrown by this method. - * @return the [[Cancellable]] representing the schedule job that polls the mempool. You can call .cancel() to stop this + * future returned by this method. This is needed because we don't want to + * block the rest of the application from starting if we have to do a ton of + * syncing. However, we don't want to swallow exceptions thrown by this + * method. + * @return + * the [[Cancellable]] representing the schedule job that polls the + * mempool. You can call .cancel() to stop this */ private def syncWalletWithBitcoindAndStartPolling( bitcoind: BitcoindRpcClient, wallet: NeutrinoHDWalletApi, - chainCallbacksOpt: Option[ChainCallbacks]): Future[BitcoindSyncState] = { + chainCallbacksOpt: Option[ChainCallbacks] + ): Future[BitcoindSyncState] = { val f = for { _ <- handlePotentialBitcoindLostBlock(bitcoind, wallet) syncF = BitcoindRpcBackendUtil.syncWalletToBitcoind( bitcoind, wallet, - chainCallbacksOpt)(system) + chainCallbacksOpt + )(system) _ = syncF.map(_ => wallet.updateUtxoPendingStates()) - //don't start polling until initial sync is done + // don't start polling until initial sync is done pollingCancellable <- syncF.flatMap { _ => if (bitcoindRpcConf.zmqConfig == ZmqConfig.empty) { val blockingPollingCancellable = BitcoindRpcBackendUtil @@ -603,15 +636,18 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit .executeOnTxReceivedCallbacks(tx) } val combinedCancellable = - BitcoindPollingCancellable(blockingPollingCancellable, - mempoolCancellable) + BitcoindPollingCancellable( + blockingPollingCancellable, + mempoolCancellable + ) Future.successful(combinedCancellable) } else { Future { BitcoindRpcBackendUtil.startZMQWalletCallbacks( wallet, - bitcoindRpcConf.zmqConfig) + bitcoindRpcConf.zmqConfig + ) BitcoindPollingCancellabe.none } } @@ -624,13 +660,15 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit f } - /** Surprisingly on some OSes like umbrel bitcoind can lose blocks during the shutdown process - * This means next time we boot up, our wallet will have more blocks than bitcoind! - * Eventually bitcoind will synchrnoize with the network. This waits until bitcoind is synced + /** Surprisingly on some OSes like umbrel bitcoind can lose blocks during the + * shutdown process This means next time we boot up, our wallet will have + * more blocks than bitcoind! Eventually bitcoind will synchrnoize with the + * network. This waits until bitcoind is synced */ private def handlePotentialBitcoindLostBlock( bitcoind: BitcoindRpcClient, - wallet: WalletApi): Future[Unit] = { + wallet: WalletApi + ): Future[Unit] = { AsyncUtil.retryUntilSatisfiedF( conditionF = { () => for { @@ -645,21 +683,22 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit ) } - /** Builds a websocket queue that you can feed elements to. - * The Source can be wired up with Directives.handleWebSocketMessages - * to create a flow that emits websocket messages + /** Builds a websocket queue that you can feed elements to. The Source can be + * wired up with Directives.handleWebSocketMessages to create a flow that + * emits websocket messages */ private def buildWsSource: ( SourceQueueWithComplete[WsNotification[_]], - Source[WsNotification[_], NotUsed]) = { + Source[WsNotification[_], NotUsed] + ) = { val maxBufferSize: Int = 25 - /** This will queue [[maxBufferSize]] elements in the queue. Once the buffer size is reached, - * we will drop the first element in the buffer + /** This will queue [[maxBufferSize]] elements in the queue. Once the buffer + * size is reached, we will drop the first element in the buffer */ val tuple = { - //from: https://github.com/akka/akka-http/issues/3039#issuecomment-610263181 - //the BroadcastHub.sink is needed to avoid these errors + // from: https://github.com/akka/akka-http/issues/3039#issuecomment-610263181 + // the BroadcastHub.sink is needed to avoid these errors // 'Websocket handler failed with Processor actor' Source .queue[WsNotification[_]](maxBufferSize, OverflowStrategy.dropHead) @@ -667,7 +706,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit .run() } - //need to drain the websocket queue if no one is connected + // need to drain the websocket queue if no one is connected val _: Future[Done] = tuple._2.runWith(Sink.ignore) tuple @@ -703,7 +742,8 @@ object BitcoinSServerMain extends BitcoinSAppScalaDaemon { implicit lazy val conf: BitcoinSAppConfig = BitcoinSAppConfig( datadirParser.datadir, - Vector(datadirParser.baseConfig, serverCmdLineArgs.toConfig))(system) + Vector(datadirParser.baseConfig, serverCmdLineArgs.toConfig) + )(system) val m = new BitcoinSServerMain(serverCmdLineArgs) @@ -711,7 +751,8 @@ object BitcoinSServerMain extends BitcoinSAppScalaDaemon { sys.addShutdownHook { logger.info( - s"@@@@@@@@@@@@@@@@@@@@@ Shutting down ${getClass.getSimpleName} @@@@@@@@@@@@@@@@@@@@@") + s"@@@@@@@@@@@@@@@@@@@@@ Shutting down ${getClass.getSimpleName} @@@@@@@@@@@@@@@@@@@@@" + ) Await.result(m.stop(), 10.seconds) () } diff --git a/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala b/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala index bd29350a56..abea42cd90 100644 --- a/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala +++ b/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala @@ -32,15 +32,19 @@ import java.util.concurrent.atomic.{AtomicBoolean, AtomicInteger} import scala.concurrent.duration.{DurationInt, FiniteDuration} import scala.concurrent.{ExecutionContext, Future, Promise} -/** Useful utilities to use in the wallet project for syncing things against bitcoind */ +/** Useful utilities to use in the wallet project for syncing things against + * bitcoind + */ object BitcoindRpcBackendUtil extends BitcoinSLogger { - /** Has the wallet process all the blocks it has not seen up until bitcoind's chain tip */ + /** Has the wallet process all the blocks it has not seen up until bitcoind's + * chain tip + */ def syncWalletToBitcoind( bitcoind: BitcoindRpcClient, wallet: NeutrinoHDWalletApi, - chainCallbacksOpt: Option[ChainCallbacks])(implicit - system: ActorSystem): Future[Unit] = { + chainCallbacksOpt: Option[ChainCallbacks] + )(implicit system: ActorSystem): Future[Unit] = { logger.info("Syncing wallet to bitcoind") import system.dispatcher @@ -59,24 +63,26 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { } } _ = logger.info( - s"Syncing from bitcoind with bitcoindHeight=$bitcoindHeight walletHeight=${heightRange.start}") + s"Syncing from bitcoind with bitcoindHeight=$bitcoindHeight walletHeight=${heightRange.start}" + ) syncFlow <- buildBitcoindSyncSink(bitcoind, wallet) stream = Source(heightRange).toMat(syncFlow)(Keep.right) } yield stream - //run the stream + // run the stream val res = streamF.flatMap(_.run()) res.onComplete { case _ => val isBitcoindInSyncF = BitcoindRpcBackendUtil.isBitcoindInSync(bitcoind) isBitcoindInSyncF.flatMap { isBitcoindInSync => if (isBitcoindInSync) { - //if bitcoind is in sync, and we are in sync with bitcoind, set the syncing flag to false + // if bitcoind is in sync, and we are in sync with bitcoind, set the syncing flag to false setSyncingFlag(false, bitcoind, chainCallbacksOpt) } else { - //if bitcoind is not in sync, we cannot be done syncing. Keep the syncing flag to true - //so do nothing in this case + // if bitcoind is not in sync, we cannot be done syncing. Keep the syncing flag to true + // so do nothing in this case logger.warn( - s"We synced against bitcoind, but bitcoind is not in sync with the network.") + s"We synced against bitcoind, but bitcoind is not in sync with the network." + ) Future.unit } } @@ -85,14 +91,15 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { res.map(_ => ()) } - /** Gets the height range for syncing against bitcoind when we don't have a [[org.bitcoins.core.api.wallet.WalletStateDescriptor]] - * to read the sync height from. + /** Gets the height range for syncing against bitcoind when we don't have a + * [[org.bitcoins.core.api.wallet.WalletStateDescriptor]] to read the sync + * height from. */ private def getHeightRangeNoWalletState( wallet: NeutrinoHDWalletApi, bitcoind: BitcoindRpcClient, - bitcoindHeight: Int)(implicit - ex: ExecutionContext): Future[Range.Inclusive] = { + bitcoindHeight: Int + )(implicit ex: ExecutionContext): Future[Range.Inclusive] = { for { txDbs <- wallet.listTransactions() lastConfirmedOpt = txDbs @@ -108,7 +115,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { range <- heightOpt match { case Some(height) => logger.info( - s"Last tx occurred at block $height, syncing from there") + s"Last tx occurred at block $height, syncing from there" + ) val range = height.to(bitcoindHeight) Future.successful(range) case None => @@ -123,8 +131,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { private def setSyncingFlag( syncing: Boolean, bitcoind: BitcoindRpcClient, - chainCallbacksOpt: Option[ChainCallbacks])(implicit - ec: ExecutionContext): Future[Unit] = { + chainCallbacksOpt: Option[ChainCallbacks] + )(implicit ec: ExecutionContext): Future[Unit] = { val oldSyncingFlagF = bitcoind.isSyncing() for { oldFlag <- oldSyncingFlagF @@ -146,14 +154,16 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { } } - /** Helper method to sync the wallet until the bitcoind height. - * This method returns a Sink that you can give block heights too and - * the sink will synchronize our bitcoin-s wallet against bitcoind + /** Helper method to sync the wallet until the bitcoind height. This method + * returns a Sink that you can give block heights too and the sink will + * synchronize our bitcoin-s wallet against bitcoind */ private def buildBitcoindSyncSink( bitcoind: BitcoindRpcClient, - wallet: NeutrinoHDWalletApi)(implicit - system: ActorSystem): Future[Sink[Int, Future[NeutrinoHDWalletApi]]] = { + wallet: NeutrinoHDWalletApi + )(implicit + system: ActorSystem + ): Future[Sink[Int, Future[NeutrinoHDWalletApi]]] = { import system.dispatcher val hasFiltersF = bitcoind @@ -163,10 +173,10 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { .recover { case _: Throwable => false } val numParallelism = FutureUtil.getParallelism - //feeding blockchain hashes into this sync - //will sync our wallet with those blockchain hashes - val syncWalletSinkF: Future[ - Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]]] = { + // feeding blockchain hashes into this sync + // will sync our wallet with those blockchain hashes + val syncWalletSinkF + : Future[Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]]] = { for { hasFilters <- hasFiltersF @@ -197,8 +207,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { def createWalletWithBitcoindCallbacks( bitcoind: BitcoindRpcClient, wallet: Wallet, - chainCallbacksOpt: Option[ChainCallbacks])(implicit - system: ActorSystem): Wallet = { + chainCallbacksOpt: Option[ChainCallbacks] + )(implicit system: ActorSystem): Wallet = { // We need to create a promise so we can inject the wallet with the callback // after we have created it into SyncUtil.getNodeApiWalletCallback // so we don't lose the internal state of the wallet @@ -207,7 +217,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { val nodeApi = BitcoindRpcBackendUtil.buildBitcoindNodeApi( bitcoind, walletCallbackP.future, - chainCallbacksOpt) + chainCallbacksOpt + ) val pairedWallet = Wallet( nodeApi = nodeApi, chainQueryApi = bitcoind, @@ -221,10 +232,12 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { def startZMQWalletCallbacks( wallet: NeutrinoHDWalletApi, - zmqConfig: ZmqConfig)(implicit - ec: ExecutionContext): WalletZmqSubscribers = { - require(zmqConfig != ZmqConfig.empty, - "Must have the zmq raw configs defined to setup ZMQ callbacks") + zmqConfig: ZmqConfig + )(implicit ec: ExecutionContext): WalletZmqSubscribers = { + require( + zmqConfig != ZmqConfig.empty, + "Must have the zmq raw configs defined to setup ZMQ callbacks" + ) val rawTxSub = zmqConfig.rawTx.map { zmq => val rawTxListener: Option[Transaction => Unit] = Some { @@ -238,18 +251,21 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { } } - new ZMQSubscriber(socket = zmq, - hashTxListener = None, - hashBlockListener = None, - rawTxListener = rawTxListener, - rawBlockListener = None) + new ZMQSubscriber( + socket = zmq, + hashTxListener = None, + hashBlockListener = None, + rawTxListener = rawTxListener, + rawBlockListener = None + ) } val rawBlockSub = zmqConfig.rawBlock.map { zmq => val rawBlockListener: Option[Block => Unit] = Some { { block: Block => logger.info( - s"Received block ${block.blockHeader.hashBE.hex}, processing") + s"Received block ${block.blockHeader.hashBE.hex}, processing" + ) val f = wallet.processBlock(block) f.failed.foreach { err => logger.error("failed to process raw block zmq message", err) @@ -258,11 +274,13 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { } } - new ZMQSubscriber(socket = zmq, - hashTxListener = None, - hashBlockListener = None, - rawTxListener = None, - rawBlockListener = rawBlockListener) + new ZMQSubscriber( + socket = zmq, + hashTxListener = None, + hashBlockListener = None, + rawTxListener = None, + rawBlockListener = rawBlockListener + ) } val subs = WalletZmqSubscribers(rawTxSub, rawBlockSub) @@ -273,18 +291,19 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { def createDLCWalletWithBitcoindCallbacks( bitcoind: BitcoindRpcClient, wallet: DLCWallet, - chainCallbacksOpt: Option[ChainCallbacks])(implicit - system: ActorSystem): DLCWallet = { + chainCallbacksOpt: Option[ChainCallbacks] + )(implicit system: ActorSystem): DLCWallet = { // We need to create a promise so we can inject the wallet with the callback // after we have created it into SyncUtil.getNodeApiWalletCallback // so we don't lose the internal state of the wallet val walletCallbackP = Promise[DLCWallet]() val pairedWallet = DLCWallet( - nodeApi = - BitcoindRpcBackendUtil.buildBitcoindNodeApi(bitcoind, - walletCallbackP.future, - chainCallbacksOpt), + nodeApi = BitcoindRpcBackendUtil.buildBitcoindNodeApi( + bitcoind, + walletCallbackP.future, + chainCallbacksOpt + ), chainQueryApi = bitcoind, feeRateApi = wallet.feeRateApi )(wallet.walletConfig, wallet.dlcConfig) @@ -296,9 +315,10 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { private def filterSyncSink( bitcoindRpcClient: BlockchainRpc, - wallet: NeutrinoHDWalletApi)(implicit ec: ExecutionContext): Sink[ - DoubleSha256DigestBE, - Future[NeutrinoHDWalletApi]] = { + wallet: NeutrinoHDWalletApi + )(implicit + ec: ExecutionContext + ): Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]] = { val numParallelism = FutureUtil.getParallelism val sink: Sink[DoubleSha256DigestBE, Future[NeutrinoHDWalletApi]] = @@ -317,39 +337,46 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { sink } - /** Creates an anonymous [[NodeApi]] that downloads blocks using - * akka streams from bitcoind, and then calls [[NeutrinoWalletApi.processBlock]] + /** Creates an anonymous [[NodeApi]] that downloads blocks using akka streams + * from bitcoind, and then calls [[NeutrinoWalletApi.processBlock]] */ def buildBitcoindNodeApi( bitcoindRpcClient: BitcoindRpcClient, walletF: Future[WalletApi], - chainCallbacksOpt: Option[ChainCallbacks])(implicit - system: ActorSystem): NodeApi = { + chainCallbacksOpt: Option[ChainCallbacks] + )(implicit system: ActorSystem): NodeApi = { import system.dispatcher new NodeApi { override def downloadBlocks( - blockHashes: Vector[DoubleSha256DigestBE]): Future[Unit] = { + blockHashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] = { logger.info(s"Fetching ${blockHashes.length} blocks from bitcoind") val numParallelism = FutureUtil.getParallelism val source = Source(blockHashes) val fetchBlocksFlow = BitcoindStreamUtil.fetchBlocksBitcoind( bitcoindRpcClient = bitcoindRpcClient, - parallelism = numParallelism) + parallelism = numParallelism + ) - val sinkF: Future[ - Sink[(Block, GetBlockHeaderResult), Future[WalletApi]]] = { + val sinkF + : Future[Sink[(Block, GetBlockHeaderResult), Future[WalletApi]]] = { walletF.map { initWallet => Sink.foldAsync[WalletApi, (Block, GetBlockHeaderResult)]( - initWallet) { - case (wallet: WalletApi, - (block: Block, blockHeaderResult: GetBlockHeaderResult)) => + initWallet + ) { + case ( + wallet: WalletApi, + (block: Block, blockHeaderResult: GetBlockHeaderResult) + ) => val blockProcessedF = wallet.processBlock(block) val executeCallbackF: Future[WalletApi] = { for { wallet <- blockProcessedF - _ <- handleChainCallbacks(chainCallbacksOpt, - blockHeaderResult) + _ <- handleChainCallbacks( + chainCallbacksOpt, + blockHeaderResult + ) } yield wallet } @@ -374,7 +401,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { /** Broadcasts the given transaction over the P2P network */ override def broadcastTransactions( - transactions: Vector[Transaction]): Future[Unit] = { + transactions: Vector[Transaction] + ): Future[Unit] = { bitcoindRpcClient.broadcastTransactions(transactions) } @@ -386,12 +414,12 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { private def handleChainCallbacks( chainCallbacksOpt: Option[ChainCallbacks], - blockHeaderResult: GetBlockHeaderResult)(implicit - ec: ExecutionContext): Future[Unit] = { + blockHeaderResult: GetBlockHeaderResult + )(implicit ec: ExecutionContext): Future[Unit] = { chainCallbacksOpt match { case None => Future.unit case Some(callback) => - //this can be slow as we aren't batching headers at all + // this can be slow as we aren't batching headers at all val headerWithHeights = Vector((blockHeaderResult.height, blockHeaderResult.blockHeader)) val f = callback @@ -400,19 +428,22 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { } } - /** Starts the [[ActorSystem]] to poll the [[BitcoindRpcClient]] for its block count, - * if it has changed, it will then request those blocks to process them + /** Starts the [[ActorSystem]] to poll the [[BitcoindRpcClient]] for its block + * count, if it has changed, it will then request those blocks to process + * them * - * @param startCount The starting block height of the wallet - * @param interval The amount of time between polls, this should not be too aggressive - * as the wallet will need to process the new blocks + * @param startCount + * The starting block height of the wallet + * @param interval + * The amount of time between polls, this should not be too aggressive as + * the wallet will need to process the new blocks */ def startBitcoindBlockPolling( wallet: WalletApi, bitcoind: BitcoindRpcClient, chainCallbacksOpt: Option[ChainCallbacks], - interval: FiniteDuration = 10.seconds)(implicit - system: ActorSystem): Cancellable = { + interval: FiniteDuration = 10.seconds + )(implicit system: ActorSystem): Cancellable = { import system.dispatcher val processingBitcoindBlocks = new AtomicBoolean(false) @@ -431,10 +462,12 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { res <- if (!rescanning) { val pollFOptF = - pollBitcoind(wallet = wallet, - bitcoind = bitcoind, - chainCallbacksOpt = chainCallbacksOpt, - prevCount = walletSyncState.height) + pollBitcoind( + wallet = wallet, + bitcoind = bitcoind, + chainCallbacksOpt = chainCallbacksOpt, + prevCount = walletSyncState.height + ) pollFOptF.flatMap { case Some(pollF) => pollF @@ -442,17 +475,20 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { } } else { logger.info( - s"Skipping scanning the blockchain during wallet rescan") + s"Skipping scanning the blockchain during wallet rescan" + ) Future.unit } } yield res f.onComplete { _ => processingBitcoindBlocks.set(false) - BitcoindRpcBackendUtil.setSyncingFlag(false, - bitcoind, - chainCallbacksOpt) - } //reset polling variable + BitcoindRpcBackendUtil.setSyncingFlag( + false, + bitcoind, + chainCallbacksOpt + ) + } // reset polling variable f.failed.foreach(err => logger.error(s"Failed to poll bitcoind", err)) } else { @@ -465,14 +501,16 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { } /** Polls bitcoind for syncing the blockchain - * @return None if there was nothing to sync, else the Future[Done] that is completed when the sync is finished. + * @return + * None if there was nothing to sync, else the Future[Done] that is + * completed when the sync is finished. */ private def pollBitcoind( wallet: WalletApi, bitcoind: BitcoindRpcClient, chainCallbacksOpt: Option[ChainCallbacks], - prevCount: Int)(implicit - system: ActorSystem): Future[Option[Future[Done]]] = { + prevCount: Int + )(implicit system: ActorSystem): Future[Option[Future[Done]]] = { import system.dispatcher val atomicPrevCount = new AtomicInteger(prevCount) val queueSource: Source[Int, SourceQueueWithComplete[Int]] = @@ -492,7 +530,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { atomicPrevCount.set(prevCount) logger.error( s"Processing blocks from bitcoind polling failed, range=[$prevCount, $failedCount]", - err) + err + ) } for { @@ -523,7 +562,8 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { retval <- { if (prevCount < count) { logger.info( - s"Bitcoind has new block(s), requesting... ${count - prevCount} blocks") + s"Bitcoind has new block(s), requesting... ${count - prevCount} blocks" + ) val setSyncFlagF = setSyncingFlag(true, bitcoind, chainCallbacksOpt) setSyncFlagF.map { _ => // use .tail so we don't process the previous block that we already did @@ -531,15 +571,18 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { range.foreach(r => queue.offer(r)) } } else if (prevCount > count) { - Future.failed(new RuntimeException( - s"Bitcoind is at a block height ($count) before the wallet's ($prevCount)")) + Future.failed( + new RuntimeException( + s"Bitcoind is at a block height ($count) before the wallet's ($prevCount)" + ) + ) } else { logger.debug(s"In sync $prevCount count=$count") Future.unit } } } yield { - queue.complete() //complete the stream after offering all heights we need to sync + queue.complete() // complete the stream after offering all heights we need to sync retval } resF.map(_ => Some(doneF)) @@ -548,15 +591,16 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { def startBitcoindMempoolPolling( wallet: WalletApi, bitcoind: BitcoindRpcClient, - interval: FiniteDuration = 10.seconds)( - processTx: Transaction => Future[Unit])(implicit - system: ActorSystem, - ec: ExecutionContext): Cancellable = { + interval: FiniteDuration = 10.seconds + )( + processTx: Transaction => Future[Unit] + )(implicit system: ActorSystem, ec: ExecutionContext): Cancellable = { @volatile var prevMempool: Set[DoubleSha256DigestBE] = Set.empty[DoubleSha256DigestBE] def getDiffAndReplace( - newMempool: Set[DoubleSha256DigestBE]): Set[DoubleSha256DigestBE] = + newMempool: Set[DoubleSha256DigestBE] + ): Set[DoubleSha256DigestBE] = synchronized { val txids = newMempool.diff(prevMempool) prevMempool = newMempool @@ -570,7 +614,7 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { logger.debug("Polling bitcoind for mempool") val numParallelism = FutureUtil.getParallelism - //don't want to execute these in parallel + // don't want to execute these in parallel val processTxFlow = Sink.foreachAsync[Option[Transaction]](1) { case Some(tx) => processTx(tx) case None => Future.unit @@ -594,14 +638,16 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { .run() } yield { logger.debug( - s"Done processing ${newTxIds.size} new mempool transactions") + s"Done processing ${newTxIds.size} new mempool transactions" + ) () } res.onComplete(_ => processingMempool.set(false)) res } else { logger.info( - s"Skipping scanning the mempool since a previously scheduled task is still running") + s"Skipping scanning the mempool since a previously scheduled task is still running" + ) Future.unit } } @@ -625,9 +671,12 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger { } } - /** Checks if bitcoind has all blocks for the headers it has seen on the network */ - private def isBitcoindInSync(bitcoind: BitcoindRpcClient)(implicit - ec: ExecutionContext): Future[Boolean] = { + /** Checks if bitcoind has all blocks for the headers it has seen on the + * network + */ + private def isBitcoindInSync( + bitcoind: BitcoindRpcClient + )(implicit ec: ExecutionContext): Future[Boolean] = { for { blockchainInfo <- bitcoind.getBlockChainInfo } yield { diff --git a/app/server/src/main/scala/org/bitcoins/server/ChainRoutes.scala b/app/server/src/main/scala/org/bitcoins/server/ChainRoutes.scala index 6480df4e13..1ae2b22479 100644 --- a/app/server/src/main/scala/org/bitcoins/server/ChainRoutes.scala +++ b/app/server/src/main/scala/org/bitcoins/server/ChainRoutes.scala @@ -17,7 +17,8 @@ import scala.concurrent.Future case class ChainRoutes( chain: ChainApi, network: BitcoinNetwork, - startedTorConfigF: Future[Unit])(implicit system: ActorSystem) + startedTorConfigF: Future[Unit] +)(implicit system: ActorSystem) extends ServerRoute { import system.dispatcher @@ -59,8 +60,8 @@ case class ChainRoutes( for { results <- resultsF } yield { - val json = upickle.default.writeJs(results.head)( - Picklers.getBlockHeaderResultPickler) + val json = upickle.default + .writeJs(results.head)(Picklers.getBlockHeaderResultPickler) Server.httpSuccess(json) } } diff --git a/app/server/src/main/scala/org/bitcoins/server/CoreRoutes.scala b/app/server/src/main/scala/org/bitcoins/server/CoreRoutes.scala index 98c12c0011..6458c5d28a 100644 --- a/app/server/src/main/scala/org/bitcoins/server/CoreRoutes.scala +++ b/app/server/src/main/scala/org/bitcoins/server/CoreRoutes.scala @@ -172,7 +172,8 @@ case class CoreRoutes()(implicit system: ActorSystem, config: BitcoinSAppConfig) case DecodeContractInfo(contractInfo) => complete { Server.httpSuccess( - writeJs(contractInfo)(contractInfoV0TLVJsonWriter)) + writeJs(contractInfo)(contractInfoV0TLVJsonWriter) + ) } } @@ -181,7 +182,8 @@ case class CoreRoutes()(implicit system: ActorSystem, config: BitcoinSAppConfig) case DecodeAnnouncement(announcement) => complete { Server.httpSuccess( - writeJs(announcement)(oracleAnnouncementTLVJsonWriter)) + writeJs(announcement)(oracleAnnouncementTLVJsonWriter) + ) } } diff --git a/app/server/src/main/scala/org/bitcoins/server/DLCRoutes.scala b/app/server/src/main/scala/org/bitcoins/server/DLCRoutes.scala index e1fc30e605..cdd2b82d32 100644 --- a/app/server/src/main/scala/org/bitcoins/server/DLCRoutes.scala +++ b/app/server/src/main/scala/org/bitcoins/server/DLCRoutes.scala @@ -42,10 +42,12 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem) case AcceptDLC(offer, address, payoutAddressOpt, changeAddressOpt) => complete { dlcNode - .acceptDLCOffer(address, - offer, - payoutAddressOpt, - changeAddressOpt) + .acceptDLCOffer( + address, + offer, + payoutAddressOpt, + changeAddressOpt + ) .map { accept => Server.httpSuccess(accept.toMessage.hex) } @@ -63,9 +65,11 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem) case _: EnumEventDescriptorV0TLV => EnumSingleOracleInfo(create.announcementTLV) } - val contractInfo = SingleContractInfo(create.totalCollateral, - create.ContractDescriptorTLV, - oracleInfo) + val contractInfo = SingleContractInfo( + create.totalCollateral, + create.ContractDescriptorTLV, + oracleInfo + ) Server.httpSuccess(contractInfo.hex) } } @@ -91,9 +95,11 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem) withValidServerCommand(OfferAdd.fromJsArr(arr)) { register => complete { dlcNode.wallet - .registerIncomingDLCOffer(register.offerTLV, - register.peer, - register.message) + .registerIncomingDLCOffer( + register.offerTLV, + register.peer, + register.message + ) .map { hash => Server.httpSuccess(hash.hex) } @@ -133,8 +139,8 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem) case ServerCommand("contacts-list", _) => complete { dlcNode.wallet.listDLCContacts().map { contacts => - val json = contacts.map(c => - upickle.default.writeJs(c)(Picklers.contactDbPickler)) + val json = contacts + .map(c => upickle.default.writeJs(c)(Picklers.contactDbPickler)) Server.httpSuccess(json) } } @@ -171,7 +177,8 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem) val contactId = dlcContactAdd.address.getHostName + ":" + dlcContactAdd.address.getPort Server.httpSuccess( - ujson.Obj("dlcId" -> dlcId, "contactId" -> contactId)) + ujson.Obj("dlcId" -> dlcId, "contactId" -> contactId) + ) } } } diff --git a/app/server/src/main/scala/org/bitcoins/server/DLCWalletLoaderApi.scala b/app/server/src/main/scala/org/bitcoins/server/DLCWalletLoaderApi.scala index e7c8b78a6c..f2a3b1d82d 100644 --- a/app/server/src/main/scala/org/bitcoins/server/DLCWalletLoaderApi.scala +++ b/app/server/src/main/scala/org/bitcoins/server/DLCWalletLoaderApi.scala @@ -22,8 +22,9 @@ import org.bitcoins.wallet.config.WalletAppConfig import scala.concurrent.{ExecutionContext, Future} -/** A trait used to help load a different load and discard the current wallet in memory - * This trait encapsulates the heavy lifting done in the 'loadwallet' RPC command +/** A trait used to help load a different load and discard the current wallet in + * memory This trait encapsulates the heavy lifting done in the 'loadwallet' + * RPC command */ sealed trait DLCWalletLoaderApi extends BitcoinSLogger @@ -42,8 +43,8 @@ sealed trait DLCWalletLoaderApi def load( walletNameOpt: Option[String], - aesPasswordOpt: Option[AesPassword]): Future[ - (WalletHolder, WalletAppConfig, DLCAppConfig)] + aesPasswordOpt: Option[AesPassword] + ): Future[(WalletHolder, WalletAppConfig, DLCAppConfig)] protected def loadWallet( walletHolder: WalletHolder, @@ -51,17 +52,21 @@ sealed trait DLCWalletLoaderApi nodeApi: NodeApi, feeProviderApi: FeeRateApi, walletNameOpt: Option[String], - aesPasswordOpt: Option[AesPassword])(implicit - ec: ExecutionContext): Future[ - (DLCNeutrinoHDWalletApi, WalletAppConfig, DLCAppConfig)] = { + aesPasswordOpt: Option[AesPassword] + )(implicit + ec: ExecutionContext + ): Future[(DLCNeutrinoHDWalletApi, WalletAppConfig, DLCAppConfig)] = { logger.info( - s"Loading wallet with bitcoind backend, walletName=${walletNameOpt.getOrElse("DEFAULT")}") + s"Loading wallet with bitcoind backend, walletName=${walletNameOpt.getOrElse("DEFAULT")}" + ) val walletName = walletNameOpt.getOrElse(WalletAppConfig.DEFAULT_WALLET_NAME) for { - (walletConfig, dlcConfig) <- updateWalletConfigs(walletName, - aesPasswordOpt) + (walletConfig, dlcConfig) <- updateWalletConfigs( + walletName, + aesPasswordOpt + ) _ <- { if (walletHolder.isInitialized) { walletHolder @@ -83,8 +88,8 @@ sealed trait DLCWalletLoaderApi protected def updateWalletConfigs( walletName: String, - aesPasswordOpt: Option[AesPassword])(implicit - ec: ExecutionContext): Future[(WalletAppConfig, DLCAppConfig)] = { + aesPasswordOpt: Option[AesPassword] + )(implicit ec: ExecutionContext): Future[(WalletAppConfig, DLCAppConfig)] = { val walletNameArgOpt = ArgumentSource.RpcArgument(walletName) val aesPasswordArgOpt = aesPasswordOpt match { case None => @@ -93,8 +98,11 @@ sealed trait DLCWalletLoaderApi Some(ArgumentSource.RpcArgument(pw)) } val kmConfigF = Future.successful( - conf.walletConf.kmConf.copy(walletNameOverride = Some(walletNameArgOpt), - aesPasswordOverride = aesPasswordArgOpt)) + conf.walletConf.kmConf.copy( + walletNameOverride = Some(walletNameArgOpt), + aesPasswordOverride = aesPasswordArgOpt + ) + ) (for { kmConfig <- kmConfigF @@ -107,46 +115,49 @@ sealed trait DLCWalletLoaderApi } yield (walletConfig, dlcConfig)) } - protected def updateWalletName(walletNameOpt: Option[String])(implicit - ec: ExecutionContext): Future[Unit] = { + protected def updateWalletName( + walletNameOpt: Option[String] + )(implicit ec: ExecutionContext): Future[Unit] = { val nodeStateDAO: NodeStateDescriptorDAO = NodeStateDescriptorDAO()(ec, conf.nodeConf) nodeStateDAO.updateWalletName(walletNameOpt) } - protected def restartRescanIfNeeded(wallet: DLCNeutrinoHDWalletApi)(implicit - ec: ExecutionContext): Future[RescanState] = { + protected def restartRescanIfNeeded( + wallet: DLCNeutrinoHDWalletApi + )(implicit ec: ExecutionContext): Future[RescanState] = { for { isRescanning <- wallet.isRescanning() res <- if (isRescanning) - wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = - wallet.discoveryBatchSize(), - useCreationTime = true, - force = true) + wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = wallet.discoveryBatchSize(), + useCreationTime = true, + force = true + ) else Future.successful(RescanState.RescanDone) } yield res } - /** Store a rescan state for the wallet that is currently loaded - * This is needed because we don't save rescan state anywhere else. + /** Store a rescan state for the wallet that is currently loaded This is + * needed because we don't save rescan state anywhere else. */ - @volatile private[this] var rescanStateOpt: Option[ - RescanState.RescanStarted] = None + @volatile private[this] var rescanStateOpt + : Option[RescanState.RescanStarted] = None def setRescanState(rescanState: RescanState): Unit = { rescanState match { case RescanState.RescanAlreadyStarted => - //do nothing in this case, we don't need to keep these states around - //don't overwrite the existing reference to RescanStarted + // do nothing in this case, we don't need to keep these states around + // don't overwrite the existing reference to RescanStarted case RescanState.RescanDone | RescanState.RescanNotNeeded => - //rescan is done, reset state + // rescan is done, reset state rescanStateOpt = None case started: RescanState.RescanStarted => if (rescanStateOpt.isEmpty) { - //add callback to reset state when the rescan is done + // add callback to reset state when the rescan is done val resetStateCallbackF = started.entireRescanDoneF.map { _ => rescanStateOpt = None } @@ -156,20 +167,22 @@ sealed trait DLCWalletLoaderApi case scala.util.control.NonFatal(exn) => logger.error( s"Failed to reset rescanState in wallet loader. Resetting rescan state", - exn) + exn + ) rescanStateOpt = None } rescanStateOpt = Some(started) } else { sys.error( - s"Cannot run multiple rescans at the same time, got=$started have=$rescanStateOpt") + s"Cannot run multiple rescans at the same time, got=$started have=$rescanStateOpt" + ) } } } protected def stopRescan()(implicit ec: ExecutionContext): Future[Unit] = { rescanStateOpt match { - case Some(state) => state.stop().map(_ => ()) //stop the rescan + case Some(state) => state.stop().map(_ => ()) // stop the rescan case None => Future.unit } } @@ -188,17 +201,18 @@ sealed trait DLCWalletLoaderApi () } - @volatile private[this] var currentWalletAppConfigOpt: Option[ - WalletAppConfig] = None + @volatile private[this] var currentWalletAppConfigOpt + : Option[WalletAppConfig] = None @volatile private[this] var currentDLCAppConfigOpt: Option[DLCAppConfig] = None protected def stopOldWalletAppConfig( - newWalletConfig: WalletAppConfig): Future[Unit] = { + newWalletConfig: WalletAppConfig + ): Future[Unit] = { currentWalletAppConfigOpt match { case Some(current) => - //stop the old config + // stop the old config current .stop() .map(_ => { @@ -214,10 +228,11 @@ sealed trait DLCWalletLoaderApi } protected def stopOldDLCAppConfig( - newDlcConfig: DLCAppConfig): Future[Unit] = { + newDlcConfig: DLCAppConfig + ): Future[Unit] = { currentDLCAppConfigOpt match { case Some(current) => - //stop the old config + // stop the old config current .stop() .map(_ => { @@ -266,10 +281,11 @@ case class DLCWalletNeutrinoBackendLoader( walletHolder: WalletHolder, chainQueryApi: ChainQueryApi, nodeApi: NodeApi, - feeRateApi: FeeRateApi)(implicit + feeRateApi: FeeRateApi +)(implicit override val conf: BitcoinSAppConfig, - override val system: ActorSystem) - extends DLCWalletLoaderApi { + override val system: ActorSystem +) extends DLCWalletLoaderApi { import system.dispatcher implicit private val nodeConf: NodeAppConfig = conf.nodeConf @@ -278,8 +294,8 @@ case class DLCWalletNeutrinoBackendLoader( override def load( walletNameOpt: Option[String], - aesPasswordOpt: Option[AesPassword]): Future[ - (WalletHolder, WalletAppConfig, DLCAppConfig)] = { + aesPasswordOpt: Option[AesPassword] + ): Future[(WalletHolder, WalletAppConfig, DLCAppConfig)] = { val stopCallbackF = nodeConf.callBacks match { case stream: NodeCallbackStreamManager => stream.stop() @@ -320,17 +336,18 @@ case class DLCWalletBitcoindBackendLoader( walletHolder: WalletHolder, bitcoind: BitcoindRpcClient, nodeApi: NodeApi, - feeProvider: FeeRateApi)(implicit + feeProvider: FeeRateApi +)(implicit override val conf: BitcoinSAppConfig, - override val system: ActorSystem) - extends DLCWalletLoaderApi { + override val system: ActorSystem +) extends DLCWalletLoaderApi { import system.dispatcher implicit private val nodeConf: NodeAppConfig = conf.nodeConf override def load( walletNameOpt: Option[String], - aesPasswordOpt: Option[AesPassword]): Future[ - (WalletHolder, WalletAppConfig, DLCAppConfig)] = { + aesPasswordOpt: Option[AesPassword] + ): Future[(WalletHolder, WalletAppConfig, DLCAppConfig)] = { val stopCallbackF = nodeConf.callBacks match { case stream: NodeCallbackStreamManager => stream.stop() @@ -347,15 +364,17 @@ case class DLCWalletBitcoindBackendLoader( nodeApi = nodeApi, feeProviderApi = feeProvider, walletNameOpt = walletNameOpt, - aesPasswordOpt = aesPasswordOpt) + aesPasswordOpt = aesPasswordOpt + ) _ <- stopOldWalletAppConfig(walletConfig) _ <- stopOldDLCAppConfig(dlcConfig) nodeCallbacks <- CallbackUtil.createBitcoindNodeCallbacksForWallet( - walletHolder) + walletHolder + ) _ = nodeConf.replaceCallbacks(nodeCallbacks) _ <- walletHolder.replaceWallet(dlcWallet) - //do something with possible rescan? + // do something with possible rescan? rescanState <- restartRescanIfNeeded(walletHolder) _ = setRescanState(rescanState) } yield { diff --git a/app/server/src/main/scala/org/bitcoins/server/ServerJsonModels.scala b/app/server/src/main/scala/org/bitcoins/server/ServerJsonModels.scala index 81f95c42a7..d7ed1d057e 100644 --- a/app/server/src/main/scala/org/bitcoins/server/ServerJsonModels.scala +++ b/app/server/src/main/scala/org/bitcoins/server/ServerJsonModels.scala @@ -45,7 +45,9 @@ object DecodeAccept extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length} Expected: 1")) + s"Bad number of arguments: ${other.length} Expected: 1" + ) + ) } } } @@ -75,7 +77,9 @@ object DecodeSign extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length} Expected: 1")) + s"Bad number of arguments: ${other.length} Expected: 1" + ) + ) } } } @@ -97,7 +101,9 @@ object DecodeAttestations extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -106,7 +112,8 @@ case class DLCDataFromFile( path: Path, destinationOpt: Option[Path], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]) + externalChangeAddressOpt: Option[BitcoinAddress] +) object DLCDataFromFile extends ServerJsonModels { @@ -115,7 +122,8 @@ object DLCDataFromFile extends ServerJsonModels { pathJs: Value, destJs: Value, payoutAddressJs: Value, - changeAddressJs: Value) = Try { + changeAddressJs: Value + ) = Try { val path = new File(pathJs.str).toPath val destJsOpt = nullToOpt(destJs) val destOpt = destJsOpt.map(js => new File(js.str).toPath) @@ -143,7 +151,9 @@ object DLCDataFromFile extends ServerJsonModels { case other => Failure( new IllegalArgumentException( - s"Bad number of arguments: ${other.length}. Expected: 1")) + s"Bad number of arguments: ${other.length}. Expected: 1" + ) + ) } } } @@ -151,7 +161,8 @@ object DLCDataFromFile extends ServerJsonModels { case class OfferAdd( offerTLV: DLCOfferTLV, peer: Option[String], - message: Option[String]) + message: Option[String] +) object OfferAdd extends ServerJsonModels { @@ -167,7 +178,8 @@ object OfferAdd extends ServerJsonModels { } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to offer-add, got=${other.length} expected=3") + s"Bad number or arguments to offer-add, got=${other.length} expected=3" + ) Failure(exn) } } @@ -186,7 +198,8 @@ object OfferRemove { } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to offer-remove, got=${other.length} expected=1") + s"Bad number or arguments to offer-remove, got=${other.length} expected=1" + ) Failure(exn) } } @@ -195,7 +208,8 @@ object OfferRemove { case class OfferSend( remoteAddress: InetSocketAddress, message: String, - offerE: Either[DLCOfferTLV, Sha256Digest]) + offerE: Either[DLCOfferTLV, Sha256Digest] +) object OfferSend extends ServerJsonModels { @@ -216,7 +230,8 @@ object OfferSend extends ServerJsonModels { } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to offer-send, got=${other.length} expected=3") + s"Bad number or arguments to offer-send, got=${other.length} expected=3" + ) Failure(exn) } } @@ -236,7 +251,8 @@ object GetDLCOffer { } case other => val exn = new IllegalArgumentException( - s"Bad number or arguments to offer-send, got=${other.length} expected=1") + s"Bad number or arguments to offer-send, got=${other.length} expected=1" + ) Failure(exn) } } @@ -251,7 +267,8 @@ trait ServerJsonModels { case _: Value => throw Value.InvalidData( js, - "Expected an OracleAnnouncementTLV as a hex string") + "Expected an OracleAnnouncementTLV as a hex string" + ) } def jsToContractInfoTLV(js: Value): ContractInfoV0TLV = @@ -311,7 +328,8 @@ trait ServerJsonModels { LockUnspentOutputParameter.fromJson(js) def jsToLockUnspentOutputParameters( - js: Value): Seq[LockUnspentOutputParameter] = { + js: Value + ): Seq[LockUnspentOutputParameter] = { js.arr.foldLeft(Seq.empty[LockUnspentOutputParameter])((seq, outPoint) => seq :+ jsToLockUnspentOutputParameter(outPoint)) } @@ -337,11 +355,13 @@ trait ServerJsonModels { case _: Value => throw Value.InvalidData( js, - "Expected a SchnorrDigitalSignature as a hex string") + "Expected a SchnorrDigitalSignature as a hex string" + ) } def jsToSchnorrDigitalSignatureVec( - js: Value): Vector[SchnorrDigitalSignature] = { + js: Value + ): Vector[SchnorrDigitalSignature] = { js.arr.foldLeft(Vector.empty[SchnorrDigitalSignature])((vec, sig) => vec :+ jsToSchnorrDigitalSignature(sig)) } @@ -353,7 +373,8 @@ trait ServerJsonModels { case _: Value => throw Value.InvalidData( js, - "Expected a OracleAttestmentTLV as a hex string") + "Expected a OracleAttestmentTLV as a hex string" + ) } def jsToOracleAttestmentTLVVec(js: Value): Vector[OracleAttestmentTLV] = { @@ -384,7 +405,8 @@ trait ServerJsonModels { } def jsToWalletNameAndPassword( - js: Value): (Option[String], Option[AesPassword]) = { + js: Value + ): (Option[String], Option[AesPassword]) = { js match { case Arr(arr) => if (arr.size >= 2) { @@ -403,14 +425,16 @@ trait ServerJsonModels { case Arr(arr) => arr.map(_.str).toVector case Null | False | True | Num(_) | Obj(_) => throw new IllegalArgumentException( - "mnemonic must be a string or array of strings") + "mnemonic must be a string or array of strings" + ) } MnemonicCode.fromWords(mnemonicWords) } def jsToInetSocketAddress( js: Value, - defaultPort: Int = -1): InetSocketAddress = { + defaultPort: Int = -1 + ): InetSocketAddress = { js match { case str: Str => val uri = new URI("tcp://" + str.str) diff --git a/app/server/src/main/scala/org/bitcoins/server/WalletRoutes.scala b/app/server/src/main/scala/org/bitcoins/server/WalletRoutes.scala index 57aa8f1346..314b9f960e 100644 --- a/app/server/src/main/scala/org/bitcoins/server/WalletRoutes.scala +++ b/app/server/src/main/scala/org/bitcoins/server/WalletRoutes.scala @@ -37,8 +37,8 @@ import scala.util.{Failure, Success} case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit system: ActorSystem, - walletConf: WalletAppConfig) - extends ServerRoute + walletConf: WalletAppConfig +) extends ServerRoute with BitcoinSLogger { import system.dispatcher @@ -64,7 +64,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit private def handleBroadcastable( tx: Transaction, - noBroadcast: Boolean): Future[NetworkElement] = { + noBroadcast: Boolean + ): Future[NetworkElement] = { if (noBroadcast) { Future.successful(tx) } else { @@ -154,11 +155,14 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit val json = Obj( "confirmed" -> Num( - formatCurrencyUnit(confirmed, isSats).toDouble), + formatCurrencyUnit(confirmed, isSats).toDouble + ), "unconfirmed" -> Num( - formatCurrencyUnit(unconfirmed, isSats).toDouble), + formatCurrencyUnit(unconfirmed, isSats).toDouble + ), "reserved" -> Num( - formatCurrencyUnit(reserved, isSats).toDouble), + formatCurrencyUnit(reserved, isSats).toDouble + ), "total" -> Num(formatCurrencyUnit(total, isSats).toDouble) ) Server.httpSuccess(json) @@ -226,7 +230,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit complete { wallet.tagAddress(address, label).map { tagDb => Server.httpSuccess( - s"Added label \'${tagDb.tagName.name}\' to ${tagDb.address.value}") + s"Added label \'${tagDb.tagName.name}\' to ${tagDb.address.value}" + ) } } } @@ -263,8 +268,10 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit val json: Vector[ujson.Obj] = grouped.map { case (address, labels) => val tagNames: Vector[ujson.Str] = labels.map(l => ujson.Str(l.tagName.name)) - ujson.Obj(("address", address.toString), - ("labels", ujson.Arr.from(tagNames))) + ujson.Obj( + ("address", address.toString), + ("labels", ujson.Arr.from(tagNames)) + ) }.toVector Server.httpSuccess(ujson.Arr.from(json)) } @@ -298,11 +305,15 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit dlcOpt <- wallet.findDLCByTemporaryContractId(tempContractId) dlc = dlcOpt.getOrElse( throw new IllegalArgumentException( - s"Cannot find a DLC with temp contact ID $tempContractId")) + s"Cannot find a DLC with temp contact ID $tempContractId" + ) + ) offerOpt <- wallet.getDLCOffer(dlc.dlcId) offer = offerOpt.getOrElse( throw new IllegalArgumentException( - s"Cannot find an offer with for DLC ID ${dlc.dlcId}")) + s"Cannot find an offer with for DLC ID ${dlc.dlcId}" + ) + ) } yield { Server.httpSuccess(offer.toMessage.hex) } @@ -358,14 +369,17 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit case Failure(exception) => complete(Server.httpBadRequest(exception)) case Success( - CreateDLCOffer(contractInfo, - collateral, - feeRateOpt, - locktimeOpt, - refundLT, - payoutAddressOpt, - changeAddressOpt, - peerAddressOpt)) => + CreateDLCOffer( + contractInfo, + collateral, + feeRateOpt, + locktimeOpt, + refundLT, + payoutAddressOpt, + changeAddressOpt, + peerAddressOpt + ) + ) => complete { val announcements = contractInfo.oracleInfo match { case OracleInfoV0TLV(announcement) => Vector(announcement) @@ -375,29 +389,34 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit if (!announcements.forall(_.validateSignature)) { throw new RuntimeException( s"Received Oracle announcement with invalid signature! ${announcements - .map(_.hex)}") + .map(_.hex)}" + ) } val offerF = locktimeOpt match { case Some(locktime) => wallet - .createDLCOffer(contractInfo, - collateral, - feeRateOpt, - locktime, - refundLT, - peerAddressOpt, - payoutAddressOpt, - changeAddressOpt) + .createDLCOffer( + contractInfo, + collateral, + feeRateOpt, + locktime, + refundLT, + peerAddressOpt, + payoutAddressOpt, + changeAddressOpt + ) case None => wallet - .createDLCOffer(contractInfo, - collateral, - feeRateOpt, - refundLT, - peerAddressOpt, - payoutAddressOpt, - changeAddressOpt) + .createDLCOffer( + contractInfo, + collateral, + feeRateOpt, + refundLT, + peerAddressOpt, + payoutAddressOpt, + changeAddressOpt + ) } offerF.map { offer => @@ -411,16 +430,21 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit case Failure(exception) => complete(Server.httpBadRequest(exception)) case Success( - AcceptDLCOffer(offer, - payoutAddressOpt, - changeAddressOpt, - peerAddressOpt)) => + AcceptDLCOffer( + offer, + payoutAddressOpt, + changeAddressOpt, + peerAddressOpt + ) + ) => complete { wallet - .acceptDLCOffer(offer.tlv, - peerAddressOpt, - payoutAddressOpt, - changeAddressOpt) + .acceptDLCOffer( + offer.tlv, + peerAddressOpt, + payoutAddressOpt, + changeAddressOpt + ) .map { accept => Server.httpSuccess(accept.toMessage.hex) } @@ -432,10 +456,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit case Failure(exception) => complete(Server.httpBadRequest(exception)) case Success( - DLCDataFromFile(path, - destOpt, - payoutAddressOpt, - changeAddressOpt)) => + DLCDataFromFile(path, destOpt, payoutAddressOpt, changeAddressOpt) + ) => complete { val hex = Files.readAllLines(path).get(0) @@ -445,10 +467,12 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit .getOrElse(LnMessage(DLCOfferTLV.fromHex(hex))) wallet - .acceptDLCOffer(offerMessage.tlv, - None, - payoutAddressOpt, - changeAddressOpt) + .acceptDLCOffer( + offerMessage.tlv, + None, + payoutAddressOpt, + changeAddressOpt + ) .map { accept => val ret = handleDestinationOpt(accept.toMessage.hex, destOpt) Server.httpSuccess(ret) @@ -500,7 +524,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit complete { wallet.addDLCSigs(sigs.tlv).map { db => Server.httpSuccess( - s"Successfully added sigs to DLC ${db.contractIdOpt.get.toHex}") + s"Successfully added sigs to DLC ${db.contractIdOpt.get.toHex}" + ) } } } @@ -520,7 +545,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit wallet.addDLCSigs(signMessage.tlv).map { db => Server.httpSuccess( - s"Successfully added sigs to DLC ${db.contractIdOpt.get.toHex}") + s"Successfully added sigs to DLC ${db.contractIdOpt.get.toHex}" + ) } } } @@ -604,7 +630,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit Server.httpSuccess(ret) case None => Server.httpError( - s"Cannot execute DLC with contractId=${contractId.toHex}") + s"Cannot execute DLC with contractId=${contractId.toHex}" + ) } } } @@ -627,15 +654,19 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit case ServerCommand("sendtoaddress", arr) => withValidServerCommand(SendToAddress.fromJsArr(arr)) { - case SendToAddress(address, - bitcoins, - satoshisPerVirtualByteOpt, - noBroadcast) => + case SendToAddress( + address, + bitcoins, + satoshisPerVirtualByteOpt, + noBroadcast + ) => complete { for { - tx <- wallet.sendToAddress(address, - bitcoins, - satoshisPerVirtualByteOpt) + tx <- wallet.sendToAddress( + address, + bitcoins, + satoshisPerVirtualByteOpt + ) retStr <- handleBroadcastable(tx, noBroadcast) } yield { Server.httpSuccess(retStr.hex) @@ -644,16 +675,20 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit } case ServerCommand("sendfromoutpoints", arr) => withValidServerCommand(SendFromOutPoints.fromJsArr(arr)) { - case SendFromOutPoints(outPoints, - address, - bitcoins, - satoshisPerVirtualByteOpt) => + case SendFromOutPoints( + outPoints, + address, + bitcoins, + satoshisPerVirtualByteOpt + ) => complete { for { - tx <- wallet.sendFromOutPoints(outPoints, - address, - bitcoins, - satoshisPerVirtualByteOpt) + tx <- wallet.sendFromOutPoints( + outPoints, + address, + bitcoins, + satoshisPerVirtualByteOpt + ) _ <- wallet.broadcastTransaction(tx) } yield Server.httpSuccess(tx.txIdBE) } @@ -675,10 +710,12 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit case SendWithAlgo(address, bitcoins, satoshisPerVirtualByteOpt, algo) => complete { for { - tx <- wallet.sendWithAlgo(address, - bitcoins, - satoshisPerVirtualByteOpt, - algo) + tx <- wallet.sendWithAlgo( + address, + bitcoins, + satoshisPerVirtualByteOpt, + algo + ) _ <- wallet.broadcastTransaction(tx) } yield Server.httpSuccess(tx.txIdBE) } @@ -698,9 +735,11 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit case OpReturnCommit(message, hashMessage, satoshisPerVirtualByteOpt) => complete { for { - tx <- wallet.makeOpReturnCommitment(message, - hashMessage, - satoshisPerVirtualByteOpt) + tx <- wallet.makeOpReturnCommitment( + message, + hashMessage, + satoshisPerVirtualByteOpt + ) _ <- wallet.broadcastTransaction(tx) } yield { Server.httpSuccess(tx.txIdBE) @@ -838,9 +877,11 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit case KeyManagerPassphraseChange(oldPassword, newPassword) => complete { val path = walletConf.seedPath - WalletStorage.changeAesPassword(path, - Some(oldPassword), - Some(newPassword)) + WalletStorage.changeAesPassword( + path, + Some(oldPassword), + Some(newPassword) + ) Server.httpSuccess(ujson.Null) } @@ -867,16 +908,20 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit val mnemonicState = passwordOpt match { case Some(pass) => - DecryptedMnemonic(mnemonic, - creationTime, - backupTimeOpt = None, - imported = true) + DecryptedMnemonic( + mnemonic, + creationTime, + backupTimeOpt = None, + imported = true + ) .encrypt(pass) case None => - DecryptedMnemonic(mnemonic, - creationTime, - backupTimeOpt = None, - imported = true) + DecryptedMnemonic( + mnemonic, + creationTime, + backupTimeOpt = None, + imported = true + ) } WalletStorage.writeSeedToDisk(seedPath, mnemonicState) @@ -894,7 +939,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit Server.httpSuccess( WalletStorage .readDecryptedSeedPhraseForBackup(seedPath, passwordOpt) - .get) + .get + ) } } @@ -938,16 +984,20 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit val mnemonicState = passwordOpt match { case Some(pass) => - DecryptedExtPrivKey(xprv, - creationTime, - backupTimeOpt = None, - imported = true) + DecryptedExtPrivKey( + xprv, + creationTime, + backupTimeOpt = None, + imported = true + ) .encrypt(pass) case None => - DecryptedExtPrivKey(xprv, - creationTime, - backupTimeOpt = None, - imported = true) + DecryptedExtPrivKey( + xprv, + creationTime, + backupTimeOpt = None, + imported = true + ) } WalletStorage.writeSeedToDisk(seedPath, mnemonicState) @@ -973,7 +1023,7 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit feeRateF.map { f => logger.info(s"Retrieved fee rate ${f.toSatsPerVByte}, it took ${System - .currentTimeMillis() - start}ms") + .currentTimeMillis() - start}ms") Server.httpSuccess(f.toSatsPerVByte) } } @@ -1020,7 +1070,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit .map(_ + "-") .getOrElse(WalletAppConfig.DEFAULT_WALLET_NAME) kmConf.seedFolder.resolve( - walletName + WalletStorage.ENCRYPTED_SEED_FILE_NAME) + walletName + WalletStorage.ENCRYPTED_SEED_FILE_NAME + ) } /** Returns information about the state of our wallet */ @@ -1048,7 +1099,8 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit private def formatCurrencyUnit( currencyUnit: CurrencyUnit, - isSats: Boolean): Double = { + isSats: Boolean + ): Double = { if (isSats) { currencyUnit.satoshis.toBigDecimal.toDouble } else { @@ -1066,19 +1118,21 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit } } - /** Gets the fee rate for the wallet with a timeout on the request of 1 second */ + /** Gets the fee rate for the wallet with a timeout on the request of 1 second + */ private def getFeeRate(): Future[FeeUnit] = { val resultF = wallet .getFeeRate() .recover { case scala.util.control.NonFatal(exn) => logger.error( s"Failed to fetch fee rate from wallet, returning -1 sats/vbyte", - exn) + exn + ) SatoshisPerVirtualByte.negativeOne } - //due to tor variability, we need to make sure we give a prompt response. - //timeout the fee rate request after 1 second - //see: https://github.com/bitcoin-s/bitcoin-s/issues/4460#issuecomment-1182325014 + // due to tor variability, we need to make sure we give a prompt response. + // timeout the fee rate request after 1 second + // see: https://github.com/bitcoin-s/bitcoin-s/issues/4460#issuecomment-1182325014 try { val result = Await.result(resultF, 1.second) Future.successful(result) @@ -1097,15 +1151,15 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit val stateF: Future[RescanState] = rescanState match { case started: RescanState.RescanStarted => if (started.isStopped) { - //means rescan is done, reset the variable + // means rescan is done, reset the variable rescanStateOpt = Some(RescanDone) Future.successful(RescanDone) } else { - //do nothing, we don't want to reset/stop a rescan that is running + // do nothing, we don't want to reset/stop a rescan that is running Future.successful(started) } case RescanState.RescanDone | RescanState.RescanNotNeeded => - //if the previous rescan is done, start another rescan + // if the previous rescan is done, start another rescan startRescan(rescan) case RescanState.RescanAlreadyStarted => Future.successful(RescanState.RescanAlreadyStarted) @@ -1124,7 +1178,9 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit } else { Future.failed( new IllegalArgumentException( - s"Cannot rescan when a rescan is already ongoing for wallet")) + s"Cannot rescan when a rescan is already ongoing for wallet" + ) + ) } } @@ -1149,7 +1205,7 @@ case class WalletRoutes(loadWalletApi: DLCWalletLoaderApi)(implicit } case RescanState.RescanAlreadyStarted | RescanState.RescanDone | RescanState.RescanNotNeeded => - //do nothing in these cases, no state needs to be reset + // do nothing in these cases, no state needs to be reset } stateF diff --git a/app/server/src/main/scala/org/bitcoins/server/WalletZmqSubscribers.scala b/app/server/src/main/scala/org/bitcoins/server/WalletZmqSubscribers.scala index df0f38c64a..21d40e030a 100644 --- a/app/server/src/main/scala/org/bitcoins/server/WalletZmqSubscribers.scala +++ b/app/server/src/main/scala/org/bitcoins/server/WalletZmqSubscribers.scala @@ -7,8 +7,8 @@ import java.util.concurrent.atomic.AtomicBoolean case class WalletZmqSubscribers( rawTxSubscriberOpt: Option[ZMQSubscriber], - rawBlockSubscriberOpt: Option[ZMQSubscriber]) - extends StartStop[Unit] { + rawBlockSubscriberOpt: Option[ZMQSubscriber] +) extends StartStop[Unit] { private val isStarted: AtomicBoolean = new AtomicBoolean(false) override def start(): Unit = { diff --git a/app/server/src/main/scala/org/bitcoins/server/bitcoind/BitcoindSyncState.scala b/app/server/src/main/scala/org/bitcoins/server/bitcoind/BitcoindSyncState.scala index 14490753e0..228392de69 100644 --- a/app/server/src/main/scala/org/bitcoins/server/bitcoind/BitcoindSyncState.scala +++ b/app/server/src/main/scala/org/bitcoins/server/bitcoind/BitcoindSyncState.scala @@ -4,12 +4,17 @@ import org.bitcoins.server.util.{BitcoindPollingCancellable} import scala.concurrent.Future -/** @param syncF the future that will be completed when the synchronization with bitcoind is complete - * @param pollingCancellable You can cancel bitcoind polling by calling [[BitcoindPollingCancellabe.cancel()]] +/** @param syncF + * the future that will be completed when the synchronization with bitcoind + * is complete + * @param pollingCancellable + * You can cancel bitcoind polling by calling + * [[BitcoindPollingCancellabe.cancel()]] */ case class BitcoindSyncState( syncF: Future[Unit], - pollingCancellable: BitcoindPollingCancellable) { + pollingCancellable: BitcoindPollingCancellable +) { /** Stops syncing and polling bitcoind */ def stop(): Future[Unit] = { diff --git a/app/server/src/main/scala/org/bitcoins/server/util/BitcoindPollingCancellabe.scala b/app/server/src/main/scala/org/bitcoins/server/util/BitcoindPollingCancellabe.scala index 4391af0b56..fe70b0ed1f 100644 --- a/app/server/src/main/scala/org/bitcoins/server/util/BitcoindPollingCancellabe.scala +++ b/app/server/src/main/scala/org/bitcoins/server/util/BitcoindPollingCancellabe.scala @@ -5,8 +5,8 @@ import org.bitcoins.commons.util.BitcoinSLogger case class BitcoindPollingCancellable( blockPollingCancellable: Cancellable, - mempoolPollingCancelable: Cancellable) - extends Cancellable + mempoolPollingCancelable: Cancellable +) extends Cancellable with BitcoinSLogger { override def cancel(): Boolean = { @@ -22,5 +22,6 @@ object BitcoindPollingCancellabe { val none: BitcoindPollingCancellable = BitcoindPollingCancellable( Cancellable.alreadyCancelled, - Cancellable.alreadyCancelled) + Cancellable.alreadyCancelled + ) } diff --git a/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala b/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala index 4a753d75e4..d1f41c5733 100644 --- a/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala +++ b/app/server/src/main/scala/org/bitcoins/server/util/CallbackUtil.scala @@ -18,8 +18,8 @@ import scala.concurrent.Future object CallbackUtil extends BitcoinSLogger { def createNeutrinoNodeCallbacksForWallet( - wallet: WalletApi with NeutrinoWalletApi)(implicit - system: ActorSystem): Future[NodeCallbackStreamManager] = { + wallet: WalletApi with NeutrinoWalletApi + )(implicit system: ActorSystem): Future[NodeCallbackStreamManager] = { import system.dispatcher val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction => logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback") @@ -32,7 +32,8 @@ object CallbackUtil extends BitcoinSLogger { Sink.foreachAsync[Vector[(DoubleSha256DigestBE, GolombFilter)]](1) { case blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)] => logger.debug( - s"Executing onCompactFilters callback with filter count=${blockFilters.length}") + s"Executing onCompactFilters callback with filter count=${blockFilters.length}" + ) wallet .processCompactFilters(blockFilters = blockFilters) .map(_ => ()) @@ -42,7 +43,8 @@ object CallbackUtil extends BitcoinSLogger { val blockSink = { Sink.foreachAsync[Block](1) { case block: Block => logger.debug( - s"Executing onBlock callback=${block.blockHeader.hashBE.hex}") + s"Executing onBlock callback=${block.blockHeader.hashBE.hex}" + ) wallet.processBlock(block).map(_ => ()) } } @@ -50,7 +52,8 @@ object CallbackUtil extends BitcoinSLogger { val onHeaderSink = { Sink.foreachAsync(1) { headers: Vector[BlockHeader] => logger.debug( - s"Executing block header with header count=${headers.length}") + s"Executing block header with header count=${headers.length}" + ) if (headers.isEmpty) { Future.unit } else { @@ -85,18 +88,20 @@ object CallbackUtil extends BitcoinSLogger { .map(_ => ()) } - val callbacks = NodeCallbacks(onTxReceived = Vector(onTx), - onBlockReceived = Vector(onBlock), - onCompactFiltersReceived = - Vector(onCompactFilters), - onBlockHeadersReceived = Vector(onHeaders)) + val callbacks = NodeCallbacks( + onTxReceived = Vector(onTx), + onBlockReceived = Vector(onBlock), + onCompactFiltersReceived = Vector(onCompactFilters), + onBlockHeadersReceived = Vector(onHeaders) + ) val streamManager = NodeCallbackStreamManager(callbacks) Future.successful(streamManager) } - def createBitcoindNodeCallbacksForWallet(wallet: DLCNeutrinoHDWalletApi)( - implicit system: ActorSystem): Future[NodeCallbackStreamManager] = { + def createBitcoindNodeCallbacksForWallet( + wallet: DLCNeutrinoHDWalletApi + )(implicit system: ActorSystem): Future[NodeCallbackStreamManager] = { import system.dispatcher val txSink = Sink.foreachAsync[Transaction](1) { case tx: Transaction => logger.debug(s"Receiving transaction txid=${tx.txIdBE.hex} as a callback") diff --git a/app/server/src/main/scala/org/bitcoins/server/util/ChainUtil.scala b/app/server/src/main/scala/org/bitcoins/server/util/ChainUtil.scala index 95cc7d24fc..9ec2173cd9 100644 --- a/app/server/src/main/scala/org/bitcoins/server/util/ChainUtil.scala +++ b/app/server/src/main/scala/org/bitcoins/server/util/ChainUtil.scala @@ -12,8 +12,8 @@ object ChainUtil { def getBlockHeaderResult( hashes: Vector[DoubleSha256DigestBE], - chain: ChainApi)(implicit - ec: ExecutionContext): Future[Vector[GetBlockHeaderResult]] = { + chain: ChainApi + )(implicit ec: ExecutionContext): Future[Vector[GetBlockHeaderResult]] = { val headersF: Future[Vector[Option[BlockHeaderDb]]] = chain.getHeaders(hashes) val bestHeightF = chain.getBestBlockHeader().map(_.height) @@ -30,7 +30,8 @@ object ChainUtil { headersWithConfs.map { case None => sys.error( - s"Could not find block header or confirmations for the header ") + s"Could not find block header or confirmations for the header " + ) case Some((header, confs)) => val chainworkStr = { val bytes = ByteVector(header.chainWork.toByteArray) diff --git a/app/server/src/main/scala/org/bitcoins/server/util/WalletHolderWithLoaderApi.scala b/app/server/src/main/scala/org/bitcoins/server/util/WalletHolderWithLoaderApi.scala index 89cfecccc3..ee573cd29a 100644 --- a/app/server/src/main/scala/org/bitcoins/server/util/WalletHolderWithLoaderApi.scala +++ b/app/server/src/main/scala/org/bitcoins/server/util/WalletHolderWithLoaderApi.scala @@ -15,12 +15,12 @@ sealed trait WalletHolderWithLoaderApi { case class WalletHolderWithNeutrinoLoaderApi( walletHolder: WalletHolder, - loaderApi: DLCWalletNeutrinoBackendLoader) - extends WalletHolderWithLoaderApi + loaderApi: DLCWalletNeutrinoBackendLoader +) extends WalletHolderWithLoaderApi case class WalletHolderWithBitcoindLoaderApi( walletHolder: WalletHolder, - loaderApi: DLCWalletBitcoindBackendLoader) - extends WalletHolderWithLoaderApi { + loaderApi: DLCWalletBitcoindBackendLoader +) extends WalletHolderWithLoaderApi { val bitcoind: BitcoindRpcClient = loaderApi.bitcoind } diff --git a/app/server/src/main/scala/org/bitcoins/server/util/WebsocketUtil.scala b/app/server/src/main/scala/org/bitcoins/server/util/WebsocketUtil.scala index 5343c4cae6..fa4afeb4b0 100644 --- a/app/server/src/main/scala/org/bitcoins/server/util/WebsocketUtil.scala +++ b/app/server/src/main/scala/org/bitcoins/server/util/WebsocketUtil.scala @@ -69,8 +69,8 @@ object WebsocketUtil extends BitcoinSLogger { private def sendHeadersToWs( notifications: Vector[ChainNotification[_]], - queue: SourceQueueWithComplete[WsNotification[_]])(implicit - ec: ExecutionContext): Future[Unit] = { + queue: SourceQueueWithComplete[WsNotification[_]] + )(implicit ec: ExecutionContext): Future[Unit] = { for { _ <- FutureUtil.sequentially(notifications) { case msg => val x: Future[Unit] = queue @@ -83,9 +83,11 @@ object WebsocketUtil extends BitcoinSLogger { def buildChainCallbacks( queue: SourceQueueWithComplete[WsNotification[_]], - chainApi: ChainApi)(implicit + chainApi: ChainApi + )(implicit ec: ExecutionContext, - chainAppConfig: ChainAppConfig): ChainCallbacks = { + chainAppConfig: ChainAppConfig + ): ChainCallbacks = { val onBlockProcessed: OnBlockHeaderConnected = { case headersWithHeight: Vector[(Int, BlockHeader)] => val hashes: Vector[DoubleSha256DigestBE] = @@ -98,7 +100,7 @@ object WebsocketUtil extends BitcoinSLogger { chainAppConfig.ibdBlockProcessedEvents isIBDF.flatMap { isIBD => if (isIBD && !emitBlockProccessedWhileIBDOnGoing) { - //only emit the last header so that we don't overwhelm the UI + // only emit the last header so that we don't overwhelm the UI for { results <- resultsF notification = BlockProcessedNotification(results.last) @@ -166,15 +168,16 @@ object WebsocketUtil extends BitcoinSLogger { ChainCallbacks.onBlockHeaderConnected(onBlockProcessed) + ChainCallbacks.onOnSyncFlagChanged(onSyncFlagChanged) + ChainCallbacks.onCompactFilterHeaderConnected( - onCompactFilterHeaderProcessed) + + onCompactFilterHeaderProcessed + ) + ChainCallbacks.onCompactFilterConnected(onCompactFilterProcessed) } /** Builds websocket callbacks for the wallet */ def buildWalletCallbacks( walletQueue: SourceQueueWithComplete[WsNotification[_]], - walletName: String)(implicit - system: ActorSystem): WalletCallbackStreamManager = { + walletName: String + )(implicit system: ActorSystem): WalletCallbackStreamManager = { import system.dispatcher val onAddressCreated: OnNewAddressGenerated = { addr => val notification = WalletNotification.NewAddressNotification(addr) @@ -183,15 +186,19 @@ object WebsocketUtil extends BitcoinSLogger { } val onTxProcessed: OnTransactionProcessed = { tx => - buildTxNotification(wsType = WalletWsType.TxProcessed, - tx = tx, - walletQueue = walletQueue) + buildTxNotification( + wsType = WalletWsType.TxProcessed, + tx = tx, + walletQueue = walletQueue + ) } val onTxBroadcast: OnTransactionBroadcast = { tx => - buildTxNotification(wsType = WalletWsType.TxBroadcast, - tx = tx, - walletQueue = walletQueue) + buildTxNotification( + wsType = WalletWsType.TxBroadcast, + tx = tx, + walletQueue = walletQueue + ) } val onReservedUtxo: OnReservedUtxos = { utxos => @@ -226,8 +233,9 @@ object WebsocketUtil extends BitcoinSLogger { WalletCallbackStreamManager(callbacks = callbacks) } - def buildTorCallbacks(queue: SourceQueueWithComplete[WsNotification[_]])( - implicit ec: ExecutionContext): TorCallbacks = { + def buildTorCallbacks( + queue: SourceQueueWithComplete[WsNotification[_]] + )(implicit ec: ExecutionContext): TorCallbacks = { val onTorStarted: OnTorStarted = { _ => val notification = TorStartedNotification val offerF = queue.offer(notification) @@ -240,8 +248,8 @@ object WebsocketUtil extends BitcoinSLogger { private def buildTxNotification( wsType: WalletWsType, tx: Transaction, - walletQueue: SourceQueueWithComplete[WsNotification[_]])(implicit - ec: ExecutionContext): Future[Unit] = { + walletQueue: SourceQueueWithComplete[WsNotification[_]] + )(implicit ec: ExecutionContext): Future[Unit] = { val notification = wsType match { case WalletWsType.TxProcessed => WalletNotification.TxProcessedNotification(tx) @@ -259,8 +267,8 @@ object WebsocketUtil extends BitcoinSLogger { } def buildDLCWalletCallbacks( - walletQueue: SourceQueueWithComplete[WsNotification[_]])(implicit - system: ActorSystem): DLCWalletCallbackStreamManager = { + walletQueue: SourceQueueWithComplete[WsNotification[_]] + )(implicit system: ActorSystem): DLCWalletCallbackStreamManager = { import system.dispatcher val onStateChange: OnDLCStateChange = { status: DLCStatus => val notification = WalletNotification.DLCStateChangeNotification(status) @@ -284,14 +292,15 @@ object WebsocketUtil extends BitcoinSLogger { import DLCWalletCallbacks._ val callbacks = onDLCStateChange(onStateChange) + onDLCOfferAdd( - onOfferAdd) + onDLCOfferRemove(onOfferRemove) + onOfferAdd + ) + onDLCOfferRemove(onOfferRemove) DLCWalletCallbackStreamManager(callbacks) } def buildDLCNodeCallbacks( - walletQueue: SourceQueueWithComplete[WsNotification[_]])(implicit - ec: ExecutionContext): DLCNodeCallbacks = { + walletQueue: SourceQueueWithComplete[WsNotification[_]] + )(implicit ec: ExecutionContext): DLCNodeCallbacks = { val onConnectionInitiated: OnPeerConnectionInitiated = { payload => val notification = diff --git a/async-utils/src/main/scala/org/bitcoins/asyncutil/AsyncUtil.scala b/async-utils/src/main/scala/org/bitcoins/asyncutil/AsyncUtil.scala index b3c16cad7d..4f83b1095d 100644 --- a/async-utils/src/main/scala/org/bitcoins/asyncutil/AsyncUtil.scala +++ b/async-utils/src/main/scala/org/bitcoins/asyncutil/AsyncUtil.scala @@ -12,7 +12,8 @@ abstract class AsyncUtil extends AsyncUtilApi { private def retryRunnable( condition: => Boolean, - p: Promise[Boolean]): Runnable = + p: Promise[Boolean] + ): Runnable = new Runnable { override def run(): Unit = { @@ -24,8 +25,8 @@ abstract class AsyncUtil extends AsyncUtilApi { def retryUntilSatisfied( condition: => Boolean, interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL, - maxTries: Int = DEFAULT_MAX_TRIES)(implicit - ec: ExecutionContext): Future[Unit] = { + maxTries: Int = DEFAULT_MAX_TRIES + )(implicit ec: ExecutionContext): Future[Unit] = { val f = () => Future(condition) retryUntilSatisfiedF(f, interval, maxTries) } @@ -35,32 +36,43 @@ abstract class AsyncUtil extends AsyncUtilApi { case object Exponential extends RetryMode /** The returned Future completes when condition becomes true - * @param conditionF The condition being waited on - * @param duration The interval between calls to check condition - * @param maxTries If condition is tried this many times, the Future fails - * @param system An ActorSystem to schedule calls to condition - * @return A Future[Unit] that succeeds if condition becomes true and fails otherwise + * @param conditionF + * The condition being waited on + * @param duration + * The interval between calls to check condition + * @param maxTries + * If condition is tried this many times, the Future fails + * @param system + * An ActorSystem to schedule calls to condition + * @return + * A Future[Unit] that succeeds if condition becomes true and fails + * otherwise */ def retryUntilSatisfiedF( conditionF: () => Future[Boolean], interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL, maxTries: Int = DEFAULT_MAX_TRIES, - mode: RetryMode = Linear)(implicit ec: ExecutionContext): Future[Unit] = { + mode: RetryMode = Linear + )(implicit ec: ExecutionContext): Future[Unit] = { if (mode == Exponential) { val millis = interval.toMillis if (millis > 0) { - require((millis << maxTries) > 0, - s"Too many tries for retryUntilSatisfied(): $maxTries") + require( + (millis << maxTries) > 0, + s"Too many tries for retryUntilSatisfied(): $maxTries" + ) } } val stackTrace: Array[StackTraceElement] = Thread.currentThread().getStackTrace - retryUntilSatisfiedWithCounter(conditionF = conditionF, - interval = interval, - maxTries = maxTries, - stackTrace = stackTrace, - mode = mode) + retryUntilSatisfiedWithCounter( + conditionF = conditionF, + interval = interval, + maxTries = maxTries, + stackTrace = stackTrace, + mode = mode + ) } // Has a different name so that default values are permitted @@ -70,14 +82,18 @@ abstract class AsyncUtil extends AsyncUtilApi { counter: Int = 0, maxTries: Int, stackTrace: Array[StackTraceElement], - mode: RetryMode)(implicit ec: ExecutionContext): Future[Unit] = { + mode: RetryMode + )(implicit ec: ExecutionContext): Future[Unit] = { conditionF().flatMap { condition => if (condition) { Future.unit } else if (counter == maxTries) { - Future.failed(AsyncUtil.RpcRetryException( - s"Condition timed out after $maxTries attempts with interval=$interval waiting periods", - stackTrace)) + Future.failed( + AsyncUtil.RpcRetryException( + s"Condition timed out after $maxTries attempts with interval=$interval waiting periods", + stackTrace + ) + ) } else { val p = Promise[Boolean]() val runnable = retryRunnable(condition, p) @@ -92,32 +108,38 @@ abstract class AsyncUtil extends AsyncUtilApi { p.future.flatMap { case true => Future.unit case false => - retryUntilSatisfiedWithCounter(conditionF = conditionF, - interval = interval, - counter = counter + 1, - maxTries = maxTries, - stackTrace = stackTrace, - mode = mode) + retryUntilSatisfiedWithCounter( + conditionF = conditionF, + interval = interval, + counter = counter + 1, + maxTries = maxTries, + stackTrace = stackTrace, + mode = mode + ) } } } } - /** Returns a future that resolved when the condition becomes true, the condition - * is checked maxTries times, or overallTimeout is reached - * @param condition The blocking condition - * @param duration The interval between calls to check condition - * @param maxTries If condition is tried this many times, an exception is thrown - * @param system An ActorSystem to schedule calls to condition + /** Returns a future that resolved when the condition becomes true, the + * condition is checked maxTries times, or overallTimeout is reached + * @param condition + * The blocking condition + * @param duration + * The interval between calls to check condition + * @param maxTries + * If condition is tried this many times, an exception is thrown + * @param system + * An ActorSystem to schedule calls to condition */ def awaitCondition( condition: () => Boolean, interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL, - maxTries: Int = DEFAULT_MAX_TRIES)(implicit - ec: ExecutionContext): Future[Unit] = { + maxTries: Int = DEFAULT_MAX_TRIES + )(implicit ec: ExecutionContext): Future[Unit] = { - //type hackery here to go from () => Boolean to () => Future[Boolean] - //to make sure we re-evaluate every time retryUntilSatisfied is called + // type hackery here to go from () => Boolean to () => Future[Boolean] + // to make sure we re-evaluate every time retryUntilSatisfied is called def conditionDef: Boolean = condition() val conditionF: () => Future[Boolean] = () => Future(conditionDef) @@ -127,21 +149,25 @@ abstract class AsyncUtil extends AsyncUtilApi { def awaitConditionF( conditionF: () => Future[Boolean], interval: FiniteDuration = AsyncUtil.DEFAULT_INTERVAL, - maxTries: Int = DEFAULT_MAX_TRIES)(implicit - ec: ExecutionContext): Future[Unit] = { + maxTries: Int = DEFAULT_MAX_TRIES + )(implicit ec: ExecutionContext): Future[Unit] = { - retryUntilSatisfiedF(conditionF = conditionF, - interval = interval, - maxTries = maxTries) + retryUntilSatisfiedF( + conditionF = conditionF, + interval = interval, + maxTries = maxTries + ) } override def nonBlockingSleep(duration: FiniteDuration): Future[Unit] = { val p = Promise[Unit]() val r: Runnable = () => p.success(()) - AsyncUtil.scheduler.scheduleOnce(duration.toMillis, - TimeUnit.MILLISECONDS, - r) + AsyncUtil.scheduler.scheduleOnce( + duration.toMillis, + TimeUnit.MILLISECONDS, + r + ) p.future } } @@ -150,8 +176,8 @@ object AsyncUtil extends AsyncUtil { case class RpcRetryException( message: String, - caller: Array[StackTraceElement]) - extends Exception(message) { + caller: Array[StackTraceElement] + ) extends Exception(message) { /* Someone who calls a method in this class will be interested @@ -161,10 +187,12 @@ object AsyncUtil extends AsyncUtil { * * This trims the top of the stack trace to exclude these internal calls. */ - val internalFiles: Vector[String] = Vector("AsyncUtil.scala", - "RpcUtil.scala", - "TestAsyncUtil.scala", - "TestRpcUtil.scala") + val internalFiles: Vector[String] = Vector( + "AsyncUtil.scala", + "RpcUtil.scala", + "TestAsyncUtil.scala", + "TestRpcUtil.scala" + ) private val relevantStackTrace = caller.tail.dropWhile(elem => internalFiles.contains(elem.getFileName)) @@ -182,7 +210,9 @@ object AsyncUtil extends AsyncUtil { */ private[bitcoins] val DEFAULT_MAX_TRIES: Int = 50 - /** Gives you a thread factory with the given prefix with a counter appended to the name */ + /** Gives you a thread factory with the given prefix with a counter appended + * to the name + */ def getNewThreadFactory(prefix: String): ThreadFactory = { new ThreadFactory { private val atomicInteger = new AtomicInteger(0) diff --git a/bench/src/main/scala/org/bitcoins/bench/core/BlockBench.scala b/bench/src/main/scala/org/bitcoins/bench/core/BlockBench.scala index 28c58e5052..0dcc24811a 100644 --- a/bench/src/main/scala/org/bitcoins/bench/core/BlockBench.scala +++ b/bench/src/main/scala/org/bitcoins/bench/core/BlockBench.scala @@ -35,5 +35,5 @@ object BlockBench extends App { 0.until(10).foreach(_ => bench1()) - //bench2() + // bench2() } diff --git a/bench/src/main/scala/org/bitcoins/bench/eclair/EclairBench.scala b/bench/src/main/scala/org/bitcoins/bench/eclair/EclairBench.scala index cb913e8e7e..78b6e9715e 100644 --- a/bench/src/main/scala/org/bitcoins/bench/eclair/EclairBench.scala +++ b/bench/src/main/scala/org/bitcoins/bench/eclair/EclairBench.scala @@ -13,13 +13,15 @@ import scala.concurrent.Future import scala.concurrent.duration.DurationInt import scala.util.{Failure, Success} -/** This test spins up one test node and [[NetworkSize]] sender nodes, which open channels with the test one. - * Then each sender node sends [[PaymentCount]] payments to the test node one by one. For each payment the - * test node generates an invoice and the send node pays it using `sendtonode` API call. +/** This test spins up one test node and [[NetworkSize]] sender nodes, which + * open channels with the test one. Then each sender node sends + * [[PaymentCount]] payments to the test node one by one. For each payment the + * test node generates an invoice and the send node pays it using `sendtonode` + * API call. * - * The test keeps track of times when a payment was initiated, when the payment ID was received, - * and when the corresponding web socket event was received. It writes all results into [[OutputFileName]] - * in CSV format. + * The test keeps track of times when a payment was initiated, when the payment + * ID was received, and when the corresponding web socket event was received. + * It writes all results into [[OutputFileName]] in CSV format. */ object EclairBench extends App with EclairRpcTestUtil { @@ -72,7 +74,8 @@ object EclairBench extends App with EclairRpcTestUtil { def sendPayments( network: EclairNetwork, amount: MilliSatoshis, - count: Int): Future[Vector[PaymentId]] = + count: Int + ): Future[Vector[PaymentId]] = for { _ <- network.testEclairNode.getInfo paymentIds <- Future.sequence(network.networkEclairNodes.map { node => @@ -104,22 +107,26 @@ object EclairBench extends App with EclairRpcTestUtil { val _ = logEvent(event) } _ = println( - s"Set up $NetworkSize nodes, that will send $PaymentCount payments to the test node each") + s"Set up $NetworkSize nodes, that will send $PaymentCount payments to the test node each" + ) _ = println( s"Test node data directory: ${network.testEclairNode.instance.authCredentials.datadir - .getOrElse("")}") + .getOrElse("")}" + ) _ = println("Testing...") _ <- sendPayments(network, PaymentAmount, PaymentCount) _ <- TestAsyncUtil.retryUntilSatisfied( condition = paymentLog.size() == NetworkSize * PaymentCount, interval = 1.second, - maxTries = 100) + maxTries = 100 + ) _ <- TestAsyncUtil .retryUntilSatisfied( condition = EclairBenchUtil.paymentLogValues().forall(_.completed), interval = 1.second, - maxTries = 100) + maxTries = 100 + ) .recover { case ex: Throwable => ex.printStackTrace() } _ = println("\nDone!") } yield { @@ -128,13 +135,15 @@ object EclairBench extends App with EclairRpcTestUtil { } val res: Future[Unit] = for { - network <- EclairNetwork.start(TestEclairVersion, - TestEclairCommit, - SenderEclairVersion, - SenderEclairCommit, - NetworkSize, - ChannelAmount, - LogbackXml) + network <- EclairNetwork.start( + TestEclairVersion, + TestEclairCommit, + SenderEclairVersion, + SenderEclairCommit, + NetworkSize, + ChannelAmount, + LogbackXml + ) log <- runTests(network).recoverWith { case e: Throwable => e.printStackTrace() Future.successful(Vector.empty[PaymentLogEntry]) @@ -145,17 +154,20 @@ object EclairBench extends App with EclairRpcTestUtil { val first = log.head val csv = Vector( - "time,number_of_payments,payment_hash,payment_id,event,payment_sent_at,payment_id_received_at,event_received_at,received_in,completed_in") ++ + "time,number_of_payments,payment_hash,payment_id,event,payment_sent_at,payment_id_received_at,event_received_at,received_in,completed_in" + ) ++ log.zipWithIndex .map { case (x, i) => s"${x.paymentSentAt - first.paymentSentAt},${i + 1},${x.toCSV}" } val outputFile = new File(OutputFileName) - Files.write(outputFile.toPath, - EclairBenchUtil.convertStrings(csv), - StandardOpenOption.CREATE, - StandardOpenOption.WRITE, - StandardOpenOption.TRUNCATE_EXISTING) + Files.write( + outputFile.toPath, + EclairBenchUtil.convertStrings(csv), + StandardOpenOption.CREATE, + StandardOpenOption.WRITE, + StandardOpenOption.TRUNCATE_EXISTING + ) println(s"The test results was written in ${outputFile.getAbsolutePath}") } } diff --git a/bench/src/main/scala/org/bitcoins/bench/eclair/PaymentLog.scala b/bench/src/main/scala/org/bitcoins/bench/eclair/PaymentLog.scala index 4f3015d5bc..9454024c48 100644 --- a/bench/src/main/scala/org/bitcoins/bench/eclair/PaymentLog.scala +++ b/bench/src/main/scala/org/bitcoins/bench/eclair/PaymentLog.scala @@ -22,11 +22,14 @@ object PaymentLog { event: Option[WebSocketEvent] = None, paymentSentAt: Long, paymentIdReceivedAt: Long = 0, - eventReceivedAt: Long = 0) { + eventReceivedAt: Long = 0 + ) { def withPaymentHash(paymentHash: Sha256Digest): PaymentLogEntry = - copy(paymentHash = Some(paymentHash), - paymentSentAt = System.currentTimeMillis()) + copy( + paymentHash = Some(paymentHash), + paymentSentAt = System.currentTimeMillis() + ) def withPaymentId(id: PaymentId): PaymentLogEntry = copy(id = Some(id), paymentIdReceivedAt = System.currentTimeMillis()) @@ -47,7 +50,8 @@ object PaymentLog { part.timestamp.toEpochMilli case None => throw new RuntimeException( - s"PaymentReceived but with no parts, got $e") + s"PaymentReceived but with no parts, got $e" + ) } case PaymentFailed(_, _, _, timestamp) => timestamp.toEpochMilli case _: WebSocketEvent => @@ -57,18 +61,21 @@ object PaymentLog { def toCSV: String = s"""${paymentHash - .map(_.hex) - .getOrElse("")},${id.map(_.toString).getOrElse("")},${event - .map(_.getClass.getName.split('$').last) - .getOrElse( - "")},$paymentSentAt,$paymentIdReceivedAt,$eventReceivedAt,${paymentIdReceivedAt - paymentSentAt},${eventReceivedAt - paymentIdReceivedAt}""" + .map(_.hex) + .getOrElse("")},${id.map(_.toString).getOrElse("")},${event + .map(_.getClass.getName.split('$').last) + .getOrElse( + "" + )},$paymentSentAt,$paymentIdReceivedAt,$eventReceivedAt,${paymentIdReceivedAt - paymentSentAt},${eventReceivedAt - paymentIdReceivedAt}""" } object PaymentLogEntry { def apply(paymentHash: Sha256Digest): PaymentLogEntry = { - PaymentLogEntry(paymentSentAt = System.currentTimeMillis(), - paymentHash = Some(paymentHash)) + PaymentLogEntry( + paymentSentAt = System.currentTimeMillis(), + paymentHash = Some(paymentHash) + ) } } @@ -87,13 +94,15 @@ object PaymentLog { def logPaymentId( paymentHash: Sha256Digest, - paymentId: PaymentId): PaymentLogEntry = { + paymentId: PaymentId + ): PaymentLogEntry = { paymentLog.compute( paymentHash, new BiFunction[Sha256Digest, PaymentLogEntry, PaymentLogEntry] { override def apply( hash: Sha256Digest, - old: PaymentLogEntry): PaymentLogEntry = { + old: PaymentLogEntry + ): PaymentLogEntry = { val log = if (old == null) { PaymentLogEntry(paymentSentAt = 0, paymentHash = Some(hash)) } else { @@ -121,7 +130,8 @@ object PaymentLog { new BiFunction[Sha256Digest, PaymentLogEntry, PaymentLogEntry] { override def apply( hash: Sha256Digest, - old: PaymentLogEntry): PaymentLogEntry = { + old: PaymentLogEntry + ): PaymentLogEntry = { val log = if (old == null) { PaymentLogEntry(paymentSentAt = 0, paymentHash = Some(hash)) } else { @@ -136,7 +146,8 @@ object PaymentLog { new BiFunction[Sha256Digest, Promise[Unit], Promise[Unit]] { override def apply( hash: Sha256Digest, - old: Promise[Unit]): Promise[Unit] = { + old: Promise[Unit] + ): Promise[Unit] = { val promise = if (old == null) { Promise[Unit]() } else { diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/BitcoindInstanceTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/BitcoindInstanceTest.scala index 616473d79d..9476f405d4 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/BitcoindInstanceTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/BitcoindInstanceTest.scala @@ -39,8 +39,8 @@ class BitcoindInstanceTest extends BitcoindRpcTest { pw.close() } - /** Tests that the client can call the isStartedF method - * without throwing and then start + /** Tests that the client can call the isStartedF method without throwing and + * then start */ private def testClientStart(client: BitcoindRpcClient): Future[Assertion] = synchronized { @@ -71,7 +71,8 @@ class BitcoindInstanceTest extends BitcoindRpcTest { val instance = BitcoindInstanceLocal.fromConfig(conf, newestBitcoindBinary) assert( instance.authCredentials - .isInstanceOf[BitcoindAuthCredentials.CookieBased]) + .isInstanceOf[BitcoindAuthCredentials.CookieBased] + ) val cli = BitcoindRpcClient.withActorSystem(instance) testClientStart(cli) @@ -91,7 +92,8 @@ class BitcoindInstanceTest extends BitcoindRpcTest { val instance = BitcoindInstanceLocal.fromConfig(conf, newestBitcoindBinary) assert( instance.authCredentials - .isInstanceOf[BitcoindAuthCredentials.PasswordBased]) + .isInstanceOf[BitcoindAuthCredentials.PasswordBased] + ) testClientStart(BitcoindRpcClient.withActorSystem(instance)) } @@ -116,8 +118,10 @@ class BitcoindInstanceTest extends BitcoindRpcTest { val conf = BitcoindConfig(confStr, FileUtil.tmpDir()) val authCredentials = - BitcoindAuthCredentials.PasswordBased(username = "bitcoin-s", - password = "strong_password") + BitcoindAuthCredentials.PasswordBased( + username = "bitcoin-s", + password = "strong_password" + ) val instance = BitcoindInstanceLocal( network = RegTest, @@ -167,8 +171,10 @@ class BitcoindInstanceTest extends BitcoindRpcTest { val conf = BitcoindConfig(confStr, FileUtil.tmpDir()) val authCredentials = - BitcoindAuthCredentials.PasswordBased(username = "bitcoin-s", - password = "strong_password") + BitcoindAuthCredentials.PasswordBased( + username = "bitcoin-s", + password = "strong_password" + ) val instance = BitcoindInstanceLocal( network = RegTest, diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/TestRpcUtilTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/TestRpcUtilTest.scala index f75205c37a..96fd676758 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/TestRpcUtilTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/TestRpcUtilTest.scala @@ -35,7 +35,8 @@ class TestRpcUtilTest extends BitcoindFixturesCachedPairNewest { assert(dir.isDirectory) assert(dir.getPath().startsWith(scala.util.Properties.tmpDir)) assert( - dir.listFiles.contains(new File(dir.getAbsolutePath + "/bitcoin.conf"))) + dir.listFiles.contains(new File(dir.getAbsolutePath + "/bitcoin.conf")) + ) FileUtil.deleteTmpDir(dir) assert(!dir.exists) } @@ -63,15 +64,18 @@ class TestRpcUtilTest extends BitcoindFixturesCachedPairNewest { val allClients = nodes.toVector for { heightPreGeneration <- first.getBlockCount() - _ <- BitcoindRpcTestUtil.generateAllAndSync(allClients, - blocks = blocksToGenerate) + _ <- BitcoindRpcTestUtil.generateAllAndSync( + allClients, + blocks = blocksToGenerate + ) firstHash <- first.getBestBlockHash() secondHash <- second.getBestBlockHash() heightPostGeneration <- first.getBlockCount() } yield { assert(firstHash == secondHash) assert( - heightPostGeneration - heightPreGeneration == blocksToGenerate * allClients.length) + heightPostGeneration - heightPreGeneration == blocksToGenerate * allClients.length + ) } } @@ -82,10 +86,12 @@ class TestRpcUtilTest extends BitcoindFixturesCachedPairNewest { address <- second.getNewAddress txid <- first.sendToAddress(address, Bitcoins.one) hashes <- BitcoindRpcTestUtil.generateAndSync(Vector(first, second)) - vout <- BitcoindRpcTestUtil.findOutput(first, - txid, - Bitcoins.one, - Some(hashes.head)) + vout <- BitcoindRpcTestUtil.findOutput( + first, + txid, + Bitcoins.one, + Some(hashes.head) + ) tx <- first.getRawTransaction(txid, Some(hashes.head)) } yield { assert(tx.vout(vout.toInt).value == Bitcoins.one) diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/BlockchainRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/BlockchainRpcTest.scala index 530e62600f..e7b3d343df 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/BlockchainRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/BlockchainRpcTest.scala @@ -230,10 +230,13 @@ class BlockchainRpcTest extends BitcoindFixturesCachedPairNewest { txs <- Future.sequence( block.transactions .filterNot(_.isCoinbase) - .map(tx => client.getTransaction(tx.txIdBE))) + .map(tx => client.getTransaction(tx.txIdBE)) + ) - prevFilter <- client.getBlockFilter(block.blockHeader.previousBlockHashBE, - FilterType.Basic) + prevFilter <- client.getBlockFilter( + block.blockHeader.previousBlockHashBE, + FilterType.Basic + ) } yield { val pubKeys = txs.flatMap(_.hex.outputs.map(_.scriptPubKey)).toVector val filter = BlockFilter(block, pubKeys) @@ -242,7 +245,8 @@ class BlockchainRpcTest extends BitcoindFixturesCachedPairNewest { blockFilter.header == filter .getHeader(prevFilter.header.flip) .hash - .flip) + .flip + ) } } } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MempoolRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MempoolRpcTest.scala index ff490d9f10..b0bef4e04a 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MempoolRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MempoolRpcTest.scala @@ -132,17 +132,21 @@ class MempoolRpcTest extends BitcoindFixturesCachedPairNewest { for { _ <- client.generate(1) address1 <- client.getNewAddress - txid1 <- BitcoindRpcTestUtil.fundMemPoolTransaction(client, - address1, - Bitcoins(2)) + txid1 <- BitcoindRpcTestUtil.fundMemPoolTransaction( + client, + address1, + Bitcoins(2) + ) mempool <- client.getRawMemPool address2 <- client.getNewAddress createdTx <- { val input: TransactionInput = - TransactionInput(TransactionOutPoint(txid1.flip, UInt32.zero), - ScriptSignature.empty, - UInt32.max - UInt32.one) + TransactionInput( + TransactionOutPoint(txid1.flip, UInt32.zero), + ScriptSignature.empty, + UInt32.max - UInt32.one + ) client .createRawTransaction(Vector(input), Map(address2 -> Bitcoins.one)) } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MessageRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MessageRpcTest.scala index f904cb52aa..48068e0a30 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MessageRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MessageRpcTest.scala @@ -37,8 +37,10 @@ class MessageRpcTest extends BitcoindRpcTest { for { client <- clientF - signature <- client.signMessageWithPrivKey(privKey.toPrivateKeyBytes(), - message) + signature <- client.signMessageWithPrivKey( + privKey.toPrivateKeyBytes(), + message + ) validity <- client.verifyMessage(address, signature, message) } yield assert(validity) } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MiningRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MiningRpcTest.scala index 90c559cedf..407d53cca1 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MiningRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MiningRpcTest.scala @@ -56,12 +56,15 @@ class MiningRpcTest extends BitcoindRpcTest { TransactionInput( TransactionOutPoint(output.txid.flip, UInt32(output.vout)), ScriptSignature.empty, - UInt32.max - UInt32(2)) + UInt32.max - UInt32(2) + ) val inputs = Vector(input) val outputs = - Map(address -> Bitcoins(0.5), - changeAddress -> Bitcoins(output.amount.toBigDecimal - 0.55)) + Map( + address -> Bitcoins(0.5), + changeAddress -> Bitcoins(output.amount.toBigDecimal - 0.55) + ) client.createRawTransaction(inputs, outputs) } @@ -97,7 +100,9 @@ class MiningRpcTest extends BitcoindRpcTest { foundBlocks.foreach { case found: GetBlockWithTransactionsResultV22 => assert( found.tx.exists( - _.vout.exists(_.scriptPubKey.address == Some(address)))) + _.vout.exists(_.scriptPubKey.address == Some(address)) + ) + ) } succeed } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MultiWalletRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MultiWalletRpcTest.scala index 36fcb6a186..e400cf9d1f 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MultiWalletRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MultiWalletRpcTest.scala @@ -23,7 +23,9 @@ import java.io.File import scala.concurrent.Future import scala.concurrent.duration.DurationInt -/** These tests are all copied over from WalletRpcTest and changed to be for multi-wallet */ +/** These tests are all copied over from WalletRpcTest and changed to be for + * multi-wallet + */ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest { val walletName = "other" @@ -43,9 +45,12 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest { clientsF.flatMap(setupWalletClient) } - /** We need to test bitcoin core's wallet specific features, so we need to set that up */ - private def setupWalletClient(pair: NodePair[BitcoindRpcClient]): Future[ - NodePair[BitcoindRpcClient]] = { + /** We need to test bitcoin core's wallet specific features, so we need to set + * that up + */ + private def setupWalletClient( + pair: NodePair[BitcoindRpcClient] + ): Future[NodePair[BitcoindRpcClient]] = { val NodePair(client: BitcoindRpcClient, walletClient: BitcoindRpcClient) = pair for { @@ -228,9 +233,11 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest { for { address <- otherClient.getNewAddress(Some(walletName)) _ <- client.walletPassphrase(password, 1000, Some(walletName)) - txid <- client.sendToAddress(address, - Bitcoins(1), - walletNameOpt = Some(walletName)) + txid <- client.sendToAddress( + address, + Bitcoins(1), + walletNameOpt = Some(walletName) + ) transaction <- client.getTransaction(txid, walletNameOpt = Some(walletName)) } yield { @@ -248,8 +255,10 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest { _ <- client.walletPassphrase(password, 1000, Some(walletName)) txid <- client - .sendMany(Map(address1 -> Bitcoins(1), address2 -> Bitcoins(2)), - walletNameOpt = Some(walletName)) + .sendMany( + Map(address1 -> Bitcoins(1), address2 -> Bitcoins(2)), + walletNameOpt = Some(walletName) + ) transaction <- client.getTransaction(txid, walletNameOpt = Some(walletName)) } yield { @@ -286,20 +295,27 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest { for { firstResult <- client - .createMultiSig(2, - Vector(privKey1.publicKey, privKey2.publicKey), - AddressType.Bech32, - walletNameOpt = Some(walletName)) + .createMultiSig( + 2, + Vector(privKey1.publicKey, privKey2.publicKey), + AddressType.Bech32, + walletNameOpt = Some(walletName) + ) address2 = firstResult.address secondResult <- client .importMulti( Vector( - RpcOpts.ImportMultiRequest(RpcOpts.ImportMultiAddress(address1), - UInt32(0)), - RpcOpts.ImportMultiRequest(RpcOpts.ImportMultiAddress(address2), - UInt32(0))), + RpcOpts.ImportMultiRequest( + RpcOpts.ImportMultiAddress(address1), + UInt32(0) + ), + RpcOpts.ImportMultiRequest( + RpcOpts.ImportMultiAddress(address2), + UInt32(0) + ) + ), rescan = false, walletNameOpt = Some(walletName) ) @@ -343,7 +359,9 @@ class MultiWalletRpcTest extends BitcoindFixturesCachedPairNewest { assert(transaction.inputs.length == 1) assert( transaction.outputs.contains( - TransactionOutput(Bitcoins(1), address.scriptPubKey))) + TransactionOutput(Bitcoins(1), address.scriptPubKey) + ) + ) } } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MultisigRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MultisigRpcTest.scala index b3e59648f5..aefa8f9a83 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MultisigRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/MultisigRpcTest.scala @@ -15,8 +15,10 @@ class MultisigRpcTest extends BitcoindRpcTest { BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest)) lazy val clientF: Future[BitcoindRpcClient] = - BitcoindRpcTestUtil.startedBitcoindRpcClient(instanceOpt = Some(instance), - clientAccum = clientAccum) + BitcoindRpcTestUtil.startedBitcoindRpcClient( + instanceOpt = Some(instance), + clientAccum = clientAccum + ) behavior of "MultisigRpc" @@ -29,9 +31,11 @@ class MultisigRpcTest extends BitcoindRpcTest { for { client <- clientF - _ <- client.createMultiSig(2, - Vector(pubKey1, pubKey2), - AddressType.Bech32) + _ <- client.createMultiSig( + 2, + Vector(pubKey1, pubKey2), + AddressType.Bech32 + ) } yield succeed } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/RawTransactionRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/RawTransactionRpcTest.scala index 7a3a900cf4..736c276c69 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/RawTransactionRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/RawTransactionRpcTest.scala @@ -98,14 +98,20 @@ class RawTransactionRpcTest extends BitcoindRpcTest { address <- otherClient.getNewAddress - input0 = TransactionOutPoint(transaction0.txid.flip, - UInt32(transaction0.blockindex.get)) - input1 = TransactionOutPoint(transaction1.txid.flip, - UInt32(transaction1.blockindex.get)) + input0 = TransactionOutPoint( + transaction0.txid.flip, + UInt32(transaction0.blockindex.get) + ) + input1 = TransactionOutPoint( + transaction1.txid.flip, + UInt32(transaction1.blockindex.get) + ) transaction <- { val sig: ScriptSignature = ScriptSignature.empty - val inputs = Vector(TransactionInput(input0, sig, UInt32(1)), - TransactionInput(input1, sig, UInt32(2))) + val inputs = Vector( + TransactionInput(input0, sig, UInt32(1)), + TransactionInput(input1, sig, UInt32(2)) + ) val outputs = Map(address -> Bitcoins(1)) client.createRawTransaction(inputs, outputs) } @@ -150,12 +156,16 @@ class RawTransactionRpcTest extends BitcoindRpcTest { newAddress <- client.getNewAddress rawCreatedTx <- { val input = - TransactionInput(TransactionOutPoint(txid.flip, UInt32(output.n)), - EmptyScriptSignature, - UInt32.max - UInt32.one) + TransactionInput( + TransactionOutPoint(txid.flip, UInt32(output.n)), + EmptyScriptSignature, + UInt32.max - UInt32.one + ) client - .createRawTransaction(Vector(input), - Map(newAddress -> Bitcoins(sendAmt.satoshis))) + .createRawTransaction( + Vector(input), + Map(newAddress -> Bitcoins(sendAmt.satoshis)) + ) } result <- { @@ -166,7 +176,8 @@ class RawTransactionRpcTest extends BitcoindRpcTest { scriptPubKey = ScriptPubKey.fromAsmHex(output.scriptPubKey.hex), redeemScript = None, amount = Some(fundAmt) - )) + ) + ) BitcoindRpcTestUtil.signRawTransaction( client, rawCreatedTx, @@ -183,7 +194,8 @@ class RawTransactionRpcTest extends BitcoindRpcTest { .createRawTransaction(Vector(), Map(address -> Bitcoins(1))) .flatMap { tx => recoverToSucceededIf[InvalidAddressOrKey]( - client.abandonTransaction(tx.txId)) + client.abandonTransaction(tx.txId) + ) } } } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/UTXORpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/UTXORpcTest.scala index d491a80115..810e3904ab 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/UTXORpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/UTXORpcTest.scala @@ -35,8 +35,10 @@ class UTXORpcTest extends BitcoindRpcTest { val vout1 = unspent(0).vout val vout2 = unspent(1).vout - Vector(RpcOpts.LockUnspentOutputParameter(txid1, vout1), - RpcOpts.LockUnspentOutputParameter(txid2, vout2)) + Vector( + RpcOpts.LockUnspentOutputParameter(txid1, vout1), + RpcOpts.LockUnspentOutputParameter(txid2, vout2) + ) } firstSuccess <- client.lockUnspent(unlock = false, param) locked <- client.listLockUnspent diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala index b13cac590b..30b052e131 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/common/WalletRpcTest.scala @@ -52,7 +52,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { lazy val walletClientF: Future[BitcoindRpcClient] = clientsF.flatMap { _ => val walletClient = BitcoindRpcClient.withActorSystem( - BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest))) + BitcoindRpcTestUtil.instance(versionOpt = Some(BitcoindVersion.newest)) + ) for { _ <- startClient(walletClient) @@ -126,10 +127,12 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { for { _ <- { val addrFuts = - List(client.getNewAddress, - client.getNewAddress(AddressType.Bech32), - client.getNewAddress(AddressType.P2SHSegwit), - client.getNewAddress(AddressType.Legacy)) + List( + client.getNewAddress, + client.getNewAddress(AddressType.Bech32), + client.getNewAddress(AddressType.P2SHSegwit), + client.getNewAddress(AddressType.Legacy) + ) Future.sequence(addrFuts) } } yield succeed @@ -166,8 +169,10 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { val client = nodePair.node1 for { balance <- client.getUnconfirmedBalance - transaction <- BitcoindRpcTestUtil.sendCoinbaseTransaction(client, - client) + transaction <- BitcoindRpcTestUtil.sendCoinbaseTransaction( + client, + client + ) newBalance <- client.getUnconfirmedBalance } yield { assert(balance == Bitcoins(0)) @@ -188,7 +193,7 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { } it should "be able to refill the keypool" ignore { nodePair: FixtureParam => - //ignore until: https://github.com/bitcoin/bitcoin/issues/29924 + // ignore until: https://github.com/bitcoin/bitcoin/issues/29924 val client = nodePair.node1 for { info <- client.getWalletInfo @@ -228,15 +233,18 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { def getChangeAddressAndAmount( client: BitcoindRpcClient, address: BitcoinAddress, - txid: DoubleSha256DigestBE): Future[(BitcoinAddress, CurrencyUnit)] = { + txid: DoubleSha256DigestBE + ): Future[(BitcoinAddress, CurrencyUnit)] = { for { rawTx <- client.getRawTransactionRaw(txid) } yield { val outs = rawTx.outputs.filterNot(_.value == amount) val changeAddresses = outs .map(out => - (BitcoinAddress.fromScriptPubKey(out.scriptPubKey, networkParam), - out.value)) + ( + BitcoinAddress.fromScriptPubKey(out.scriptPubKey, networkParam), + out.value + )) assert(changeAddresses.size == 1) assert(changeAddresses.head._1 != address) (changeAddresses.head._1, changeAddresses.head._2) @@ -248,10 +256,12 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { address <- client.getNewAddress - txid <- BitcoindRpcTestUtil.fundBlockChainTransaction(client, - otherClient, - address, - amount) + txid <- BitcoindRpcTestUtil.fundBlockChainTransaction( + client, + otherClient, + address, + amount + ) (changeAddress, changeAmount) <- getChangeAddressAndAmount(client, address, txid) @@ -269,7 +279,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { // the change address should be added to an exiting address grouping assert( - !groupingsBefore.exists(vec => vec.exists(_.address == changeAddress))) + !groupingsBefore.exists(vec => vec.exists(_.address == changeAddress)) + ) val changeGroupingOpt = groupingsAfter.find(vec => vec.exists(_.address == changeAddress)) @@ -324,10 +335,12 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { address <- otherClient.getNewAddress txid <- BitcoindRpcTestUtil - .fundBlockChainTransaction(client, - otherClient, - address, - Bitcoins(1.5)) + .fundBlockChainTransaction( + client, + otherClient, + address, + Bitcoins(1.5) + ) receivedList <- otherClient.listReceivedByAddress() } yield { val entryList = @@ -348,10 +361,12 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { address <- otherClient.getNewAddress txid <- BitcoindRpcTestUtil - .fundBlockChainTransaction(client, - otherClient, - address, - Bitcoins(1.5)) + .fundBlockChainTransaction( + client, + otherClient, + address, + Bitcoins(1.5) + ) txs <- otherClient.listTransactions() } yield { assert(txs.nonEmpty) @@ -419,12 +434,15 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { TransactionInput( TransactionOutPoint(output.txid.flip, UInt32(output.vout)), ScriptSignature.empty, - UInt32.max - UInt32(2)) + UInt32.max - UInt32(2) + ) val inputs = Vector(input) val outputs = - Map(address -> Bitcoins(0.5), - changeAddress -> Bitcoins(output.amount.toBigDecimal - 0.55)) + Map( + address -> Bitcoins(0.5), + changeAddress -> Bitcoins(output.amount.toBigDecimal - 0.55) + ) client.createRawTransaction(inputs, outputs) } @@ -453,7 +471,9 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { } yield { assert( transaction.outputs.contains( - TransactionOutput(Bitcoins(1), address.scriptPubKey))) + TransactionOutput(Bitcoins(1), address.scriptPubKey) + ) + ) } } @@ -467,23 +487,31 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { val spk = P2WPKHWitnessSPKV0(privKey.publicKey) val importedAddress = Bech32Address.fromScriptPubKey(spk, np) for { - fundingTxId <- otherClient.sendToAddress(importedAddress, - Bitcoins(1.01)) + fundingTxId <- otherClient.sendToAddress( + importedAddress, + Bitcoins(1.01) + ) _ <- otherClient.generate(1) vout <- otherClient .getRawTransactionRaw(fundingTxId) - .map(_.outputs.zipWithIndex.find( - _._1.scriptPubKey == descriptor.scriptPubKey)) + .map( + _.outputs.zipWithIndex + .find(_._1.scriptPubKey == descriptor.scriptPubKey) + ) .map(_.get._2) fundingPrevOut = TransactionOutPoint(fundingTxId, vout) - fundingInput = TransactionInput(fundingPrevOut, - ScriptSignature.empty, - TransactionConstants.sequence) + fundingInput = TransactionInput( + fundingPrevOut, + ScriptSignature.empty, + TransactionConstants.sequence + ) address <- otherClient.getNewAddress transaction <- client - .createRawTransaction(inputs = Vector(fundingInput), - outputs = Map(address -> Bitcoins.one)) + .createRawTransaction( + inputs = Vector(fundingInput), + outputs = Map(address -> Bitcoins.one) + ) signedTx <- client .signRawTransactionWithKey(transaction, Vector(privKey)) .map(_.hex) @@ -499,7 +527,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { P2WPKHV0InputInfo(outPoint, output.value, privKey.publicKey), prevTx, privKey, - HashType.sigHashAll), + HashType.sigHashAll + ), transaction, isDummySignature = false ) @@ -507,7 +536,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { signedTx match { case btx: NonWitnessTransaction => assert( - btx.inputs.head.scriptSignature.signatures.head == partialSig.signature) + btx.inputs.head.scriptSignature.signatures.head == partialSig.signature + ) case wtx: WitnessTransaction => wtx.witness.head match { case p2wpkh: P2WPKHWitnessV0 => @@ -552,7 +582,8 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { val psbt = PSBT.fromBase64( - "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==") + "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==" + ) for { result <- client.utxoUpdatePsbt(psbt, Seq(descriptor)) @@ -578,15 +609,19 @@ class WalletRpcTest extends BitcoindFixturesCachedPairNewest { val pubKey2 = ECPublicKey.freshPublicKey for { - multiSigResult <- client.createMultiSig(2, - Vector(pubKey1, pubKey2), - AddressType.Bech32) + multiSigResult <- client.createMultiSig( + 2, + Vector(pubKey1, pubKey2), + AddressType.Bech32 + ) } yield { // just validate we are able to receive a sane descriptor // no need to check checksum assert( multiSigResult.descriptor.startsWith( - s"wsh(multi(2,${pubKey1.hex},${pubKey2.hex}))#")) + s"wsh(multi(2,${pubKey1.hex},${pubKey2.hex}))#" + ) + ) } } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/config/BitcoindConfigTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/config/BitcoindConfigTest.scala index ec2a9a0f20..13b5eaa32b 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/config/BitcoindConfigTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/config/BitcoindConfigTest.scala @@ -17,10 +17,12 @@ class BitcoindConfigTest extends BitcoinSUnitTest { } it must "parse networks" in { - val conf = BitcoindConfig(""" + val conf = BitcoindConfig( + """ |regtest=1 """.stripMargin, - tmpDir) + tmpDir + ) assert(conf.network == RegTest) } diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v18/PsbtRpcTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v18/PsbtRpcTest.scala index e3aa21f414..6ea2cbf704 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v18/PsbtRpcTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v18/PsbtRpcTest.scala @@ -6,7 +6,8 @@ import org.bitcoins.rpc.client.common.BitcoindRpcClient import org.bitcoins.testkit.rpc.BitcoindFixturesFundedCachedNewest /** Tests for PSBT for RPC calls specific to V18 new PSBT calls - * @see https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors */ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest { @@ -14,7 +15,7 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest { it should "return something when analyzePsbt is called" in { client: BitcoindRpcClient => - //PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. + // PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. val psbt = "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=" @@ -26,7 +27,7 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest { } it should "analyze a PSBT and return a non-empty result" in { client: BitcoindRpcClient => - //PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. + // PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. val psbt = "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=" @@ -47,7 +48,7 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest { } it should "correctly analyze a psbt " in { client: BitcoindRpcClient => val psbt = - //PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. + // PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=" val analyzedF = client.analyzePsbt(PSBT.fromBase64(psbt)) val expectedfee = Bitcoins(0.00090341) @@ -70,12 +71,13 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest { } } - //Todo: figure out how to implement a test here + // Todo: figure out how to implement a test here it should "check to see if the utxoUpdate input has been updated" in { client: BitcoindRpcClient => val psbt = PSBT.fromBase64( - "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==") + "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==" + ) val updatedF = client.utxoUpdatePsbt(psbt) updatedF.map { result => @@ -83,16 +85,18 @@ class PsbtRpcTest extends BitcoindFixturesFundedCachedNewest { } } - /** Join psbt looks at the characteristics of a vector of PSBTs and converts them into a singular PSBT. - * This test takes test vectors from BIP 157 each missing some characteristic covered by the other. When joined - * together the resulting PSBT represented as a string is very different so we can't just search for parts of either - * PSBT. + /** Join psbt looks at the characteristics of a vector of PSBTs and converts + * them into a singular PSBT. This test takes test vectors from BIP 157 each + * missing some characteristic covered by the other. When joined together the + * resulting PSBT represented as a string is very different so we can't just + * search for parts of either PSBT. */ it should "joinpsbts" in { client: BitcoindRpcClient => val seqofpsbts = Vector( PSBT.fromBase64( - "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA"), - //PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA" + ), + // PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. PSBT.fromBase64( "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA=" ) diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v22/BitcoindV22RpcClientTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v22/BitcoindV22RpcClientTest.scala index 07eacfc5fe..32d0d30a9a 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v22/BitcoindV22RpcClientTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v22/BitcoindV22RpcClientTest.scala @@ -148,7 +148,8 @@ class BitcoindV22RpcClientTest extends BitcoindFixturesCachedPairV22 { resultVecF.map { resultVec => resultVec.foreach { result => assert( - result.network == "ipv4" || result.network == "ipv6" || result.network == "onion" || result.network == "i2p") + result.network == "ipv4" || result.network == "ipv6" || result.network == "onion" || result.network == "i2p" + ) } succeed } @@ -198,7 +199,8 @@ class BitcoindV22RpcClientTest extends BitcoindFixturesCachedPairV22 { client .addMultiSigAddress( 2, - Vector(Left(pubKey1), Right(address.asInstanceOf[P2PKHAddress]))) + Vector(Left(pubKey1), Right(address.asInstanceOf[P2PKHAddress])) + ) decoded <- client.decodeScript(multisig.redeemScript) _ <- client.loadWallet("") _ <- client.unloadWallet("decodeRWallet") @@ -222,22 +224,29 @@ class BitcoindV22RpcClientTest extends BitcoindFixturesCachedPairV22 { address <- otherClient.getNewAddress - input0 = TransactionOutPoint(transaction0.txid.flip, - UInt32(transaction0.blockindex.get)) - input1 = TransactionOutPoint(transaction1.txid.flip, - UInt32(transaction1.blockindex.get)) + input0 = TransactionOutPoint( + transaction0.txid.flip, + UInt32(transaction0.blockindex.get) + ) + input1 = TransactionOutPoint( + transaction1.txid.flip, + UInt32(transaction1.blockindex.get) + ) transactionFirst <- { val sig: ScriptSignature = ScriptSignature.empty - val inputs = Vector(TransactionInput(input0, sig, UInt32(1)), - TransactionInput(input1, sig, UInt32(2))) + val inputs = Vector( + TransactionInput(input0, sig, UInt32(1)), + TransactionInput(input1, sig, UInt32(2)) + ) val outputs = Map(address -> Bitcoins(1)) client.createRawTransaction(inputs, outputs) } fundedTransactionOne <- client.fundRawTransaction(transactionFirst) signedTransactionOne <- BitcoindRpcTestUtil.signRawTransaction( client, - fundedTransactionOne.hex) + fundedTransactionOne.hex + ) blocksTwo <- client.generate(2) firstBlockTwo <- client.getBlock(blocksTwo(0)) @@ -245,27 +254,35 @@ class BitcoindV22RpcClientTest extends BitcoindFixturesCachedPairV22 { secondBlockTwo <- client.getBlock(blocksTwo(1)) transaction3 <- client.getTransaction(secondBlockTwo.tx(0)) - input2 = TransactionOutPoint(transaction2.txid.flip, - UInt32(transaction2.blockindex.get)) - input3 = TransactionOutPoint(transaction3.txid.flip, - UInt32(transaction3.blockindex.get)) + input2 = TransactionOutPoint( + transaction2.txid.flip, + UInt32(transaction2.blockindex.get) + ) + input3 = TransactionOutPoint( + transaction3.txid.flip, + UInt32(transaction3.blockindex.get) + ) transactionSecond <- { val sig: ScriptSignature = ScriptSignature.empty - val inputs = Vector(TransactionInput(input2, sig, UInt32(1)), - TransactionInput(input3, sig, UInt32(2))) + val inputs = Vector( + TransactionInput(input2, sig, UInt32(1)), + TransactionInput(input3, sig, UInt32(2)) + ) val outputs = Map(address -> Bitcoins(1)) client.createRawTransaction(inputs, outputs) } fundedTransactionTwo <- client.fundRawTransaction(transactionSecond) signedTransactionTwo <- BitcoindRpcTestUtil.signRawTransaction( client, - fundedTransactionTwo.hex) + fundedTransactionTwo.hex + ) _ <- client.generate(100) // Can't spend until depth 100 mempoolAccept <- client.testMempoolAccept( - Vector(signedTransactionOne.hex, signedTransactionTwo.hex)) + Vector(signedTransactionOne.hex, signedTransactionTwo.hex) + ) } yield { val mempooltxid: Int = mempoolAccept.length assert(mempooltxid > 1) diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v23/BitcoindV23RpcClientTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v23/BitcoindV23RpcClientTest.scala index 69b053cb36..7a86667fda 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v23/BitcoindV23RpcClientTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v23/BitcoindV23RpcClientTest.scala @@ -81,7 +81,8 @@ class BitcoindV23RpcClientTest extends BitcoindFixturesFundedCachedV23 { it should "analyze a descriptor" in { client => val descriptor = Descriptor.fromString( - "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#gn28ywm7") + "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#gn28ywm7" + ) val descriptorF = client.getDescriptorInfo(descriptor) descriptorF.map { result => diff --git a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v24/BitcoindV24RpcClientTest.scala b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v24/BitcoindV24RpcClientTest.scala index 426b417120..f92f332173 100644 --- a/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v24/BitcoindV24RpcClientTest.scala +++ b/bitcoind-rpc-test/src/test/scala/org/bitcoins/rpc/v24/BitcoindV24RpcClientTest.scala @@ -42,7 +42,8 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { def indexSynced(client: BitcoindRpcClient): Future[Boolean] = { client.getIndexInfo.map { indexes => indexes("txindex").best_block_height == 101 && indexes( - "basic block filter index").best_block_height == 101 + "basic block filter index" + ).best_block_height == 101 } } for { @@ -112,7 +113,8 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { it should "analyze a descriptor" in { client => val descriptor = Descriptor.fromString( - "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#gn28ywm7") + "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)#gn28ywm7" + ) val descriptorF = client.getDescriptorInfo(descriptor) @@ -165,7 +167,8 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { client.deriveAddresses(descriptor0, None).map(_.addresses) val expected0 = Vector("bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5").map( - BitcoinAddress.fromString) + BitcoinAddress.fromString + ) val assert0 = addresses0F.map { addresses => assert(addresses == expected0) } @@ -178,9 +181,11 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { val addresses1F = client.deriveAddresses(descriptor1, Some(Vector(0, 2))).map(_.addresses) val expected1 = - Vector("bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5", - "bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", - "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq") + Vector( + "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5", + "bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", + "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq" + ) .map(BitcoinAddress.fromString) val assert1 = assert0.flatMap(_ => @@ -195,12 +200,14 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { val str1 = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)#kft60nuy" val descriptor = Descriptor.fromString(str1) - val imp = DescriptorsResult(desc = descriptor, - timestamp = Instant.now().getEpochSecond, - active = true, - internal = None, - range = Some(Vector(0, 2)), - next = None) + val imp = DescriptorsResult( + desc = descriptor, + timestamp = Instant.now().getEpochSecond, + active = true, + internal = None, + range = Some(Vector(0, 2)), + next = None + ) val resultF = client.importDescriptors(Vector(imp)) @@ -209,7 +216,7 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { _ = assert(result.forall(_.success)) firstAddress <- client.getNewAddress secondAddress <- client.getNewAddress - //check it by deriving addresses externally + // check it by deriving addresses externally deriveAddresses <- client .deriveAddresses(descriptor, Some(Vector(0, 1))) .map(_.addresses) @@ -243,7 +250,8 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { } prevFilter <- client.getBlockFilter( block.blockHeader.previousBlockHashBE, - FilterType.Basic) + FilterType.Basic + ) } yield { val pubKeys = fundingOutputs.map(_.scriptPubKey).toVector val filter = BlockFilter(block, pubKeys) @@ -251,7 +259,8 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { assert( blockFilter.header == filter .getHeader(prevFilter.header.flip) - .hashBE) + .hashBE + ) } } @@ -264,7 +273,8 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { val blockReward = 50 assert(immatureBalance.mine.immature.toBigDecimal >= 0) assert( - immatureBalance.mine.trusted.toBigDecimal + blockReward == newImmatureBalance.mine.trusted.toBigDecimal) + immatureBalance.mine.trusted.toBigDecimal + blockReward == newImmatureBalance.mine.trusted.toBigDecimal + ) } } @@ -313,7 +323,8 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { val psbt = PSBT.fromBase64( - "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==") + "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAA==" + ) for { result <- client.utxoUpdatePsbt(psbt, Seq(descriptor)) @@ -328,15 +339,19 @@ class BitcoindV24RpcClientTest extends BitcoindFixturesFundedCachedV24 { val pubKey2 = ECPublicKey.freshPublicKey for { - multiSigResult <- client.createMultiSig(2, - Vector(pubKey1, pubKey2), - AddressType.Bech32) + multiSigResult <- client.createMultiSig( + 2, + Vector(pubKey1, pubKey2), + AddressType.Bech32 + ) } yield { // just validate we are able to receive a sane descriptor // no need to check checksum assert( multiSigResult.descriptor.startsWith( - s"wsh(multi(2,${pubKey1.hex},${pubKey2.hex}))#")) + s"wsh(multi(2,${pubKey1.hex},${pubKey2.hex}))#" + ) + ) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/BitcoindException.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/BitcoindException.scala index bd17de4fcd..2ab03ce565 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/BitcoindException.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/BitcoindException.scala @@ -5,11 +5,11 @@ import play.api.libs.json.{JsResult, JsValue} import play.api.libs.json.JsError import play.api.libs.json.JsSuccess -/** Represents failures that can happen when using the - * `bitcoind` RPC interface. +/** Represents failures that can happen when using the `bitcoind` RPC interface. * - * @see [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/rpc/protocol.h#L32 protcol.h]] - * for an enumeration of all error codes used + * @see + * [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/rpc/protocol.h#L32 protcol.h]] + * for an enumeration of all error codes used */ sealed abstract class BitcoindException(private val message: String) extends Exception { @@ -19,8 +19,9 @@ sealed abstract class BitcoindException(private val message: String) /** Wallet errors from `bitcoind` RPC calls * - * @see [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/rpc/protocol.h#L32 protcol.h]] - * for an enumeration of all error codes used + * @see + * [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/rpc/protocol.h#L32 protcol.h]] + * for an enumeration of all error codes used */ object BitcoindException { @@ -36,7 +37,8 @@ object BitcoindException { exception <- BitcoindException.fromCodeAndMessage(code, message) match { case None => JsError( - s"Could not construct bitcoind exception with code $code and message '$message'") + s"Could not construct bitcoind exception with code $code and message '$message'" + ) case Some(value) => JsSuccess(value) } } yield exception @@ -78,10 +80,12 @@ object BitcoindException { NotSpecified(_) ) - /** Attempts to construct a BitcoindException from the given code and message */ + /** Attempts to construct a BitcoindException from the given code and message + */ def fromCodeAndMessage( code: Int, - message: String): Option[BitcoindException] = { + message: String + ): Option[BitcoindException] = { val constructorOpt = all.find(func => func(message).code == code) @@ -93,8 +97,8 @@ object BitcoindException { val code: Int = -32602 } - /** InternalError is only used for genuine errors in bitcoind - * (for example datadir corruption) + /** InternalError is only used for genuine errors in bitcoind (for example + * datadir corruption) */ final case class InternalError(private val message: String) extends BitcoindException(message) { @@ -159,7 +163,8 @@ object BitcoindException { extends BitcoindException( if (message == "non-final") "Transaction is not final. Try again in a bit." - else message) { + else message + ) { val code: Int = -26 } @@ -188,10 +193,11 @@ object BitcoindException { } } -/** P2P client errors +/** P2P client errors * - * @see [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/rpc/protocol.h#L32 protcol.h]] - * for an enumeration of all error codes used + * @see + * [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/rpc/protocol.h#L32 protcol.h]] + * for an enumeration of all error codes used */ sealed abstract class BitcoindP2PException(private val message: String) extends BitcoindException(message) @@ -282,7 +288,9 @@ object BitcoindWalletException { val code: Int = -14 } - /** Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.) */ + /** Command given in wrong wallet encryption state (encrypting an encrypted + * wallet etc.) + */ final case class WrongEncState(private val message: String) extends BitcoindWalletException(message) { val code: Int = -15 diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala index 00195edaa9..4c367e9001 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala @@ -25,19 +25,18 @@ import java.io.File import java.util.concurrent.atomic.AtomicBoolean import scala.concurrent.Future -/** This class is not guaranteed to be compatible with any particular - * version of Bitcoin Core. It implements RPC calls that are similar - * across different versions. If you need RPC calls specific to a - * version, check out +/** This class is not guaranteed to be compatible with any particular version of + * Bitcoin Core. It implements RPC calls that are similar across different + * versions. If you need RPC calls specific to a version, check out * * If a RPC call fails for any reason, a - * [[org.bitcoins.rpc.BitcoindException BitcoindException]] is thrown. - * This is a sealed abstract class, so you can pattern match easily - * on the errors, and handle them as you see fit. + * [[org.bitcoins.rpc.BitcoindException BitcoindException]] is thrown. This is + * a sealed abstract class, so you can pattern match easily on the errors, and + * handle them as you see fit. */ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit - override val system: ActorSystem) - extends Client + override val system: ActorSystem +) extends Client with FeeRateApi with NodeApi with ChainApi @@ -78,21 +77,26 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit result.feerate match { case Some(feeRate) => Future.successful(feeRate) case None => - Future.failed(new RuntimeException( - s"Unexpected error when getting fee rate, errors=${result.errors}")) + Future.failed( + new RuntimeException( + s"Unexpected error when getting fee rate, errors=${result.errors}" + ) + ) } } // Chain Api /** Gets the height of the given block */ override def getBlockHeight( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = { + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = { getBlockHeader(blockHash).map(header => Some(header.height)) } /** Gets number of confirmations for the given block hash */ override def getNumberOfConfirmations( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = { + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = { getBlockHeader(blockHash).map(header => Some(header.confirmations)) } @@ -105,13 +109,16 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit getBlockHeader(blockHash.hash).map(_.height) case blockTime: BlockStamp.BlockTime => Future.failed( - new UnsupportedOperationException(s"Not implemented: $blockTime")) + new UnsupportedOperationException(s"Not implemented: $blockTime") + ) } /** Gets the block height of the closest block to the given time */ override def epochSecondToBlockHeight(time: Long): Future[Int] = { - require(time >= 1231006505L, - s"Time must be after the genesis block (1231006505), got $time") + require( + time >= 1231006505L, + s"Time must be after the genesis block (1231006505), got $time" + ) // the longest difference between successive blocks ever recorded + 10 minutes val MaxDiff = 463160L + 600L @@ -154,27 +161,32 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit // Node Api override def broadcastTransactions( - transactions: Vector[Transaction]): Future[Unit] = + transactions: Vector[Transaction] + ): Future[Unit] = FutureUtil.sequentially(transactions)(sendRawTransaction(_)).map(_ => ()) override def downloadBlocks( - blockHashes: Vector[DoubleSha256DigestBE]): Future[Unit] = Future.unit + blockHashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] = Future.unit override def processHeaders(headers: Vector[BlockHeader]): Future[ChainApi] = Future.successful(this) override def processFilterHeaders( filterHeaders: Vector[FilterHeader], - stopHash: DoubleSha256DigestBE): Future[ChainApi] = + stopHash: DoubleSha256DigestBE + ): Future[ChainApi] = Future.successful(this) override def getHeader( - hash: DoubleSha256DigestBE): Future[Option[BlockHeaderDb]] = + hash: DoubleSha256DigestBE + ): Future[Option[BlockHeaderDb]] = getBlockHeader(hash).map(header => Some(header.blockHeaderDb)) - override def getHeaders(hashes: Vector[DoubleSha256DigestBE]): Future[ - Vector[Option[BlockHeaderDb]]] = { - //sends a request for every header, i'm not aware of a way to batch these + override def getHeaders( + hashes: Vector[DoubleSha256DigestBE] + ): Future[Vector[Option[BlockHeaderDb]]] = { + // sends a request for every header, i'm not aware of a way to batch these val resultsNested: Vector[Future[Option[BlockHeaderDb]]] = hashes.map(getHeader) Future @@ -183,7 +195,8 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit override def getHeadersBetween( from: BlockHeaderDb, - to: BlockHeaderDb): Future[Vector[BlockHeaderDb]] = { + to: BlockHeaderDb + ): Future[Vector[BlockHeaderDb]] = { val headerFs = from.height.to(to.height).map(height => getHeaderAtHeight(height)) Future.sequence(headerFs).map(_.toVector) @@ -214,26 +227,34 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit override def nextBlockHeaderBatchRange( prevStopHash: DoubleSha256DigestBE, stopHash: DoubleSha256DigestBE, - batchSize: Int): Future[Option[FilterSyncMarker]] = + batchSize: Int + ): Future[Option[FilterSyncMarker]] = Future.failed( new UnsupportedOperationException( - s"Bitcoind chainApi doesn't allow you fetch block header batch range")) + s"Bitcoind chainApi doesn't allow you fetch block header batch range" + ) + ) override def nextFilterHeaderBatchRange( stopBlockHash: DoubleSha256DigestBE, batchSize: Int, - startHeightOpt: Option[Int]): Future[Option[FilterSyncMarker]] = + startHeightOpt: Option[Int] + ): Future[Option[FilterSyncMarker]] = Future.failed( new UnsupportedOperationException( - s"Bitcoind chainApi doesn't allow you fetch filter header batch range")) + s"Bitcoind chainApi doesn't allow you fetch filter header batch range" + ) + ) override def processFilters( - message: Vector[CompactFilterMessage]): Future[ChainApi] = + message: Vector[CompactFilterMessage] + ): Future[ChainApi] = Future.successful(this) override def processCheckpoints( checkpoints: Vector[DoubleSha256DigestBE], - blockHash: DoubleSha256DigestBE): Future[ChainApi] = + blockHash: DoubleSha256DigestBE + ): Future[ChainApi] = Future.successful(this) def generate(numBlocks: Int): Future[Vector[DoubleSha256DigestBE]] = { @@ -251,8 +272,10 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit override def isTipStale(): Future[Boolean] = { getBestBlockHeader().map { blockHeaderDb => - NetworkUtil.isBlockHeaderStale(blockHeaderDb.blockHeader, - network.chainParams) + NetworkUtil.isBlockHeaderStale( + blockHeaderDb.blockHeader, + network.chainParams + ) } } @@ -273,8 +296,8 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit object BitcoindRpcClient { - /** The name we give to actor systems we create. We use this - * information to know which actor systems to shut down + /** The name we give to actor systems we create. We use this information to + * know which actor systems to shut down */ private[rpc] val ActorSystemName = "bitcoind-rpc-client-created-by-bitcoin-s" @@ -283,46 +306,50 @@ object BitcoindRpcClient { /** Creates an RPC client from the given instance. * - * Behind the scenes, we create an actor system for - * you. You can use `withActorSystem` if you want to - * manually specify an actor system for the RPC client. + * Behind the scenes, we create an actor system for you. You can use + * `withActorSystem` if you want to manually specify an actor system for the + * RPC client. */ def apply(instance: BitcoindInstance): BitcoindRpcClient = { withActorSystem(instance)(system) } - /** Creates an RPC client from the given instance, - * together with the given actor system. This is for - * advanced users, where you need fine grained control - * over the RPC client. + /** Creates an RPC client from the given instance, together with the given + * actor system. This is for advanced users, where you need fine grained + * control over the RPC client. */ def withActorSystem(instance: BitcoindInstance)(implicit - system: ActorSystem): BitcoindRpcClient = + system: ActorSystem + ): BitcoindRpcClient = new BitcoindRpcClient(instance) - /** Constructs a RPC client from the given datadir, or - * the default datadir if no directory is provided. - * This is always a [[BitcoindInstanceLocal]] since a binary - * is passed into this method + /** Constructs a RPC client from the given datadir, or the default datadir if + * no directory is provided. This is always a [[BitcoindInstanceLocal]] since + * a binary is passed into this method */ def fromDatadir( datadir: File = BitcoindConfig.DEFAULT_DATADIR, - binary: File): BitcoindRpcClient = { + binary: File + ): BitcoindRpcClient = { val instance = BitcoindInstanceLocal.fromDatadir(datadir, binary) val cli = BitcoindRpcClient(instance) cli } - /** Returns a bitcoind with the appropriated version you passed in, the bitcoind is NOT started. */ + /** Returns a bitcoind with the appropriated version you passed in, the + * bitcoind is NOT started. + */ def fromVersion(version: BitcoindVersion, instance: BitcoindInstance)(implicit - system: ActorSystem): BitcoindRpcClient = { + system: ActorSystem + ): BitcoindRpcClient = { val bitcoind = version match { case BitcoindVersion.V22 => BitcoindV22RpcClient.withActorSystem(instance) case BitcoindVersion.V23 => BitcoindV23RpcClient.withActorSystem(instance) case BitcoindVersion.V24 => BitcoindV24RpcClient.withActorSystem(instance) case BitcoindVersion.Unknown => sys.error( - s"Cannot create a Bitcoin Core RPC client: unsupported version") + s"Cannot create a Bitcoin Core RPC client: unsupported version" + ) } bitcoind @@ -330,7 +357,8 @@ object BitcoindRpcClient { def fromVersionNoSystem( version: BitcoindVersion, - instance: BitcoindInstance): BitcoindRpcClient = { + instance: BitcoindInstance + ): BitcoindRpcClient = { fromVersion(version, instance)(system) } } @@ -373,18 +401,19 @@ object BitcoindVersion fromStringOpt(string).get } - /** Gets the bitcoind version from the 'getnetworkresult' bitcoind rpc - * An example for 210100 for the 21.1.0 release of bitcoin core + /** Gets the bitcoind version from the 'getnetworkresult' bitcoind rpc An + * example for 210100 for the 21.1.0 release of bitcoin core */ def fromNetworkVersion(int: Int): BitcoindVersion = { - //need to translate the int 210100 (as an example) to a BitcoindVersion + // need to translate the int 210100 (as an example) to a BitcoindVersion int.toString.substring(0, 2) match { case "22" => V22 case "23" => V23 case "24" => V24 case _ => logger.warn( - s"Unsupported Bitcoin Core version: $int. The latest supported version is ${BitcoindVersion.newest}") + s"Unsupported Bitcoin Core version: $int. The latest supported version is ${BitcoindVersion.newest}" + ) newest } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BlockchainRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BlockchainRpc.scala index 9cc43b5cf0..b70817e522 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BlockchainRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BlockchainRpc.scala @@ -28,8 +28,10 @@ trait BlockchainRpc extends ChainApi { self: Client => def getBlock(headerHash: DoubleSha256DigestBE): Future[GetBlockResult] = { val isJsonObject = JsNumber(1) - bitcoindCall[GetBlockResult]("getblock", - List(JsString(headerHash.hex), isJsonObject)) + bitcoindCall[GetBlockResult]( + "getblock", + List(JsString(headerHash.hex), isJsonObject) + ) } def getBlock(headerHash: DoubleSha256Digest): Future[GetBlockResult] = { @@ -54,21 +56,27 @@ trait BlockchainRpc extends ChainApi { self: Client => } def getBlockHeader( - headerHash: DoubleSha256DigestBE): Future[GetBlockHeaderResult] = { + headerHash: DoubleSha256DigestBE + ): Future[GetBlockHeaderResult] = { bitcoindCall[GetBlockHeaderResult]( "getblockheader", - List(JsString(headerHash.hex), JsBoolean(true))) + List(JsString(headerHash.hex), JsBoolean(true)) + ) } def getBlockHeader( - headerHash: DoubleSha256Digest): Future[GetBlockHeaderResult] = { + headerHash: DoubleSha256Digest + ): Future[GetBlockHeaderResult] = { getBlockHeader(headerHash.flip) } def getBlockHeaderRaw( - headerHash: DoubleSha256DigestBE): Future[BlockHeader] = { - bitcoindCall[BlockHeader]("getblockheader", - List(JsString(headerHash.hex), JsBoolean(false))) + headerHash: DoubleSha256DigestBE + ): Future[BlockHeader] = { + bitcoindCall[BlockHeader]( + "getblockheader", + List(JsString(headerHash.hex), JsBoolean(false)) + ) } def getBlockHeaderRaw(headerHash: DoubleSha256Digest): Future[BlockHeader] = { @@ -83,19 +91,22 @@ trait BlockchainRpc extends ChainApi { self: Client => getBlockRaw(headerHash.flip) } - def getBlockWithTransactions(headerHash: DoubleSha256DigestBE): Future[ - GetBlockWithTransactionsResultV22] = { + def getBlockWithTransactions( + headerHash: DoubleSha256DigestBE + ): Future[GetBlockWithTransactionsResultV22] = { val isVerboseJsonObject = JsNumber(2) self.version.flatMap { case V22 | V23 | V24 | Unknown => bitcoindCall[GetBlockWithTransactionsResultV22]( "getblock", - List(JsString(headerHash.hex), isVerboseJsonObject)) + List(JsString(headerHash.hex), isVerboseJsonObject) + ) } } - def getBlockWithTransactions(headerHash: DoubleSha256Digest): Future[ - GetBlockWithTransactionsResult] = { + def getBlockWithTransactions( + headerHash: DoubleSha256Digest + ): Future[GetBlockWithTransactionsResult] = { getBlockWithTransactions(headerHash.flip) } @@ -108,8 +119,8 @@ trait BlockchainRpc extends ChainApi { self: Client => private def getChainTxStats( blocks: Option[Int], - blockHash: Option[DoubleSha256DigestBE]): Future[ - GetChainTxStatsResult] = { + blockHash: Option[DoubleSha256DigestBE] + ): Future[GetChainTxStatsResult] = { val params = if (blocks.isEmpty) { List.empty @@ -126,12 +137,14 @@ trait BlockchainRpc extends ChainApi { self: Client => def getChainTxStats( blocks: Int, - blockHash: DoubleSha256DigestBE): Future[GetChainTxStatsResult] = + blockHash: DoubleSha256DigestBE + ): Future[GetChainTxStatsResult] = getChainTxStats(Some(blocks), Some(blockHash)) def getChainTxStats( blocks: Int, - blockHash: DoubleSha256Digest): Future[GetChainTxStatsResult] = + blockHash: DoubleSha256Digest + ): Future[GetChainTxStatsResult] = getChainTxStats(Some(blocks), Some(blockHash.flip)) def getDifficulty: Future[BigDecimal] = { @@ -151,70 +164,84 @@ trait BlockchainRpc extends ChainApi { self: Client => def listSinceBlock( headerHash: Option[DoubleSha256DigestBE] = None, confirmations: Int = 1, - includeWatchOnly: Boolean = false): Future[ListSinceBlockResult] = { + includeWatchOnly: Boolean = false + ): Future[ListSinceBlockResult] = { val params = if (headerHash.isEmpty) { List.empty } else { - List(JsString(headerHash.get.hex), - JsNumber(confirmations), - JsBoolean(includeWatchOnly)) + List( + JsString(headerHash.get.hex), + JsNumber(confirmations), + JsBoolean(includeWatchOnly) + ) } bitcoindCall[ListSinceBlockResult]("listsinceblock", params) } def listSinceBlock( - headerHash: DoubleSha256DigestBE): Future[ListSinceBlockResult] = + headerHash: DoubleSha256DigestBE + ): Future[ListSinceBlockResult] = listSinceBlock(Some(headerHash)) def listSinceBlock( headerHash: DoubleSha256DigestBE, - confirmations: Int): Future[ListSinceBlockResult] = + confirmations: Int + ): Future[ListSinceBlockResult] = listSinceBlock(Some(headerHash), confirmations) def listSinceBlock( headerHash: DoubleSha256DigestBE, - includeWatchOnly: Boolean): Future[ListSinceBlockResult] = + includeWatchOnly: Boolean + ): Future[ListSinceBlockResult] = listSinceBlock(Some(headerHash), includeWatchOnly = includeWatchOnly) def listSinceBlock( headerHash: DoubleSha256DigestBE, confirmations: Int, - includeWatchOnly: Boolean): Future[ListSinceBlockResult] = + includeWatchOnly: Boolean + ): Future[ListSinceBlockResult] = listSinceBlock(Some(headerHash), confirmations, includeWatchOnly) def listSinceBlock( - headerHash: DoubleSha256Digest): Future[ListSinceBlockResult] = + headerHash: DoubleSha256Digest + ): Future[ListSinceBlockResult] = listSinceBlock(Some(headerHash.flip)) def listSinceBlock( headerHash: DoubleSha256Digest, - confirmations: Int): Future[ListSinceBlockResult] = + confirmations: Int + ): Future[ListSinceBlockResult] = listSinceBlock(Some(headerHash.flip), confirmations) def listSinceBlock( headerHash: DoubleSha256Digest, - includeWatchOnly: Boolean): Future[ListSinceBlockResult] = + includeWatchOnly: Boolean + ): Future[ListSinceBlockResult] = listSinceBlock(Some(headerHash.flip), includeWatchOnly = includeWatchOnly) def listSinceBlock( headerHash: DoubleSha256Digest, confirmations: Int, - includeWatchOnly: Boolean): Future[ListSinceBlockResult] = + includeWatchOnly: Boolean + ): Future[ListSinceBlockResult] = listSinceBlock(Some(headerHash.flip), confirmations, includeWatchOnly) def listTransactions( account: String = "*", count: Int = 10, skip: Int = 0, - includeWatchOnly: Boolean = false): Future[ - Vector[ListTransactionsResult]] = { + includeWatchOnly: Boolean = false + ): Future[Vector[ListTransactionsResult]] = { bitcoindCall[Vector[ListTransactionsResult]]( "listtransactions", - List(JsString(account), - JsNumber(count), - JsNumber(skip), - JsBoolean(includeWatchOnly))) + List( + JsString(account), + JsNumber(count), + JsNumber(skip), + JsBoolean(includeWatchOnly) + ) + ) } def pruneBlockChain(height: Int): Future[Int] = { @@ -226,7 +253,8 @@ trait BlockchainRpc extends ChainApi { self: Client => private def rescanBlockChain( start: Option[Int], - stop: Option[Int]): Future[RescanBlockChainResult] = { + stop: Option[Int] + ): Future[RescanBlockChainResult] = { val params = if (start.isEmpty) { List.empty @@ -253,46 +281,55 @@ trait BlockchainRpc extends ChainApi { self: Client => } def verifyChain(level: Int = 3, blocks: Int = 6): Future[Boolean] = { - bitcoindCall[Boolean]("verifychain", - List(JsNumber(level), JsNumber(blocks))) + bitcoindCall[Boolean]( + "verifychain", + List(JsNumber(level), JsNumber(blocks)) + ) } - /** Waits for the validation interface queue to catch up on everything that was there when we entered this function - * @see [[https://github.com/bitcoin/bitcoin/issues/27085]] + /** Waits for the validation interface queue to catch up on everything that + * was there when we entered this function + * @see + * [[https://github.com/bitcoin/bitcoin/issues/27085]] * @return */ def syncWithValidationInterfaceQueue(): Future[Unit] = { bitcoindCall[Unit](command = "syncwithvalidationinterfacequeue", List.empty) } - /** This is needed because we need the block hash to create a GolombFilter. - * We use an intermediary data type to hold our data so we can add the block hash - * we were given after the RPC call + /** This is needed because we need the block hash to create a GolombFilter. We + * use an intermediary data type to hold our data so we can add the block + * hash we were given after the RPC call */ private case class TempBlockFilterResult( filter: String, - header: DoubleSha256DigestBE) + header: DoubleSha256DigestBE + ) - implicit - private val tempBlockFilterResultReads: Reads[TempBlockFilterResult] = + implicit private val tempBlockFilterResultReads + : Reads[TempBlockFilterResult] = Json.reads[TempBlockFilterResult] def getBlockFilter( blockhash: DoubleSha256DigestBE, - filtertype: FilterType): Future[GetBlockFilterResult] = { + filtertype: FilterType + ): Future[GetBlockFilterResult] = { bitcoindCall[TempBlockFilterResult]( "getblockfilter", - List(JsString(blockhash.hex), JsString(filtertype.toString.toLowerCase))) + List(JsString(blockhash.hex), JsString(filtertype.toString.toLowerCase)) + ) .map { tempBlockFilterResult => GetBlockFilterResult( BlockFilter.fromHex(tempBlockFilterResult.filter, blockhash.flip), - tempBlockFilterResult.header) + tempBlockFilterResult.header + ) } } override def getFiltersBetweenHeights( startHeight: Int, - endHeight: Int): Future[Vector[ChainQueryApi.FilterResponse]] = { + endHeight: Int + ): Future[Vector[ChainQueryApi.FilterResponse]] = { val allHeights = startHeight.to(endHeight) def f(range: Vector[Int]): Future[Vector[FilterResponse]] = { @@ -307,9 +344,11 @@ trait BlockchainRpc extends ChainApi { self: Client => Future.sequence(filterFs) } - FutureUtil.batchAndSyncExecute(elements = allHeights.toVector, - f = f, - batchSize = FutureUtil.getParallelism) + FutureUtil.batchAndSyncExecute( + elements = allHeights.toVector, + f = f, + batchSize = FutureUtil.getParallelism + ) } override def getFilterCount(): Future[Int] = getBlockCount() @@ -324,8 +363,9 @@ trait BlockchainRpc extends ChainApi { self: Client => } yield fhOpt } - override def getFilterHeader(blockHash: DoubleSha256DigestBE): Future[ - Option[CompactFilterHeaderDb]] = { + override def getFilterHeader( + blockHash: DoubleSha256DigestBE + ): Future[Option[CompactFilterHeaderDb]] = { for { blockHeaderOpt <- getHeader(blockHash) (filterOpt, prevFilterOpt) <- blockHeaderOpt match { @@ -342,18 +382,20 @@ trait BlockchainRpc extends ChainApi { self: Client => val c = CompactFilterHeaderDbHelper.fromFilterHeader( filterHeader = fh, blockHash = blockHash, - height = filter.height) + height = filter.height + ) Some(c) case (Some(filter), None) => - //must be genesis filter + // must be genesis filter val fh = FilterHeader(filter.hashBE, DoubleSha256DigestBE.empty) val c = CompactFilterHeaderDbHelper.fromFilterHeader( filterHeader = fh, blockHash = blockHash, - height = filter.height) + height = filter.height + ) Some(c) case (None, Some(_)) => - //could find previous filter, but couldn't find compact filter? + // could find previous filter, but couldn't find compact filter? None case (None, None) => None } @@ -361,7 +403,8 @@ trait BlockchainRpc extends ChainApi { self: Client => } override def getFilterHeadersAtHeight( - height: Int): Future[Vector[CompactFilterHeaderDb]] = { + height: Int + ): Future[Vector[CompactFilterHeaderDb]] = { getBlockHash(height) .flatMap { blockHashBE => getFilterHeader(blockHashBE) @@ -370,7 +413,8 @@ trait BlockchainRpc extends ChainApi { self: Client => } override def getFilter( - hash: DoubleSha256DigestBE): Future[Option[CompactFilterDb]] = { + hash: DoubleSha256DigestBE + ): Future[Option[CompactFilterDb]] = { for { header <- getBlockHeader(hash) filter <- getBlockFilter(hash, FilterType.Basic) @@ -378,7 +422,8 @@ trait BlockchainRpc extends ChainApi { self: Client => } override def getFiltersAtHeight( - height: Int): Future[Vector[CompactFilterDb]] = { + height: Int + ): Future[Vector[CompactFilterDb]] = { for { hash <- getBlockHash(height) filter <- getBlockFilter(hash, FilterType.Basic) diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala index d3f322c8fa..242b219ff9 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala @@ -44,12 +44,10 @@ import scala.concurrent.duration.DurationInt import scala.util.control.NonFatal import scala.util.{Failure, Success} -/** This is the base trait for Bitcoin Core - * RPC clients. It defines no RPC calls - * except for the a ping. It contains functionality - * and utilities useful when working with an RPC - * client, like data directories, log files - * and whether or not the client is started. +/** This is the base trait for Bitcoin Core RPC clients. It defines no RPC calls + * except for the a ping. It contains functionality and utilities useful when + * working with an RPC client, like data directories, log files and whether or + * not the client is started. */ trait Client extends BitcoinSLogger @@ -61,10 +59,9 @@ trait Client protected def walletExtension(walletName: String): String = s"/wallet/$walletName" - /** The log file of the Bitcoin Core daemon. - * This returns the log file if the underlying instance is - * [[org.bitcoins.rpc.config.BitcoindInstanceLocal]], and - * None if the underlying instance is [[BitcoindInstanceRemote]] + /** The log file of the Bitcoin Core daemon. This returns the log file if the + * underlying instance is [[org.bitcoins.rpc.config.BitcoindInstanceLocal]], + * and None if the underlying instance is [[BitcoindInstanceRemote]] */ lazy val logFileOpt: Option[Path] = { instance match { @@ -81,10 +78,9 @@ trait Client } } - /** The configuration file of the Bitcoin Core daemon - * This returns the conf file is the underlying instance is - * [[BitcoindInstanceLocal]] and None if the underlying - * instance is [[BitcoindInstanceRemote]] + /** The configuration file of the Bitcoin Core daemon This returns the conf + * file is the underlying instance is [[BitcoindInstanceLocal]] and None if + * the underlying instance is [[BitcoindInstanceRemote]] */ lazy val confFileOpt: Option[Path] = { instance match { @@ -102,8 +98,8 @@ trait Client system.getDispatcher implicit protected val network: NetworkParameters = instance.network - /** This is here (and not in JsonWrriters) - * so that the implicit network val is accessible + /** This is here (and not in JsonWrriters) so that the implicit network val is + * accessible */ implicit object ECPrivateKeyWrites extends Writes[ECPrivateKey] { @@ -113,8 +109,8 @@ trait Client implicit val eCPrivateKeyWrites: Writes[ECPrivateKey] = ECPrivateKeyWrites - /** This is here (and not in JsonWrriters) - * so that the implicit network val is accessible + /** This is here (and not in JsonWrriters) so that the implicit network val is + * accessible */ implicit object ECPrivateKeyBytesWrites extends Writes[ECPrivateKeyBytes] { @@ -139,16 +135,20 @@ trait Client instance match { case _: BitcoindInstanceRemote => logger.warn( - s"Cannot start remote instance with local binary command. You've likely misconfigured something") + s"Cannot start remote instance with local binary command. You've likely misconfigured something" + ) "" case local: BitcoindInstanceLocal => val binaryPath = local.binary.getAbsolutePath - val cmd = List(binaryPath, - "-datadir=" + local.datadir, - "-rpcport=" + instance.rpcUri.getPort, - "-port=" + instance.uri.getPort) + val cmd = List( + binaryPath, + "-datadir=" + local.datadir, + "-rpcport=" + instance.rpcUri.getPort, + "-port=" + instance.uri.getPort + ) logger.debug( - s"starting bitcoind with datadir ${local.datadir} and binary path $binaryPath") + s"starting bitcoind with datadir ${local.datadir} and binary path $binaryPath" + ) cmd.mkString(" ") @@ -156,9 +156,9 @@ trait Client } /** Starts bitcoind on the local system. - * @return a future that completes when bitcoind is fully started. - * This future times out after 60 seconds if the client - * cannot be started + * @return + * a future that completes when bitcoind is fully started. This future + * times out after 60 seconds if the client cannot be started */ override def start(): Future[BitcoindRpcClient] = { logger.info(s"Client.start() instance=$instance") @@ -185,14 +185,16 @@ trait Client instance match { case _: BitcoindInstanceRemote => sys.error( - s"Cannot start a remote instance, it needs to be started on the remote host machine") + s"Cannot start a remote instance, it needs to be started on the remote host machine" + ) case local: BitcoindInstanceLocal => val versionCheckF = version.map { v => if (v != BitcoindVersion.Unknown) { val foundVersion = local.getVersion if (foundVersion != v) { throw new RuntimeException( - s"Wrong version for bitcoind RPC client! Expected $version, got $foundVersion") + s"Wrong version for bitcoind RPC client! Expected $version, got $foundVersion" + ) } } } @@ -203,9 +205,11 @@ trait Client _ <- startedF _ <- awaitCookie(instance.authCredentials) _ = isStartedFlag.set(true) - _ <- AsyncUtil.retryUntilSatisfiedF(() => isStartedF, - interval = 1.seconds, - maxTries = 120) + _ <- AsyncUtil.retryUntilSatisfiedF( + () => isStartedF, + interval = 1.seconds, + maxTries = 120 + ) } yield this.asInstanceOf[BitcoindRpcClient] } case true => @@ -219,7 +223,8 @@ trait Client case Success(_) => logger.debug(s"started bitcoind") case Failure(exc) => logger.info( - s"Could not start bitcoind instance! Message: ${exc.getMessage}") + s"Could not start bitcoind instance! Message: ${exc.getMessage}" + ) // When we're unable to start bitcoind that's most likely // either a configuration error or bug in Bitcoin-S. In either // case it's much easier to debug this with conf and logs @@ -271,7 +276,7 @@ trait Client if exc.getMessage.contains("Connection refused") => false case _: JsonParseException => - //see https://github.com/bitcoin-s/bitcoin-s/issues/527 + // see https://github.com/bitcoin-s/bitcoin-s/issues/527 false } } @@ -289,12 +294,12 @@ trait Client case (CookieBased(_, _) | PasswordBased(_, _)) => instance match { case _: BitcoindInstanceRemote => - //we cannot check locally if it has been started - //so best we can do is try to ping + // we cannot check locally if it has been started + // so best we can do is try to ping tryPing() case _: BitcoindInstanceLocal => - //check if the binary has been started - //and then tryPing() if it has + // check if the binary has been started + // and then tryPing() if it has if (isStartedFlag.get) { tryPing() } else { @@ -305,16 +310,18 @@ trait Client } } - /** Stop method for BitcoindRpcClient that is stopped, inherits from the StartStop trait - * @return A future stopped bitcoindRPC client + /** Stop method for BitcoindRpcClient that is stopped, inherits from the + * StartStop trait + * @return + * A future stopped bitcoindRPC client */ def stop(): Future[BitcoindRpcClient] = { for { _ <- bitcoindCall[String]("stop") _ = isStartedFlag.set(false) - //do we want to call this right away? - //i think bitcoind stops asynchronously - //so it returns fast from the 'stop' rpc command + // do we want to call this right away? + // i think bitcoind stops asynchronously + // so it returns fast from the 'stop' rpc command _ <- stopBinary() _ <- { if (system.name == BitcoindRpcClient.ActorSystemName) { @@ -325,7 +332,8 @@ trait Client } /** Checks whether the underlyind bitcoind daemon is stopped - * @return A future boolean which represents isstopped or not + * @return + * A future boolean which represents isstopped or not */ def isStoppedF: Future[Boolean] = { isStartedF.map(started => !started) @@ -353,16 +361,18 @@ trait Client /** These lines are handy if you want to inspect what's being sent to and * returned from bitcoind before it's parsed into a Scala type. However, * there will sensitive material in some of those calls (private keys, - * XPUBs, balances, etc). It's therefore not a good idea to enable - * this logging in production. + * XPUBs, balances, etc). It's therefore not a good idea to enable this + * logging in production. */ // logger.info( // s"Command: $command ${parameters.map(_.toString).mkString(" ")}") // logger.info(s"Payload: \n${Json.prettyPrint(payload)}") - parseResult(result = (payload \ resultKey).validate[T], - json = payload, - printError = printError, - command = command) + parseResult( + result = (payload \ resultKey).validate[T], + json = payload, + printError = printError, + command = command + ) } } @@ -370,11 +380,14 @@ trait Client instance: BitcoindInstance, methodName: String, params: JsArray, - uriExtensionOpt: Option[String] = None): HttpRequest = { + uriExtensionOpt: Option[String] = None + ): HttpRequest = { val uuid = UUID.randomUUID().toString - val m: Map[String, JsValue] = Map("method" -> JsString(methodName), - "params" -> params, - "id" -> JsString(uuid)) + val m: Map[String, JsValue] = Map( + "method" -> JsString(methodName), + "params" -> params, + "id" -> JsString(uuid) + ) val jsObject = JsObject(m) @@ -388,9 +401,11 @@ trait Client HttpRequest( method = HttpMethods.POST, uri, - entity = HttpEntity(ContentTypes.`application/json`, jsObject.toString())) + entity = HttpEntity(ContentTypes.`application/json`, jsObject.toString()) + ) .addCredentials( - HttpCredentials.createBasicHttpCredentials(username, password)) + HttpCredentials.createBasicHttpCredentials(username, password) + ) } /** Cached http client to send requests to bitcoind with */ @@ -399,11 +414,15 @@ trait Client private lazy val httpConnectionPoolSettings: ConnectionPoolSettings = { instance match { case remote: BitcoindInstanceRemote => - Socks5ClientTransport.createConnectionPoolSettings(instance.rpcUri, - remote.proxyParams) + Socks5ClientTransport.createConnectionPoolSettings( + instance.rpcUri, + remote.proxyParams + ) case _: BitcoindInstanceLocal => - Socks5ClientTransport.createConnectionPoolSettings(instance.rpcUri, - None) + Socks5ClientTransport.createConnectionPoolSettings( + instance.rpcUri, + None + ) } } @@ -413,15 +432,16 @@ trait Client /** Parses the payload of the given response into JSON. * - * The command, parameters and request are given as debug parameters, - * and only used for printing diagnostics if things go belly-up. + * The command, parameters and request are given as debug parameters, and + * only used for printing diagnostics if things go belly-up. */ protected def getPayload(response: HttpResponse): Future[JsValue] = { try { Unmarshal(response).to[String].map { data => if (data.isEmpty) { throw new IllegalArgumentException( - s"Bad authentication credentials supplied, cannot connect to bitcoind rpc") + s"Bad authentication credentials supplied, cannot connect to bitcoind rpc" + ) } else { Json.parse(data) } @@ -456,7 +476,8 @@ trait Client s"Error when parsing result of '$command': ${JsError.toJson(res).toString}!" if (printError) logger.error(errString + s"JSON: $jsonResult") throw new IllegalArgumentException( - s"Could not parse JsResult: $jsonResult! Error: $errString") + s"Could not parse JsResult: $jsonResult! Error: $errString" + ) } } } @@ -465,7 +486,8 @@ trait Client private def checkUnitError[T]( result: JsResult[T], json: JsValue, - printError: Boolean): Unit = { + printError: Boolean + ): Unit = { if (result == JsSuccess(())) { (json \ errorKey).validate[BitcoindException] match { case JsSuccess(err, _) => diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/DescriptorRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/DescriptorRpc.scala index 651d79c504..179fa30e24 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/DescriptorRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/DescriptorRpc.scala @@ -15,15 +15,18 @@ import play.api.libs.json.Json import scala.concurrent.Future /** RPC calls in V18 that use descriptor to give us output information - * @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/util/deriveaddresses/]] - * @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/util/getdescriptorinfo/]] + * @see + * [[https://bitcoincore.org/en/doc/0.18.0/rpc/util/deriveaddresses/]] + * @see + * [[https://bitcoincore.org/en/doc/0.18.0/rpc/util/getdescriptorinfo/]] */ trait DescriptorRpc { self: Client => def deriveAddresses( descriptor: Descriptor, - range: Option[Vector[Double]]): Future[DeriveAddressesResult] = { + range: Option[Vector[Double]] + ): Future[DeriveAddressesResult] = { val params = if (range.isDefined) List(DescriptorWrites.writes(descriptor), Json.toJson(range)) @@ -32,24 +35,30 @@ trait DescriptorRpc { } def getDescriptorInfo( - descriptor: Descriptor): Future[GetDescriptorInfoResult] = { + descriptor: Descriptor + ): Future[GetDescriptorInfoResult] = { bitcoindCall[GetDescriptorInfoResult]( "getdescriptorinfo", - List(DescriptorWrites.writes(descriptor))) + List(DescriptorWrites.writes(descriptor)) + ) } /** https://bitcoincore.org/en/doc/22.0.0/rpc/wallet/importdescriptors/ * @param imports * @return */ - def importDescriptors(imports: Vector[DescriptorsResult]): Future[ - Vector[ImportDescriptorResult]] = { - bitcoindCall[Vector[ImportDescriptorResult]]("importdescriptors", - List(Json.toJson(imports))) + def importDescriptors( + imports: Vector[DescriptorsResult] + ): Future[Vector[ImportDescriptorResult]] = { + bitcoindCall[Vector[ImportDescriptorResult]]( + "importdescriptors", + List(Json.toJson(imports)) + ) } def importDescriptor( - imp: DescriptorsResult): Future[ImportDescriptorResult] = { + imp: DescriptorsResult + ): Future[ImportDescriptorResult] = { importDescriptors(Vector(imp)).map(_.head) } @@ -61,7 +70,8 @@ trait DescriptorRpc { def listDescriptors( priv: Option[Boolean], - walletName: String): Future[ListDescriptorsResult] = { + walletName: String + ): Future[ListDescriptorsResult] = { bitcoindCall[ListDescriptorsResult]( "listdescriptors", List(Json.toJson(priv)), diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MempoolRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MempoolRpc.scala index 8a310c35e7..266f9f5a48 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MempoolRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MempoolRpc.scala @@ -10,101 +10,122 @@ import play.api.libs.json.{JsBoolean, JsString} import scala.concurrent.Future -/** This trait defines RPC calls related to - * the mempool of a Bitcoin Core node. The - * mempool contains all unconfirmed transactions. +/** This trait defines RPC calls related to the mempool of a Bitcoin Core node. + * The mempool contains all unconfirmed transactions. */ trait MempoolRpc { self: Client => def getMemPoolAncestors( - txid: DoubleSha256DigestBE): Future[Vector[DoubleSha256DigestBE]] = { + txid: DoubleSha256DigestBE + ): Future[Vector[DoubleSha256DigestBE]] = { bitcoindCall[Vector[DoubleSha256DigestBE]]( "getmempoolancestors", - List(JsString(txid.hex), JsBoolean(false))) + List(JsString(txid.hex), JsBoolean(false)) + ) } def getMemPoolAncestors( - txid: DoubleSha256Digest): Future[Vector[DoubleSha256DigestBE]] = { + txid: DoubleSha256Digest + ): Future[Vector[DoubleSha256DigestBE]] = { getMemPoolAncestors(txid.flip) } - def getMemPoolAncestorsVerbose(txid: DoubleSha256DigestBE): Future[ - Map[DoubleSha256DigestBE, GetMemPoolResult]] = { + def getMemPoolAncestorsVerbose( + txid: DoubleSha256DigestBE + ): Future[Map[DoubleSha256DigestBE, GetMemPoolResult]] = { self.version.flatMap { case V24 | V23 | V24 | Unknown => bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPostV23]]( "getmempoolancestors", - List(JsString(txid.hex), JsBoolean(true))) + List(JsString(txid.hex), JsBoolean(true)) + ) case V22 | Unknown => bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]]( "getmempoolancestors", - List(JsString(txid.hex), JsBoolean(true))) + List(JsString(txid.hex), JsBoolean(true)) + ) } } - def getMemPoolAncestorsVerbose(txid: DoubleSha256Digest): Future[ - Map[DoubleSha256DigestBE, GetMemPoolResult]] = { + def getMemPoolAncestorsVerbose( + txid: DoubleSha256Digest + ): Future[Map[DoubleSha256DigestBE, GetMemPoolResult]] = { getMemPoolAncestorsVerbose(txid.flip) } def getMemPoolDescendants( - txid: DoubleSha256DigestBE): Future[Vector[DoubleSha256DigestBE]] = { + txid: DoubleSha256DigestBE + ): Future[Vector[DoubleSha256DigestBE]] = { bitcoindCall[Vector[DoubleSha256DigestBE]]( "getmempooldescendants", - List(JsString(txid.hex), JsBoolean(false))) + List(JsString(txid.hex), JsBoolean(false)) + ) } def getMemPoolDescendants( - txid: DoubleSha256Digest): Future[Vector[DoubleSha256DigestBE]] = { + txid: DoubleSha256Digest + ): Future[Vector[DoubleSha256DigestBE]] = { getMemPoolDescendants(txid.flip) } - def getMemPoolDescendantsVerbose(txid: DoubleSha256DigestBE): Future[ - Map[DoubleSha256DigestBE, GetMemPoolResult]] = { + def getMemPoolDescendantsVerbose( + txid: DoubleSha256DigestBE + ): Future[Map[DoubleSha256DigestBE, GetMemPoolResult]] = { self.version.flatMap { case V24 | V23 | V24 | Unknown => bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPostV23]]( "getmempooldescendants", - List(JsString(txid.hex), JsBoolean(true))) + List(JsString(txid.hex), JsBoolean(true)) + ) case V22 | Unknown => bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]]( "getmempooldescendants", - List(JsString(txid.hex), JsBoolean(true))) + List(JsString(txid.hex), JsBoolean(true)) + ) } } - def getMemPoolDescendantsVerbose(txid: DoubleSha256Digest): Future[ - Map[DoubleSha256DigestBE, GetMemPoolResult]] = { + def getMemPoolDescendantsVerbose( + txid: DoubleSha256Digest + ): Future[Map[DoubleSha256DigestBE, GetMemPoolResult]] = { getMemPoolDescendantsVerbose(txid.flip) } def getMemPoolEntry( - txid: DoubleSha256DigestBE): Future[GetMemPoolEntryResult] = { + txid: DoubleSha256DigestBE + ): Future[GetMemPoolEntryResult] = { self.version.flatMap { case V24 | V23 | V24 | Unknown => - bitcoindCall[GetMemPoolEntryResultPostV23]("getmempoolentry", - List(JsString(txid.hex))) + bitcoindCall[GetMemPoolEntryResultPostV23]( + "getmempoolentry", + List(JsString(txid.hex)) + ) case V22 | Unknown => - bitcoindCall[GetMemPoolEntryResultPostV19]("getmempoolentry", - List(JsString(txid.hex))) + bitcoindCall[GetMemPoolEntryResultPostV19]( + "getmempoolentry", + List(JsString(txid.hex)) + ) } } def getMemPoolEntry( - txid: DoubleSha256Digest): Future[GetMemPoolEntryResult] = { + txid: DoubleSha256Digest + ): Future[GetMemPoolEntryResult] = { getMemPoolEntry(txid.flip) } def getMemPoolEntryOpt( - txid: DoubleSha256Digest): Future[Option[GetMemPoolEntryResult]] = { + txid: DoubleSha256Digest + ): Future[Option[GetMemPoolEntryResult]] = { getMemPoolEntryOpt(txid.flip) } def getMemPoolEntryOpt( - txid: DoubleSha256DigestBE): Future[Option[GetMemPoolEntryResult]] = { + txid: DoubleSha256DigestBE + ): Future[Option[GetMemPoolEntryResult]] = { getMemPoolEntry(txid) .map(Some(_)) .recover { case _: BitcoindException.InvalidAddressOrKey => @@ -117,22 +138,26 @@ trait MempoolRpc { self: Client => } def getRawMemPool: Future[Vector[DoubleSha256DigestBE]] = { - bitcoindCall[Vector[DoubleSha256DigestBE]]("getrawmempool", - List(JsBoolean(false))) + bitcoindCall[Vector[DoubleSha256DigestBE]]( + "getrawmempool", + List(JsBoolean(false)) + ) } - def getRawMemPoolWithTransactions: Future[ - Map[DoubleSha256DigestBE, GetMemPoolResult]] = { + def getRawMemPoolWithTransactions + : Future[Map[DoubleSha256DigestBE, GetMemPoolResult]] = { self.version.flatMap { case V24 | V23 | V24 | Unknown => bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPostV23]]( "getrawmempool", - List(JsBoolean(true))) + List(JsBoolean(true)) + ) case V22 | Unknown => bitcoindCall[Map[DoubleSha256DigestBE, GetMemPoolResultPostV19]]( "getrawmempool", - List(JsBoolean(true))) + List(JsBoolean(true)) + ) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MessageRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MessageRpc.scala index 2630f5e23d..7566949bf3 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MessageRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MessageRpc.scala @@ -7,30 +7,35 @@ import play.api.libs.json.JsString import scala.concurrent.Future -/** RPC calls related to the message signing functionality - * in bitcoind +/** RPC calls related to the message signing functionality in bitcoind */ trait MessageRpc { self: Client => def signMessage(address: P2PKHAddress, message: String): Future[String] = { - bitcoindCall[String]("signmessage", - List(JsString(address.value), JsString(message))) + bitcoindCall[String]( + "signmessage", + List(JsString(address.value), JsString(message)) + ) } def signMessageWithPrivKey( key: ECPrivateKeyBytes, - message: String): Future[String] = { + message: String + ): Future[String] = { bitcoindCall[String]( "signmessagewithprivkey", - List(JsString(ECPrivateKeyUtil.toWIF(key, network)), JsString(message))) + List(JsString(ECPrivateKeyUtil.toWIF(key, network)), JsString(message)) + ) } def verifyMessage( address: P2PKHAddress, signature: String, - message: String): Future[Boolean] = { + message: String + ): Future[Boolean] = { bitcoindCall[Boolean]( "verifymessage", - List(JsString(address.value), JsString(signature), JsString(message))) + List(JsString(address.value), JsString(signature), JsString(message)) + ) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MiningRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MiningRpc.scala index 0aaa982356..aebd1b4688 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MiningRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MiningRpc.scala @@ -23,10 +23,12 @@ trait MiningRpc { self: Client with BlockchainRpc => def generateToAddress( blocks: Int, address: BitcoinAddress, - maxTries: Int = 1000000): Future[Vector[DoubleSha256DigestBE]] = { + maxTries: Int = 1000000 + ): Future[Vector[DoubleSha256DigestBE]] = { val hashesF = bitcoindCall[Vector[DoubleSha256DigestBE]]( "generatetoaddress", - List(JsNumber(blocks), JsString(address.toString), JsNumber(maxTries))) + List(JsNumber(blocks), JsString(address.toString), JsNumber(maxTries)) + ) for { hashes <- hashesF @@ -41,15 +43,17 @@ trait MiningRpc { self: Client with BlockchainRpc => val txsJs = JsArray(transactions.map(t => JsString(t.hex))) val hashesF = bitcoindCall[GenerateBlockResult]( "generateblock", - List(JsString(address.toString), txsJs)).map(_.hash) + List(JsString(address.toString), txsJs) + ).map(_.hash) for { hash <- hashesF _ <- syncWithValidationInterfaceQueue() } yield hash } - def getBlockTemplate(request: Option[RpcOpts.BlockTemplateRequest] = - None): Future[GetBlockTemplateResult] = { + def getBlockTemplate( + request: Option[RpcOpts.BlockTemplateRequest] = None + ): Future[GetBlockTemplateResult] = { val params = if (request.isEmpty) { List.empty @@ -61,9 +65,12 @@ trait MiningRpc { self: Client with BlockchainRpc => def getNetworkHashPS( blocks: Int = 120, - height: Int = -1): Future[BigDecimal] = { - bitcoindCall[BigDecimal]("getnetworkhashps", - List(JsNumber(blocks), JsNumber(height))) + height: Int = -1 + ): Future[BigDecimal] = { + bitcoindCall[BigDecimal]( + "getnetworkhashps", + List(JsNumber(blocks), JsNumber(height)) + ) } def getMiningInfo: Future[GetMiningInfoResult] = { @@ -72,15 +79,18 @@ trait MiningRpc { self: Client with BlockchainRpc => def prioritiseTransaction( txid: DoubleSha256DigestBE, - feeDelta: Satoshis): Future[Boolean] = { + feeDelta: Satoshis + ): Future[Boolean] = { bitcoindCall[Boolean]( "prioritisetransaction", - List(JsString(txid.hex), JsNumber(0), JsNumber(feeDelta.toLong))) + List(JsString(txid.hex), JsNumber(0), JsNumber(feeDelta.toLong)) + ) } def prioritiseTransaction( txid: DoubleSha256Digest, - feeDelta: Satoshis): Future[Boolean] = { + feeDelta: Satoshis + ): Future[Boolean] = { prioritiseTransaction(txid.flip, feeDelta) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MultisigRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MultisigRpc.scala index b061ce5fac..94f619e2b8 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MultisigRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/MultisigRpc.scala @@ -14,11 +14,12 @@ import play.api.libs.json.{JsArray, JsNumber, JsString, Json} import scala.concurrent.Future -/** This trait defines RPC calls related to - * multisignature functionality in Bitcoin Core. +/** This trait defines RPC calls related to multisignature functionality in + * Bitcoin Core. * - * @see [[https://en.bitcoin.it/wiki/Multisignature Bitcoin Wiki]] - * article on multisignature. + * @see + * [[https://en.bitcoin.it/wiki/Multisignature Bitcoin Wiki]] article on + * multisignature. */ trait MultisigRpc { self: Client => @@ -27,7 +28,8 @@ trait MultisigRpc { self: Client => keys: Vector[Either[ECPublicKey, P2PKHAddress]], account: String = "", addressType: Option[AddressType], - walletNameOpt: Option[String] = None): Future[MultiSigResult] = { + walletNameOpt: Option[String] = None + ): Future[MultiSigResult] = { def keyToString(key: Either[ECPublicKey, P2PKHAddress]): JsString = key match { case Right(k) => JsString(k.value) @@ -35,53 +37,63 @@ trait MultisigRpc { self: Client => } val params = - List(JsNumber(minSignatures), - JsArray(keys.map(keyToString)), - JsString(account)) ++ addressType.map(Json.toJson(_)).toList + List( + JsNumber(minSignatures), + JsArray(keys.map(keyToString)), + JsString(account) + ) ++ addressType.map(Json.toJson(_)).toList self.version.flatMap { case V24 | V23 | V22 | Unknown => - bitcoindCall[MultiSigResultPostV20]("addmultisigaddress", - params, - uriExtensionOpt = - walletNameOpt.map(walletExtension)) + bitcoindCall[MultiSigResultPostV20]( + "addmultisigaddress", + params, + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } } def addMultiSigAddress( minSignatures: Int, - keys: Vector[Either[ECPublicKey, P2PKHAddress]]): Future[MultiSigResult] = + keys: Vector[Either[ECPublicKey, P2PKHAddress]] + ): Future[MultiSigResult] = addMultiSigAddress(minSignatures, keys, addressType = None) def addMultiSigAddress( minSignatures: Int, keys: Vector[Either[ECPublicKey, P2PKHAddress]], - account: String): Future[MultiSigResult] = + account: String + ): Future[MultiSigResult] = addMultiSigAddress(minSignatures, keys, account, None) def addMultiSigAddress( minSignatures: Int, keys: Vector[Either[ECPublicKey, P2PKHAddress]], - addressType: AddressType): Future[MultiSigResult] = + addressType: AddressType + ): Future[MultiSigResult] = addMultiSigAddress(minSignatures, keys, addressType = Some(addressType)) def addMultiSigAddress( minSignatures: Int, keys: Vector[Either[ECPublicKey, P2PKHAddress]], account: String, - addressType: AddressType): Future[MultiSigResult] = + addressType: AddressType + ): Future[MultiSigResult] = addMultiSigAddress(minSignatures, keys, account, Some(addressType)) def createMultiSig( minSignatures: Int, keys: Vector[ECPublicKey], addressType: AddressType, - walletNameOpt: Option[String] = None): Future[MultiSigResult] = { + walletNameOpt: Option[String] = None + ): Future[MultiSigResult] = { self.version.flatMap { case V24 | V23 | V22 | Unknown => bitcoindCall[MultiSigResultPostV20]( "createmultisig", - List(JsNumber(minSignatures), - Json.toJson(keys.map(_.hex)), - Json.toJson(addressType)), + List( + JsNumber(minSignatures), + Json.toJson(keys.map(_.hex)), + Json.toJson(addressType) + ), uriExtensionOpt = walletNameOpt.map(walletExtension) ) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/NodeRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/NodeRpc.scala index 3757f1c0f0..4a3f57baf9 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/NodeRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/NodeRpc.scala @@ -18,12 +18,14 @@ trait NodeRpc { self: Client => private def logging( include: Option[Vector[String]], - exclude: Option[Vector[String]]): Future[Map[String, Boolean]] = { - val params = List(Json.toJson(include.getOrElse(Vector.empty)), - Json.toJson(exclude.getOrElse(Vector.empty))) + exclude: Option[Vector[String]] + ): Future[Map[String, Boolean]] = { + val params = List( + Json.toJson(include.getOrElse(Vector.empty)), + Json.toJson(exclude.getOrElse(Vector.empty)) + ) - /** Bitcoin Core v0.16 returns a map of 1/0s, - * v0.17 returns proper booleans + /** Bitcoin Core v0.16 returns a map of 1/0s, v0.17 returns proper booleans */ object IntOrBoolReads extends Reads[Boolean] { override def reads(json: JsValue): JsResult[Boolean] = @@ -51,7 +53,8 @@ trait NodeRpc { self: Client => def logging( include: Vector[String] = Vector.empty, - exclude: Vector[String] = Vector.empty): Future[Map[String, Boolean]] = { + exclude: Vector[String] = Vector.empty + ): Future[Map[String, Boolean]] = { val inc = if (include.nonEmpty) Some(include) else None val exc = if (exclude.nonEmpty) Some(exclude) else None logging(inc, exc) diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/P2PRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/P2PRpc.scala index edb527bcf5..4806bb51c0 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/P2PRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/P2PRpc.scala @@ -13,15 +13,16 @@ import play.api.libs.json.{JsBoolean, JsNumber, JsString} import java.net.URI import scala.concurrent.Future -/** This trait defines functionality relating to how - * Bitcoin Core connects to and selects its network peers. +/** This trait defines functionality relating to how Bitcoin Core connects to + * and selects its network peers. */ trait P2PRpc { self: Client => def addNode(address: URI, command: AddNodeArgument): Future[Unit] = { bitcoindCall[Unit]( "addnode", - List(JsString(address.getAuthority), JsString(command.toString))) + List(JsString(address.getAuthority), JsString(command.toString)) + ) } def clearBanned(): Future[Unit] = { @@ -78,12 +79,17 @@ trait P2PRpc { self: Client => address: URI, command: SetBanCommand, banTime: Int = 86400, - absolute: Boolean = false): Future[Unit] = { - bitcoindCall[Unit]("setban", - List(JsString(address.getAuthority), - JsString(command.toString), - JsNumber(banTime), - JsBoolean(absolute))) + absolute: Boolean = false + ): Future[Unit] = { + bitcoindCall[Unit]( + "setban", + List( + JsString(address.getAuthority), + JsString(command.toString), + JsNumber(banTime), + JsBoolean(absolute) + ) + ) } def setNetworkActive(activate: Boolean): Future[Unit] = { diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/PsbtRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/PsbtRpc.scala index ff02ba56c7..7ca517b2bc 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/PsbtRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/PsbtRpc.scala @@ -19,9 +19,12 @@ import scala.concurrent.Future /** Set of utilities to analyze, join, and update existing PSBTs * - * @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/rawtransactions/analyzepsbt/]] - * @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/rawtransactions/joinpsbts/]] - * @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/rawtransactions/utxoupdatepsbt/]] + * @see + * [[https://bitcoincore.org/en/doc/0.18.0/rpc/rawtransactions/analyzepsbt/]] + * @see + * [[https://bitcoincore.org/en/doc/0.18.0/rpc/rawtransactions/joinpsbts/]] + * @see + * [[https://bitcoincore.org/en/doc/0.18.0/rpc/rawtransactions/utxoupdatepsbt/]] */ trait PsbtRpc { self: Client => @@ -39,14 +42,17 @@ trait PsbtRpc { } def utxoUpdatePsbt(psbt: PSBT, descriptors: Seq[String]): Future[PSBT] = { - bitcoindCall[PSBT]("utxoupdatepsbt", - List(JsString(psbt.base64), Json.toJson(descriptors))) + bitcoindCall[PSBT]( + "utxoupdatepsbt", + List(JsString(psbt.base64), Json.toJson(descriptors)) + ) } def convertToPsbt( rawTx: Transaction, permitSigData: Boolean = false, - isWitness: Option[Boolean] = None): Future[PSBT] = { + isWitness: Option[Boolean] = None + ): Future[PSBT] = { val firstArgs: List[JsValue] = List(Json.toJson(rawTx), JsBoolean(permitSigData)) val args: List[JsValue] = firstArgs ++ isWitness.map(Json.toJson(_)).toList @@ -57,18 +63,23 @@ trait PsbtRpc { inputs: Vector[TransactionInput], outputs: Map[BitcoinAddress, CurrencyUnit], locktime: Int = 0, - replacable: Boolean = false): Future[PSBT] = { + replacable: Boolean = false + ): Future[PSBT] = { val outputsJson = Json.toJson { outputs.map { case (addr, curr) => addr -> Bitcoins(curr.satoshis) } } - bitcoindCall[PSBT]("createpsbt", - List(Json.toJson(inputs), - outputsJson, - JsNumber(locktime), - JsBoolean(replacable))) + bitcoindCall[PSBT]( + "createpsbt", + List( + Json.toJson(inputs), + outputsJson, + JsNumber(locktime), + JsBoolean(replacable) + ) + ) } def combinePsbt(psbts: Vector[PSBT]): Future[PSBT] = { @@ -77,10 +88,12 @@ trait PsbtRpc { def finalizePsbt( psbt: PSBT, - extract: Boolean = true): Future[FinalizePsbtResult] = { + extract: Boolean = true + ): Future[FinalizePsbtResult] = { bitcoindCall[FinalizePsbtResult]( "finalizepsbt", - List(JsString(psbt.base64), JsBoolean(extract))) + List(JsString(psbt.base64), JsBoolean(extract)) + ) } def decodePsbt(psbt: PSBT): Future[DecodePsbtResult] = { diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/RawTransactionRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/RawTransactionRpc.scala index 2ad9b88530..45202974ac 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/RawTransactionRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/RawTransactionRpc.scala @@ -19,9 +19,8 @@ import play.api.libs.json._ import scala.concurrent.Future -/** This trait defines RPC calls relating to interacting - * with raw transactions. This includes creation, decoding - * funding and sending. +/** This trait defines RPC calls relating to interacting with raw transactions. + * This includes creation, decoding funding and sending. */ trait RawTransactionRpc { self: Client => @@ -32,35 +31,41 @@ trait RawTransactionRpc { self: Client => def createRawTransaction( inputs: Vector[TransactionInput], outputs: Map[BitcoinAddress, Bitcoins], - locktime: Int = 0): Future[Transaction] = { + locktime: Int = 0 + ): Future[Transaction] = { bitcoindCall[Transaction]( "createrawtransaction", - List(Json.toJson(inputs), Json.toJson(outputs), JsNumber(locktime))) + List(Json.toJson(inputs), Json.toJson(outputs), JsNumber(locktime)) + ) } def decodeRawTransaction(transaction: Transaction): Future[RpcTransaction] = { self.version.flatMap { case V22 | V23 | V24 | Unknown => - bitcoindCall[RpcTransactionV22]("decoderawtransaction", - List(JsString(transaction.hex))) + bitcoindCall[RpcTransactionV22]( + "decoderawtransaction", + List(JsString(transaction.hex)) + ) } } def fundRawTransaction( - transaction: Transaction): Future[FundRawTransactionResult] = + transaction: Transaction + ): Future[FundRawTransactionResult] = fundRawTransaction(transaction, None) def fundRawTransaction( transaction: Transaction, - walletName: String): Future[FundRawTransactionResult] = + walletName: String + ): Future[FundRawTransactionResult] = fundRawTransaction(transaction, None, Some(walletName)) private def fundRawTransaction( transaction: Transaction, options: Option[RpcOpts.FundRawTransactionOptions], - walletNameOpt: Option[String] = None): Future[ - FundRawTransactionResult] = { + walletNameOpt: Option[String] = None + ): Future[FundRawTransactionResult] = { val params = if (options.isEmpty) { List(JsString(transaction.hex)) @@ -68,27 +73,30 @@ trait RawTransactionRpc { self: Client => List(JsString(transaction.hex), Json.toJson(options.get)) } - bitcoindCall[FundRawTransactionResult]("fundrawtransaction", - params, - uriExtensionOpt = - walletNameOpt.map(walletExtension)) + bitcoindCall[FundRawTransactionResult]( + "fundrawtransaction", + params, + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def fundRawTransaction( transaction: Transaction, - options: RpcOpts.FundRawTransactionOptions): Future[ - FundRawTransactionResult] = fundRawTransaction(transaction, Some(options)) + options: RpcOpts.FundRawTransactionOptions + ): Future[FundRawTransactionResult] = + fundRawTransaction(transaction, Some(options)) def fundRawTransaction( transaction: Transaction, options: RpcOpts.FundRawTransactionOptions, - walletName: String): Future[FundRawTransactionResult] = + walletName: String + ): Future[FundRawTransactionResult] = fundRawTransaction(transaction, Some(options), Some(walletName)) def getRawTransaction( txid: DoubleSha256DigestBE, - blockhash: Option[DoubleSha256DigestBE] = None): Future[ - GetRawTransactionResult] = { + blockhash: Option[DoubleSha256DigestBE] = None + ): Future[GetRawTransactionResult] = { val lastParam: List[JsString] = blockhash match { case Some(hash) => JsString(hash.hex) :: Nil case None => Nil @@ -102,7 +110,8 @@ trait RawTransactionRpc { self: Client => def getRawTransactionRaw( txid: DoubleSha256DigestBE, - blockhash: Option[DoubleSha256DigestBE] = None): Future[Transaction] = { + blockhash: Option[DoubleSha256DigestBE] = None + ): Future[Transaction] = { val lastParam: List[JsString] = blockhash match { case Some(hash) => JsString(hash.hex) :: Nil case None => Nil @@ -112,14 +121,17 @@ trait RawTransactionRpc { self: Client => bitcoindCall[Transaction]("getrawtransaction", params) } - /** @param maxfeerate Set to 0 if you want to enable allowhighfees + /** @param maxfeerate + * Set to 0 if you want to enable allowhighfees */ def sendRawTransaction( transaction: Transaction, - maxfeerate: Double = 0.10): Future[DoubleSha256DigestBE] = { + maxfeerate: Double = 0.10 + ): Future[DoubleSha256DigestBE] = { bitcoindCall[DoubleSha256DigestBE]( "sendrawtransaction", - List(JsString(transaction.hex), JsNumber(maxfeerate))) + List(JsString(transaction.hex), JsNumber(maxfeerate)) + ) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/TransactionRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/TransactionRpc.scala index 9187efe17e..b2dbe88cc2 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/TransactionRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/TransactionRpc.scala @@ -11,9 +11,9 @@ import play.api.libs.json._ import scala.concurrent.Future -/** This trait defines RPC calls related to transactions - * in Bitcoin Core. These RPC calls generally provide a - * higher level of abstraction than the ones found in +/** This trait defines RPC calls related to transactions in Bitcoin Core. These + * RPC calls generally provide a higher level of abstraction than the ones + * found in * [[org.bitcoins.rpc.client.common.RawTransactionRpc RawTransactionRpc]]. */ trait TransactionRpc { self: Client => @@ -31,11 +31,14 @@ trait TransactionRpc { self: Client => confTarget: Int = 6, totalFee: Option[Satoshis] = None, replaceable: Boolean = true, - estimateMode: String = "UNSET"): Future[BumpFeeResult] = { + estimateMode: String = "UNSET" + ): Future[BumpFeeResult] = { val optionsNoFee = - Map("confTarget" -> JsNumber(confTarget), - "replaceable" -> JsBoolean(replaceable), - "estimate_mode" -> JsString(estimateMode)) + Map( + "confTarget" -> JsNumber(confTarget), + "replaceable" -> JsBoolean(replaceable), + "estimate_mode" -> JsString(estimateMode) + ) val options = totalFee match { case Some(fee) => @@ -43,8 +46,10 @@ trait TransactionRpc { self: Client => case None => optionsNoFee } - bitcoindCall[BumpFeeResult]("bumpfee", - List(JsString(txid.hex), JsObject(options))) + bitcoindCall[BumpFeeResult]( + "bumpfee", + List(JsString(txid.hex), JsObject(options)) + ) } def bumpFee( @@ -52,50 +57,58 @@ trait TransactionRpc { self: Client => confTarget: Int, totalFee: Option[Satoshis], replaceable: Boolean, - estimateMode: String): Future[BumpFeeResult] = { + estimateMode: String + ): Future[BumpFeeResult] = { bumpFee(txid.flip, confTarget, totalFee, replaceable, estimateMode) } // Needs manual testing! def estimateSmartFee( blocks: Int, - mode: FeeEstimationMode = FeeEstimationMode.Ecnomical): Future[ - EstimateSmartFeeResult] = { + mode: FeeEstimationMode = FeeEstimationMode.Ecnomical + ): Future[EstimateSmartFeeResult] = { bitcoindCall[EstimateSmartFeeResult]( "estimatesmartfee", - List(JsNumber(blocks), JsString(mode.toString))) + List(JsNumber(blocks), JsString(mode.toString)) + ) } def getTransaction( txid: DoubleSha256DigestBE, watchOnly: Boolean = false, - walletNameOpt: Option[String] = None): Future[GetTransactionResult] = { + walletNameOpt: Option[String] = None + ): Future[GetTransactionResult] = { bitcoindCall[GetTransactionResult]( "gettransaction", List(JsString(txid.hex), JsBoolean(watchOnly)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def getTxOut( txid: DoubleSha256DigestBE, vout: Long, - includeMemPool: Boolean = true): Future[GetTxOutResult] = { + includeMemPool: Boolean = true + ): Future[GetTxOutResult] = { self.version.flatMap { case V22 | V23 | V24 | Unknown => bitcoindCall[GetTxOutResultV22]( "gettxout", - List(JsString(txid.hex), JsNumber(vout), JsBoolean(includeMemPool))) + List(JsString(txid.hex), JsNumber(vout), JsBoolean(includeMemPool)) + ) } } def getTxOutOpt( txid: DoubleSha256DigestBE, vout: Long, - includeMemPool: Boolean = true): Future[Option[GetTxOutResult]] = { + includeMemPool: Boolean = true + ): Future[Option[GetTxOutResult]] = { self.version .flatMap { case V22 | V23 | V24 | Unknown => bitcoindCall[GetTxOutResultV22]( "gettxout", - List(JsString(txid.hex), JsNumber(vout), JsBoolean(includeMemPool))) + List(JsString(txid.hex), JsNumber(vout), JsBoolean(includeMemPool)) + ) } .map(Some(_)) .recover(_ => None) @@ -103,7 +116,8 @@ trait TransactionRpc { self: Client => private def getTxOutProof( txids: Vector[DoubleSha256DigestBE], - headerHash: Option[DoubleSha256DigestBE]): Future[MerkleBlock] = { + headerHash: Option[DoubleSha256DigestBE] + ): Future[MerkleBlock] = { val params = { val hashes = JsArray(txids.map(hash => JsString(hash.hex))) if (headerHash.isEmpty) { @@ -120,18 +134,23 @@ trait TransactionRpc { self: Client => def getTxOutProof( txids: Vector[DoubleSha256Digest], - headerHash: DoubleSha256Digest): Future[MerkleBlock] = + headerHash: DoubleSha256Digest + ): Future[MerkleBlock] = getTxOutProof(txids.map(_.flip), Some(headerHash.flip)) def getTxOutProof( txids: Vector[DoubleSha256DigestBE], - headerHash: DoubleSha256DigestBE): Future[MerkleBlock] = + headerHash: DoubleSha256DigestBE + ): Future[MerkleBlock] = getTxOutProof(txids, Some(headerHash)) def verifyTxOutProof( - proof: MerkleBlock): Future[Vector[DoubleSha256DigestBE]] = { - bitcoindCall[Vector[DoubleSha256DigestBE]]("verifytxoutproof", - List(JsString(proof.hex))) + proof: MerkleBlock + ): Future[Vector[DoubleSha256DigestBE]] = { + bitcoindCall[Vector[DoubleSha256DigestBE]]( + "verifytxoutproof", + List(JsString(proof.hex)) + ) } def getTxOutSetInfo: Future[GetTxOutSetInfoResult] = { diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UTXORpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UTXORpc.scala index 0b68ad62aa..86455f1711 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UTXORpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UTXORpc.scala @@ -8,11 +8,12 @@ import play.api.libs.json._ import scala.concurrent.Future -/** This trait defines functionality related to - * UTXOs (unspent transaction outputs). +/** This trait defines functionality related to UTXOs (unspent transaction + * outputs). * - * @see [[https://bitcoin.org/en/developer-guide#term-utxo Bitcoin.org]] - * developer guide article on UTXOs + * @see + * [[https://bitcoin.org/en/developer-guide#term-utxo Bitcoin.org]] developer + * guide article on UTXOs */ trait UTXORpc { self: Client => @@ -27,38 +28,46 @@ trait UTXORpc { self: Client => def listUnspent( minConfirmations: Int, - maxConfirmations: Int): Future[Vector[UnspentOutput]] = + maxConfirmations: Int + ): Future[Vector[UnspentOutput]] = listUnspent(minConfirmations, maxConfirmations, None) def listUnspent( - addresses: Vector[BitcoinAddress]): Future[Vector[UnspentOutput]] = + addresses: Vector[BitcoinAddress] + ): Future[Vector[UnspentOutput]] = listUnspent(addresses = addresses) def listUnspent( minConfirmations: Int, maxConfirmations: Int, - addresses: Vector[BitcoinAddress]): Future[Vector[UnspentOutput]] = + addresses: Vector[BitcoinAddress] + ): Future[Vector[UnspentOutput]] = listUnspent(minConfirmations, maxConfirmations, Some(addresses)) private def listUnspent( minConfirmations: Int = 1, maxConfirmations: Int = 9999999, addresses: Option[Vector[BitcoinAddress]], - walletNameOpt: Option[String] = None): Future[Vector[UnspentOutput]] = { + walletNameOpt: Option[String] = None + ): Future[Vector[UnspentOutput]] = { val params = List(JsNumber(minConfirmations), JsNumber(maxConfirmations)) ++ addresses.map(Json.toJson(_)).toList - bitcoindCall[Vector[UnspentOutput]]("listunspent", - params, - uriExtensionOpt = - walletNameOpt.map(walletExtension)) + bitcoindCall[Vector[UnspentOutput]]( + "listunspent", + params, + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def lockUnspent( unlock: Boolean, - outputs: Vector[RpcOpts.LockUnspentOutputParameter]): Future[Boolean] = { - bitcoindCall[Boolean]("lockunspent", - List(JsBoolean(unlock), Json.toJson(outputs))) + outputs: Vector[RpcOpts.LockUnspentOutputParameter] + ): Future[Boolean] = { + bitcoindCall[Boolean]( + "lockunspent", + List(JsBoolean(unlock), Json.toJson(outputs)) + ) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UtilRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UtilRpc.scala index 521294675a..d33a4274df 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UtilRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/UtilRpc.scala @@ -15,15 +15,20 @@ import scala.concurrent.Future trait UtilRpc { self: Client => def validateAddress( - address: BitcoinAddress): Future[ValidateAddressResult] = { - bitcoindCall[ValidateAddressResultImpl]("validateaddress", - List(JsString(address.toString))) + address: BitcoinAddress + ): Future[ValidateAddressResult] = { + bitcoindCall[ValidateAddressResultImpl]( + "validateaddress", + List(JsString(address.toString)) + ) } def decodeScript(script: ScriptPubKey): Future[DecodeScriptResult] = { self.version.flatMap { case V22 | V23 | V24 | Unknown => - bitcoindCall[DecodeScriptResultV22]("decodescript", - List(Json.toJson(script))) + bitcoindCall[DecodeScriptResultV22]( + "decodescript", + List(Json.toJson(script)) + ) } } @@ -38,7 +43,8 @@ trait UtilRpc { self: Client => version.flatMap { case V24 | V23 | V22 | Unknown => bitcoindCall[Map[String, IndexInfoResult]]( "getindexinfo", - List(JsString(indexName))).map(_.head._2) + List(JsString(indexName)) + ).map(_.head._2) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/WalletRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/WalletRpc.scala index ec7013929e..27917d8aa1 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/WalletRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/WalletRpc.scala @@ -19,25 +19,30 @@ import play.api.libs.json._ import scala.concurrent.Future -/** RPC calls related to wallet management - * functionality in bitcoind +/** RPC calls related to wallet management functionality in bitcoind */ trait WalletRpc { self: Client => def backupWallet( destination: String, - walletNameOpt: Option[String] = None): Future[Unit] = { - bitcoindCall[Unit]("backupwallet", - List(JsString(destination)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + walletNameOpt: Option[String] = None + ): Future[Unit] = { + bitcoindCall[Unit]( + "backupwallet", + List(JsString(destination)), + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def encryptWallet( passphrase: String, - walletNameOpt: Option[String] = None): Future[String] = { - bitcoindCall[String]("encryptwallet", - List(JsString(passphrase)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + walletNameOpt: Option[String] = None + ): Future[String] = { + bitcoindCall[String]( + "encryptwallet", + List(JsString(passphrase)), + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def getBalance: Future[Bitcoins] = { @@ -45,18 +50,22 @@ trait WalletRpc { self: Client => } def getBalance(walletName: String): Future[Bitcoins] = { - bitcoindCall[Bitcoins]("getbalance", - uriExtensionOpt = Some(walletExtension(walletName))) + bitcoindCall[Bitcoins]( + "getbalance", + uriExtensionOpt = Some(walletExtension(walletName)) + ) } def getReceivedByAddress( address: BitcoinAddress, minConfirmations: Int = 1, - walletNameOpt: Option[String] = None): Future[Bitcoins] = { + walletNameOpt: Option[String] = None + ): Future[Bitcoins] = { bitcoindCall[Bitcoins]( "getreceivedbyaddress", List(JsString(address.toString), JsNumber(minConfirmations)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def getUnconfirmedBalance: Future[Bitcoins] = { @@ -64,21 +73,25 @@ trait WalletRpc { self: Client => } def getUnconfirmedBalance(walletName: String): Future[Bitcoins] = { - bitcoindCall[Bitcoins]("getunconfirmedbalance", - uriExtensionOpt = Some(walletExtension(walletName))) + bitcoindCall[Bitcoins]( + "getunconfirmedbalance", + uriExtensionOpt = Some(walletExtension(walletName)) + ) } private def getNewAddressInternal( accountOrLabel: String = "", addressType: Option[AddressType], - walletNameOpt: Option[String] = None): Future[BitcoinAddress] = { + walletNameOpt: Option[String] = None + ): Future[BitcoinAddress] = { val params = List(JsString(accountOrLabel)) ++ addressType.map(Json.toJson(_)).toList bitcoindCall[BitcoinAddress]( "getnewaddress", params, - uriExtensionOpt = walletNameOpt.map(walletExtension)).map(addr => + uriExtensionOpt = walletNameOpt.map(walletExtension) + ).map(addr => BitcoinAddress.fromScriptPubKey(addr.scriptPubKey, instance.network)) } @@ -96,22 +109,26 @@ trait WalletRpc { self: Client => def getNewAddress( accountOrLabel: String, - addressType: AddressType): Future[BitcoinAddress] = + addressType: AddressType + ): Future[BitcoinAddress] = getNewAddressInternal(accountOrLabel, Some(addressType)) def getNewAddress( accountOrLabel: String, addressType: AddressType, - walletName: String): Future[BitcoinAddress] = + walletName: String + ): Future[BitcoinAddress] = getNewAddressInternal(accountOrLabel, Some(addressType), Some(walletName)) private def getRawChangeAddressInternal( addressType: Option[AddressType], - walletNameOpt: Option[String] = None): Future[BitcoinAddress] = { - bitcoindCall[BitcoinAddress]("getrawchangeaddress", - addressType.map(Json.toJson(_)).toList, - uriExtensionOpt = - walletNameOpt.map(walletExtension)) + walletNameOpt: Option[String] = None + ): Future[BitcoinAddress] = { + bitcoindCall[BitcoinAddress]( + "getrawchangeaddress", + addressType.map(Json.toJson(_)).toList, + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def getRawChangeAddress: Future[BitcoinAddress] = @@ -125,17 +142,20 @@ trait WalletRpc { self: Client => def getRawChangeAddress( addressType: AddressType, - walletName: String): Future[BitcoinAddress] = + walletName: String + ): Future[BitcoinAddress] = getRawChangeAddressInternal(Some(addressType), Some(walletName)) private def getWalletInfo( - walletName: Option[String]): Future[GetWalletInfoResult] = { + walletName: Option[String] + ): Future[GetWalletInfoResult] = { self.version.flatMap { case BitcoindVersion.V22 | BitcoindVersion.V23 | BitcoindVersion.V24 | BitcoindVersion.Unknown => bitcoindCall[GetWalletInfoResultPostV22]( "getwalletinfo", - uriExtensionOpt = walletName.map(walletExtension)) + uriExtensionOpt = walletName.map(walletExtension) + ) } } @@ -151,39 +171,48 @@ trait WalletRpc { self: Client => */ def keyPoolRefill( keyPoolSize: Int = 100, - walletNameOpt: Option[String] = None): Future[Unit] = { - bitcoindCall[Unit]("keypoolrefill", - List(JsNumber(keyPoolSize)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + walletNameOpt: Option[String] = None + ): Future[Unit] = { + bitcoindCall[Unit]( + "keypoolrefill", + List(JsNumber(keyPoolSize)), + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def importMulti( requests: Vector[RpcOpts.ImportMultiRequest], rescan: Boolean = true, - walletNameOpt: Option[String] = None): Future[ - Vector[ImportMultiResult]] = { + walletNameOpt: Option[String] = None + ): Future[Vector[ImportMultiResult]] = { bitcoindCall[Vector[ImportMultiResult]]( "importmulti", List(Json.toJson(requests), JsObject(Map("rescan" -> JsBoolean(rescan)))), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def importPrunedFunds( transaction: Transaction, txOutProof: MerkleBlock, - walletNameOpt: Option[String] = None): Future[Unit] = { + walletNameOpt: Option[String] = None + ): Future[Unit] = { bitcoindCall[Unit]( "importprunedfunds", List(JsString(transaction.hex), JsString(txOutProof.hex)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def removePrunedFunds( txid: DoubleSha256DigestBE, - walletNameOpt: Option[String]): Future[Unit] = { - bitcoindCall[Unit]("removeprunedfunds", - List(JsString(txid.hex)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + walletNameOpt: Option[String] + ): Future[Unit] = { + bitcoindCall[Unit]( + "removeprunedfunds", + List(JsString(txid.hex)), + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def removePrunedFunds(txid: DoubleSha256DigestBE): Future[Unit] = { @@ -196,7 +225,8 @@ trait WalletRpc { self: Client => def removePrunedFunds( txid: DoubleSha256Digest, - walletNameOpt: Option[String]): Future[Unit] = { + walletNameOpt: Option[String] + ): Future[Unit] = { removePrunedFunds(txid.flip, walletNameOpt) } @@ -205,22 +235,27 @@ trait WalletRpc { self: Client => } def listAddressGroupings( - walletName: String): Future[Vector[Vector[RpcAddress]]] = { + walletName: String + ): Future[Vector[Vector[RpcAddress]]] = { bitcoindCall[Vector[Vector[RpcAddress]]]( "listaddressgroupings", - uriExtensionOpt = Some(walletExtension(walletName))) + uriExtensionOpt = Some(walletExtension(walletName)) + ) } def listReceivedByAddress( confirmations: Int = 1, includeEmpty: Boolean = false, includeWatchOnly: Boolean = false, - walletNameOpt: Option[String] = None): Future[Vector[ReceivedAddress]] = { + walletNameOpt: Option[String] = None + ): Future[Vector[ReceivedAddress]] = { bitcoindCall[Vector[ReceivedAddress]]( "listreceivedbyaddress", - List(JsNumber(confirmations), - JsBoolean(includeEmpty), - JsBoolean(includeWatchOnly)), + List( + JsNumber(confirmations), + JsBoolean(includeEmpty), + JsBoolean(includeWatchOnly) + ), uriExtensionOpt = walletNameOpt.map(walletExtension) ) } @@ -247,7 +282,8 @@ trait WalletRpc { self: Client => bitcoindCall[SetWalletFlagResult]( "setwalletflag", List(JsString(flag.toString), Json.toJson(value)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def getBalances: Future[GetBalancesResult] = { @@ -255,18 +291,22 @@ trait WalletRpc { self: Client => } def getBalances(walletName: String): Future[GetBalancesResult] = { - bitcoindCall[GetBalancesResult]("getbalances", - uriExtensionOpt = - Some(walletExtension(walletName))) + bitcoindCall[GetBalancesResult]( + "getbalances", + uriExtensionOpt = Some(walletExtension(walletName)) + ) } // TODO: Should be BitcoinFeeUnit def setTxFee( feePerKB: Bitcoins, - walletNameOpt: Option[String] = None): Future[Boolean] = { - bitcoindCall[Boolean]("settxfee", - List(JsNumber(feePerKB.toBigDecimal)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + walletNameOpt: Option[String] = None + ): Future[Boolean] = { + bitcoindCall[Boolean]( + "settxfee", + List(JsNumber(feePerKB.toBigDecimal)), + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def walletLock(): Future[Unit] = { @@ -274,46 +314,57 @@ trait WalletRpc { self: Client => } def walletLock(walletName: String): Future[Unit] = { - bitcoindCall[Unit]("walletlock", - uriExtensionOpt = Some(walletExtension(walletName))) + bitcoindCall[Unit]( + "walletlock", + uriExtensionOpt = Some(walletExtension(walletName)) + ) } def walletPassphrase( passphrase: String, seconds: Int, - walletNameOpt: Option[String] = None): Future[Unit] = { - bitcoindCall[Unit]("walletpassphrase", - List(JsString(passphrase), JsNumber(seconds)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + walletNameOpt: Option[String] = None + ): Future[Unit] = { + bitcoindCall[Unit]( + "walletpassphrase", + List(JsString(passphrase), JsNumber(seconds)), + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def walletPassphraseChange( currentPassphrase: String, newPassphrase: String, - walletNameOpt: Option[String] = None): Future[Unit] = { + walletNameOpt: Option[String] = None + ): Future[Unit] = { bitcoindCall[Unit]( "walletpassphrasechange", List(JsString(currentPassphrase), JsString(newPassphrase)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def signRawTransactionWithWallet( transaction: Transaction, - walletNameOpt: Option[String]): Future[ - SignRawTransactionWithWalletResult] = { + walletNameOpt: Option[String] + ): Future[SignRawTransactionWithWalletResult] = { bitcoindCall[SignRawTransactionWithWalletResult]( "signrawtransactionwithwallet", List(JsString(transaction.hex)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } def signRawTransactionWithWallet( - transaction: Transaction): Future[SignRawTransactionWithWalletResult] = { + transaction: Transaction + ): Future[SignRawTransactionWithWalletResult] = { signRawTransactionWithWallet(transaction, None) } - /** @param blank Not available to versions before v19 - * @param passphrase Not available to versions before v19 + /** @param blank + * Not available to versions before v19 + * @param passphrase + * Not available to versions before v19 * @return */ def createWallet( @@ -322,43 +373,51 @@ trait WalletRpc { self: Client => blank: Boolean = false, passphrase: String = "", avoidReuse: Boolean = false, - descriptors: Boolean = false): Future[CreateWalletResult] = + descriptors: Boolean = false + ): Future[CreateWalletResult] = self.version.flatMap { case V24 | V23 | V22 => bitcoindCall[CreateWalletResult]( "createwallet", - List(JsString(walletName), - JsBoolean(disablePrivateKeys), - JsBoolean(blank), - JsString(passphrase), - JsBoolean(avoidReuse), - JsBoolean(descriptors)) + List( + JsString(walletName), + JsBoolean(disablePrivateKeys), + JsBoolean(blank), + JsString(passphrase), + JsBoolean(avoidReuse), + JsBoolean(descriptors) + ) ) case Unknown => bitcoindCall[CreateWalletResult]( "createwallet", - List(JsString(walletName), - JsBoolean(disablePrivateKeys), - JsBoolean(blank), - JsString(passphrase), - JsBoolean(avoidReuse)) + List( + JsString(walletName), + JsBoolean(disablePrivateKeys), + JsBoolean(blank), + JsString(passphrase), + JsBoolean(avoidReuse) + ) ) } def getAddressInfo( address: BitcoinAddress, - walletNameOpt: Option[String] = None): Future[AddressInfoResult] = { + walletNameOpt: Option[String] = None + ): Future[AddressInfoResult] = { self.version.flatMap { case Unknown => bitcoindCall[AddressInfoResultPostV18]( "getaddressinfo", List(JsString(address.value)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) case V24 | V23 | V22 | Unknown => bitcoindCall[AddressInfoResultPostV21]( "getaddressinfo", List(JsString(address.value)), - uriExtensionOpt = walletNameOpt.map(walletExtension)) + uriExtensionOpt = walletNameOpt.map(walletExtension) + ) } } @@ -367,7 +426,8 @@ trait WalletRpc { self: Client => minconf: Int = 1, comment: String = "", subtractFeeFrom: Vector[BitcoinAddress] = Vector.empty, - walletNameOpt: Option[String] = None): Future[DoubleSha256DigestBE] = { + walletNameOpt: Option[String] = None + ): Future[DoubleSha256DigestBE] = { val jsonOutputs: JsValue = Json.toJson { amounts.map { case (addr, curr) => addr -> Bitcoins(curr.satoshis) @@ -375,11 +435,13 @@ trait WalletRpc { self: Client => } bitcoindCall[DoubleSha256DigestBE]( "sendmany", - List(JsString(""), - jsonOutputs, - JsNumber(minconf), - JsString(comment), - Json.toJson(subtractFeeFrom)), + List( + JsString(""), + jsonOutputs, + JsNumber(minconf), + JsString(comment), + Json.toJson(subtractFeeFrom) + ), uriExtensionOpt = walletNameOpt.map(walletExtension) ) } @@ -390,14 +452,17 @@ trait WalletRpc { self: Client => localComment: String = "", toComment: String = "", subractFeeFromAmount: Boolean = false, - walletNameOpt: Option[String] = None): Future[DoubleSha256DigestBE] = { + walletNameOpt: Option[String] = None + ): Future[DoubleSha256DigestBE] = { bitcoindCall[DoubleSha256DigestBE]( "sendtoaddress", - List(Json.toJson(address), - Json.toJson(Bitcoins(amount.satoshis)), - JsString(localComment), - JsString(toComment), - JsBoolean(subractFeeFromAmount)), + List( + Json.toJson(address), + Json.toJson(Bitcoins(amount.satoshis)), + JsString(localComment), + JsString(toComment), + JsBoolean(subractFeeFromAmount) + ), uriExtensionOpt = walletNameOpt.map(walletExtension) ) } @@ -406,7 +471,8 @@ trait WalletRpc { self: Client => psbt: PSBT, sign: Boolean = true, sigHashType: HashType = HashType.sigHashAll, - walletNameOpt: Option[String] = None): Future[WalletProcessPsbtResult] = { + walletNameOpt: Option[String] = None + ): Future[WalletProcessPsbtResult] = { bitcoindCall[WalletProcessPsbtResult]( "walletprocesspsbt", List(JsString(psbt.base64), JsBoolean(sign), Json.toJson(sigHashType)), @@ -428,34 +494,39 @@ trait WalletRpc { self: Client => } bitcoindCall[WalletCreateFundedPsbtResult]( "walletcreatefundedpsbt", - List(Json.toJson(inputs), - jsonOutputs, - JsNumber(locktime), - Json.toJson(options), - Json.toJson(bip32derivs)), + List( + Json.toJson(inputs), + jsonOutputs, + JsNumber(locktime), + Json.toJson(options), + Json.toJson(bip32derivs) + ), uriExtensionOpt = walletNameOpt.map(walletExtension) ) } /** $signRawTx * - * This RPC call signs the raw transaction with keys found in - * the Bitcoin Core wallet. + * This RPC call signs the raw transaction with keys found in the Bitcoin + * Core wallet. */ def signRawTransactionWithWallet( transaction: Transaction, utxoDeps: Vector[RpcOpts.SignRawTransactionOutputParameter], sigHash: HashType = HashType.sigHashAll ): Future[SignRawTransactionResult] = - bitcoindCall[SignRawTransactionResult]("signrawtransactionwithwallet", - List(JsString(transaction.hex), - Json.toJson(utxoDeps), - Json.toJson(sigHash))) + bitcoindCall[SignRawTransactionResult]( + "signrawtransactionwithwallet", + List( + JsString(transaction.hex), + Json.toJson(utxoDeps), + Json.toJson(sigHash) + ) + ) /** $signRawTx * - * This RPC call signs the raw transaction with keys provided - * manually. + * This RPC call signs the raw transaction with keys provided manually. */ def signRawTransactionWithKey( transaction: Transaction, @@ -464,9 +535,13 @@ trait WalletRpc { self: Client => Vector.empty, sigHash: HashType = HashType.sigHashAll ): Future[SignRawTransactionResult] = - bitcoindCall[SignRawTransactionResult]("signrawtransactionwithkey", - List(JsString(transaction.hex), - Json.toJson(keys), - Json.toJson(utxoDeps), - Json.toJson(sigHash))) + bitcoindCall[SignRawTransactionResult]( + "signrawtransactionwithkey", + List( + JsString(transaction.hex), + Json.toJson(keys), + Json.toJson(utxoDeps), + Json.toJson(sigHash) + ) + ) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v18/V18AssortedRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v18/V18AssortedRpc.scala index 0d726a2293..f5778830b6 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v18/V18AssortedRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v18/V18AssortedRpc.scala @@ -14,22 +14,28 @@ import play.api.libs.json.{JsString, Json} import scala.concurrent.Future /** Assorted Rpc calls for Bitcoin V18 - * @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/network/getnodeaddresses/]] - * @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/wallet/listwalletdir/]] - * @see [[https://github.com/bitcoin/bitcoin/commit/e82f6ad6f270f1f101d8853be32fd11eff4ddfb8]] - * @see [[https://bitcoincore.org/en/doc/0.18.0/rpc/mining/submitheader/]] + * @see + * [[https://bitcoincore.org/en/doc/0.18.0/rpc/network/getnodeaddresses/]] + * @see + * [[https://bitcoincore.org/en/doc/0.18.0/rpc/wallet/listwalletdir/]] + * @see + * [[https://github.com/bitcoin/bitcoin/commit/e82f6ad6f270f1f101d8853be32fd11eff4ddfb8]] + * @see + * [[https://bitcoincore.org/en/doc/0.18.0/rpc/mining/submitheader/]] */ trait V18AssortedRpc { self: Client => private def getNodeAddresses( - count: Option[Int]): Future[Vector[GetNodeAddressesResult]] = { + count: Option[Int] + ): Future[Vector[GetNodeAddressesResult]] = { self.version.flatMap { case BitcoindVersion.V22 | BitcoindVersion.V23 | BitcoindVersion.V24 | BitcoindVersion.Unknown => bitcoindCall[Vector[GetNodeAddressesResultPostV22]]( "getnodeaddresses", - List(Json.toJson(count))) + List(Json.toJson(count)) + ) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v20/V20AssortedRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v20/V20AssortedRpc.scala index c42510b571..95fa205575 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v20/V20AssortedRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v20/V20AssortedRpc.scala @@ -15,16 +15,20 @@ import scala.concurrent.Future trait V20AssortedRpc { self: Client => def dumpTxOutSet(path: Path): Future[DumpTxOutSetResult] = { - bitcoindCall[DumpTxOutSetResult]("dumptxoutset", - List(Json.toJson(path.toString))) + bitcoindCall[DumpTxOutSetResult]( + "dumptxoutset", + List(Json.toJson(path.toString)) + ) } def generateToDescriptor( numBlocks: Int, descriptor: String, - maxTries: Long = 1000000): Future[Vector[DoubleSha256DigestBE]] = { + maxTries: Long = 1000000 + ): Future[Vector[DoubleSha256DigestBE]] = { bitcoindCall[Vector[DoubleSha256DigestBE]]( "generatetodescriptor", - List(JsNumber(numBlocks), JsString(descriptor), JsNumber(maxTries))) + List(JsNumber(numBlocks), JsString(descriptor), JsNumber(maxTries)) + ) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v20/V20MultisigRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v20/V20MultisigRpc.scala index c2f3083ff2..7186d5f226 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v20/V20MultisigRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v20/V20MultisigRpc.scala @@ -12,11 +12,12 @@ import play.api.libs.json.{JsArray, JsNumber, JsString, Json} import scala.concurrent.Future -/** This trait defines RPC calls related to - * multisignature functionality in Bitcoin Core. +/** This trait defines RPC calls related to multisignature functionality in + * Bitcoin Core. * - * @see [[https://en.bitcoin.it/wiki/Multisignature Bitcoin Wiki]] - * article on multisignature. + * @see + * [[https://en.bitcoin.it/wiki/Multisignature Bitcoin Wiki]] article on + * multisignature. */ trait V20MultisigRpc extends MultisigRpc { self: Client => @@ -24,7 +25,8 @@ trait V20MultisigRpc extends MultisigRpc { self: Client => minSignatures: Int, keys: Vector[Either[ECPublicKey, P2PKHAddress]], account: String = "", - addressType: Option[AddressType]): Future[MultiSigResultPostV20] = { + addressType: Option[AddressType] + ): Future[MultiSigResultPostV20] = { def keyToString(key: Either[ECPublicKey, P2PKHAddress]): JsString = key match { case Right(k) => JsString(k.value) @@ -32,9 +34,11 @@ trait V20MultisigRpc extends MultisigRpc { self: Client => } val params = - List(JsNumber(minSignatures), - JsArray(keys.map(keyToString)), - JsString(account)) ++ addressType.map(Json.toJson(_)).toList + List( + JsNumber(minSignatures), + JsArray(keys.map(keyToString)), + JsString(account) + ) ++ addressType.map(Json.toJson(_)).toList self.version.flatMap { case V22 | V23 | V24 | Unknown => bitcoindCall[MultiSigResultPostV20]("addmultisigaddress", params) @@ -43,40 +47,46 @@ trait V20MultisigRpc extends MultisigRpc { self: Client => override def addMultiSigAddress( minSignatures: Int, - keys: Vector[Either[ECPublicKey, P2PKHAddress]]): Future[ - MultiSigResultPostV20] = + keys: Vector[Either[ECPublicKey, P2PKHAddress]] + ): Future[MultiSigResultPostV20] = addMultiSigAddress(minSignatures, keys, addressType = None) override def addMultiSigAddress( minSignatures: Int, keys: Vector[Either[ECPublicKey, P2PKHAddress]], - account: String): Future[MultiSigResultPostV20] = + account: String + ): Future[MultiSigResultPostV20] = addMultiSigAddress(minSignatures, keys, account, None) override def addMultiSigAddress( minSignatures: Int, keys: Vector[Either[ECPublicKey, P2PKHAddress]], - addressType: AddressType): Future[MultiSigResultPostV20] = + addressType: AddressType + ): Future[MultiSigResultPostV20] = addMultiSigAddress(minSignatures, keys, addressType = Some(addressType)) override def addMultiSigAddress( minSignatures: Int, keys: Vector[Either[ECPublicKey, P2PKHAddress]], account: String, - addressType: AddressType): Future[MultiSigResultPostV20] = + addressType: AddressType + ): Future[MultiSigResultPostV20] = addMultiSigAddress(minSignatures, keys, account, Some(addressType)) override def createMultiSig( minSignatures: Int, keys: Vector[ECPublicKey], addressType: AddressType, - walletNameOpt: Option[String] = None): Future[MultiSigResultPostV20] = { + walletNameOpt: Option[String] = None + ): Future[MultiSigResultPostV20] = { self.version.flatMap { case V22 | V23 | V24 | Unknown => bitcoindCall[MultiSigResultPostV20]( "createmultisig", - List(JsNumber(minSignatures), - Json.toJson(keys.map(_.hex)), - Json.toJson(addressType)), + List( + JsNumber(minSignatures), + Json.toJson(keys.map(_.hex)), + Json.toJson(addressType) + ), uriExtensionOpt = walletNameOpt.map(walletExtension) ) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/BitcoindV22RpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/BitcoindV22RpcClient.scala index ae0e393ab0..977b6398c3 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/BitcoindV22RpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/BitcoindV22RpcClient.scala @@ -16,8 +16,8 @@ import scala.util.Try /** Class for creating a BitcoindV22 instance that can access RPCs */ class BitcoindV22RpcClient(override val instance: BitcoindInstance)(implicit - actorSystem: ActorSystem) - extends BitcoindRpcClient(instance) + actorSystem: ActorSystem +) extends BitcoindRpcClient(instance) with DescriptorRpc with PsbtRpc with V20MultisigRpc @@ -34,9 +34,9 @@ object BitcoindV22RpcClient { /** Creates an RPC client from the given instance. * - * Behind the scenes, we create an actor system for - * you. You can use `withActorSystem` if you want to - * manually specify an actor system for the RPC client. + * Behind the scenes, we create an actor system for you. You can use + * `withActorSystem` if you want to manually specify an actor system for the + * RPC client. */ def apply(instance: BitcoindInstance): BitcoindV22RpcClient = { implicit val system: ActorSystem = @@ -44,17 +44,18 @@ object BitcoindV22RpcClient { withActorSystem(instance) } - /** Creates an RPC client from the given instance, - * together with the given actor system. This is for - * advanced users, where you need fine grained control - * over the RPC client. + /** Creates an RPC client from the given instance, together with the given + * actor system. This is for advanced users, where you need fine grained + * control over the RPC client. */ def withActorSystem(instance: BitcoindInstance)(implicit - system: ActorSystem): BitcoindV22RpcClient = + system: ActorSystem + ): BitcoindV22RpcClient = new BitcoindV22RpcClient(instance)(system) def fromUnknownVersion( - rpcClient: BitcoindRpcClient): Try[BitcoindV22RpcClient] = + rpcClient: BitcoindRpcClient + ): Try[BitcoindV22RpcClient] = Try { new BitcoindV22RpcClient(rpcClient.instance)(rpcClient.system) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/TestMempoolAcceptRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/TestMempoolAcceptRpc.scala index 2975ab5d38..aa16ce2f4d 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/TestMempoolAcceptRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/TestMempoolAcceptRpc.scala @@ -15,11 +15,12 @@ trait TestMempoolAcceptRpc { self: Client => def testMempoolAccept( transaction: Vector[Transaction], - maxFeeRate: Double = 0.10): Future[ - Vector[TestMempoolAcceptResultPostV22]] = { + maxFeeRate: Double = 0.10 + ): Future[Vector[TestMempoolAcceptResultPostV22]] = { bitcoindCall[Vector[TestMempoolAcceptResultPostV22]]( "testmempoolaccept", - List(Json.toJson(transaction), Json.toJson(maxFeeRate))) + List(Json.toJson(transaction), Json.toJson(maxFeeRate)) + ) } } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/V22AssortedRpc.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/V22AssortedRpc.scala index e3b694bfdb..0a6aed99c8 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/V22AssortedRpc.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v22/V22AssortedRpc.scala @@ -13,15 +13,18 @@ trait V22AssortedRpc extends V18AssortedRpc with V20AssortedRpc with WalletRpc { self: Client => private def getNodeAddresses( - count: Option[Int]): Future[Vector[GetNodeAddressesResultPostV22]] = { + count: Option[Int] + ): Future[Vector[GetNodeAddressesResultPostV22]] = { bitcoindCall[Vector[GetNodeAddressesResultPostV22]]( "getnodeaddresses", - List(Json.toJson(count))) + List(Json.toJson(count)) + ) } def getNodeAddresses( network: String, - count: Int): Future[Vector[GetNodeAddressesResultPostV22]] = { + count: Int + ): Future[Vector[GetNodeAddressesResultPostV22]] = { bitcoindCall[Vector[GetNodeAddressesResultPostV22]]( "getnodeaddresses", List(Json.toJson(count), Json.toJson(network)) @@ -29,11 +32,12 @@ trait V22AssortedRpc extends V18AssortedRpc with V20AssortedRpc with WalletRpc { } override def getNodeAddresses( - count: Int): Future[Vector[GetNodeAddressesResultPostV22]] = + count: Int + ): Future[Vector[GetNodeAddressesResultPostV22]] = getNodeAddresses(Some(count)) - override def getNodeAddresses(): Future[ - Vector[GetNodeAddressesResultPostV22]] = + override def getNodeAddresses() + : Future[Vector[GetNodeAddressesResultPostV22]] = getNodeAddresses(None) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v23/BitcoindV23RpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v23/BitcoindV23RpcClient.scala index 102d0c3c95..b530fae5c8 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v23/BitcoindV23RpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v23/BitcoindV23RpcClient.scala @@ -10,8 +10,8 @@ import scala.util.Try /** Class for creating a BitcoindV23 instance that can access RPCs */ class BitcoindV23RpcClient(override val instance: BitcoindInstance)(implicit - actorSystem: ActorSystem) - extends BitcoindRpcClient(instance) { + actorSystem: ActorSystem +) extends BitcoindRpcClient(instance) { override lazy val version: Future[BitcoindVersion] = Future.successful(BitcoindVersion.V23) @@ -21,9 +21,9 @@ object BitcoindV23RpcClient { /** Creates an RPC client from the given instance. * - * Behind the scenes, we create an actor system for - * you. You can use `withActorSystem` if you want to - * manually specify an actor system for the RPC client. + * Behind the scenes, we create an actor system for you. You can use + * `withActorSystem` if you want to manually specify an actor system for the + * RPC client. */ def apply(instance: BitcoindInstance): BitcoindV23RpcClient = { implicit val system: ActorSystem = @@ -31,17 +31,18 @@ object BitcoindV23RpcClient { withActorSystem(instance) } - /** Creates an RPC client from the given instance, - * together with the given actor system. This is for - * advanced users, where you need fine grained control - * over the RPC client. + /** Creates an RPC client from the given instance, together with the given + * actor system. This is for advanced users, where you need fine grained + * control over the RPC client. */ def withActorSystem(instance: BitcoindInstance)(implicit - system: ActorSystem): BitcoindV23RpcClient = + system: ActorSystem + ): BitcoindV23RpcClient = new BitcoindV23RpcClient(instance)(system) def fromUnknownVersion( - rpcClient: BitcoindRpcClient): Try[BitcoindV23RpcClient] = + rpcClient: BitcoindRpcClient + ): Try[BitcoindV23RpcClient] = Try { new BitcoindV23RpcClient(rpcClient.instance)(rpcClient.system) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v24/BitcoindV24RpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v24/BitcoindV24RpcClient.scala index 36dc5ff2da..325ae49ae5 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v24/BitcoindV24RpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/v24/BitcoindV24RpcClient.scala @@ -18,42 +18,49 @@ import scala.util.Try /** Class for creating a BitcoindV24 instance that can access RPCs */ class BitcoindV24RpcClient(override val instance: BitcoindInstance)(implicit - actorSystem: ActorSystem) - extends BitcoindRpcClient(instance) { + actorSystem: ActorSystem +) extends BitcoindRpcClient(instance) { override lazy val version: Future[BitcoindVersion] = Future.successful(BitcoindVersion.V24) def getTxSpendingPrevOut( - prevout: TransactionOutPoint): Future[GetTxSpendingPrevOutResult] = { + prevout: TransactionOutPoint + ): Future[GetTxSpendingPrevOutResult] = { getTxSpendingPrevOut(Vector(prevout)).map(_.head) } - def getTxSpendingPrevOut(prevouts: Vector[TransactionOutPoint]): Future[ - Vector[GetTxSpendingPrevOutResult]] = { + def getTxSpendingPrevOut( + prevouts: Vector[TransactionOutPoint] + ): Future[Vector[GetTxSpendingPrevOutResult]] = { val json = JsArray(prevouts.map { prev => Json.obj("txid" -> prev.txIdBE.hex, "vout" -> prev.vout.toLong) }) - bitcoindCall[Vector[GetTxSpendingPrevOutResult]]("gettxspendingprevout", - List(json)) + bitcoindCall[Vector[GetTxSpendingPrevOutResult]]( + "gettxspendingprevout", + List(json) + ) } def simulateRawTransaction( tx: Transaction, - includeWatchOnly: Boolean = true): Future[CurrencyUnit] = { + includeWatchOnly: Boolean = true + ): Future[CurrencyUnit] = { simulateRawTransactions(Vector(tx), includeWatchOnly) } def simulateRawTransactions( txs: Vector[Transaction], - includeWatchOnly: Boolean = true): Future[CurrencyUnit] = { + includeWatchOnly: Boolean = true + ): Future[CurrencyUnit] = { val txsJson = JsArray(txs.map(tx => JsString(tx.hex))) val options = Json.obj("include_watchonly" -> includeWatchOnly) bitcoindCall[SimulateRawTransactionResult]( "simulaterawtransaction", - List(txsJson, options)).map(_.balance_change) + List(txsJson, options) + ).map(_.balance_change) } } @@ -61,9 +68,9 @@ object BitcoindV24RpcClient { /** Creates an RPC client from the given instance. * - * Behind the scenes, we create an actor system for - * you. You can use `withActorSystem` if you want to - * manually specify an actor system for the RPC client. + * Behind the scenes, we create an actor system for you. You can use + * `withActorSystem` if you want to manually specify an actor system for the + * RPC client. */ def apply(instance: BitcoindInstance): BitcoindV24RpcClient = { implicit val system: ActorSystem = @@ -71,17 +78,18 @@ object BitcoindV24RpcClient { withActorSystem(instance) } - /** Creates an RPC client from the given instance, - * together with the given actor system. This is for - * advanced users, where you need fine grained control - * over the RPC client. + /** Creates an RPC client from the given instance, together with the given + * actor system. This is for advanced users, where you need fine grained + * control over the RPC client. */ def withActorSystem(instance: BitcoindInstance)(implicit - system: ActorSystem): BitcoindV24RpcClient = + system: ActorSystem + ): BitcoindV24RpcClient = new BitcoindV24RpcClient(instance)(system) def fromUnknownVersion( - rpcClient: BitcoindRpcClient): Try[BitcoindV24RpcClient] = + rpcClient: BitcoindRpcClient + ): Try[BitcoindV24RpcClient] = Try { new BitcoindV24RpcClient(rpcClient.instance)(rpcClient.system) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindAuthCredentials.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindAuthCredentials.scala index e75af046c9..57e883b925 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindAuthCredentials.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindAuthCredentials.scala @@ -7,8 +7,8 @@ import java.nio.file.{Files, Paths} import org.bitcoins.core.config._ import org.bitcoins.crypto.MaskedToString -/** This trait contains the information we need to authenticate - * to a `bitcoind` node. +/** This trait contains the information we need to authenticate to a `bitcoind` + * node. */ sealed trait BitcoindAuthCredentials { def password: String @@ -19,21 +19,19 @@ sealed trait BitcoindAuthCredentials { object BitcoindAuthCredentials extends BitcoinSLogger { import org.bitcoins.core.compat.JavaConverters._ - /** Authenticate by providing a username and password. - * If you are connecting to a local `bitcoind` you - * should instead use cookie based authentication. - * If you are connecting to a remote `bitcoind`, you - * should use the Bitcoin Core-provided script - * `rpcauth.py` to generate credentials. This will - * give you a `rpcauth=...` string you can put in - * your remote `bitcoind` configuration, as well as - * a set of `rpcuser=...` and `rpcpassword=...` you - * can put in your local `bitcoin.conf` configuration - * file or provide directly to this class. + /** Authenticate by providing a username and password. If you are connecting + * to a local `bitcoind` you should instead use cookie based authentication. + * If you are connecting to a remote `bitcoind`, you should use the Bitcoin + * Core-provided script `rpcauth.py` to generate credentials. This will give + * you a `rpcauth=...` string you can put in your remote `bitcoind` + * configuration, as well as a set of `rpcuser=...` and `rpcpassword=...` you + * can put in your local `bitcoin.conf` configuration file or provide + * directly to this class. * - * @see [[https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth rpcauth.py]], - * canonical Python script provided by Bitcoin Core to generate the - * auth credentials. + * @see + * [[https://github.com/bitcoin/bitcoin/tree/master/share/rpcauth rpcauth.py]], + * canonical Python script provided by Bitcoin Core to generate the auth + * credentials. */ case class PasswordBased( username: String, @@ -46,18 +44,15 @@ object BitcoindAuthCredentials extends BitcoinSLogger { } } - /** Authenticate by providing a cookie file - * found in the `bitcoind` data directory. - * This is the most secure as well as user - * friendly way of authenticating, but it - * is not always suitable for situtations - * where the `bitcoind` instance is on a - * remote server. + /** Authenticate by providing a cookie file found in the `bitcoind` data + * directory. This is the most secure as well as user friendly way of + * authenticating, but it is not always suitable for situtations where the + * `bitcoind` instance is on a remote server. */ case class CookieBased( network: NetworkParameters, - datadir: File = BitcoindConfig.DEFAULT_DATADIR) - extends BitcoindAuthCredentials { + datadir: File = BitcoindConfig.DEFAULT_DATADIR + ) extends BitcoindAuthCredentials { private[bitcoins] lazy val cookiePath = { val middleSegment = network match { @@ -70,8 +65,7 @@ object BitcoindAuthCredentials extends BitcoinSLogger { Paths.get(datadir.toString, middleSegment, ".cookie") } - /** The cookie is a string looking like - * `__cookie__:AUTO_GENERATED_PASSWORD` + /** The cookie is a string looking like `__cookie__:AUTO_GENERATED_PASSWORD` */ def cookie: String = { if (Files.exists(cookiePath)) { diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindConfig.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindConfig.scala index 67c1cb9750..6f74c0d494 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindConfig.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindConfig.scala @@ -9,43 +9,44 @@ import java.net.{InetSocketAddress, URI} import java.nio.file.{Files, Path, Paths} import scala.util.Properties -/** This class represents a parsed `bitcoin.conf` file. It - * respects the different ways of writing options in - * `bitcoin.conf`: Raw options, network-prefixed options - * and options within network sections. It also tries to - * conform to the way Bitcoin Core gives precedence to the - * different properties. +/** This class represents a parsed `bitcoin.conf` file. It respects the + * different ways of writing options in `bitcoin.conf`: Raw options, + * network-prefixed options and options within network sections. It also tries + * to conform to the way Bitcoin Core gives precedence to the different + * properties. * - * Not all options are exposed from this class. We only - * expose those that are of relevance when making RPC - * requests. + * Not all options are exposed from this class. We only expose those that are + * of relevance when making RPC requests. * - * @see https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md + * @see + * https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md */ case class BitcoindConfig( private[bitcoins] val lines: Seq[String], - datadir: File) - extends BitcoinSLogger { + datadir: File +) extends BitcoinSLogger { - //create datadir and config if it DNE on disk + // create datadir and config if it DNE on disk if (!datadir.exists()) { logger.debug( - s"datadir=${datadir.getAbsolutePath} does not exist, creating now") + s"datadir=${datadir.getAbsolutePath} does not exist, creating now" + ) datadir.mkdirs() BitcoindConfig.writeConfigToFile(this, datadir) } private val confFile = datadir.toPath.resolve("bitcoin.conf") - //create bitcoin.conf file in datadir if it does not exist + // create bitcoin.conf file in datadir if it does not exist if (!Files.exists(confFile)) { logger.debug( - s"bitcoin.conf in datadir=${datadir.getAbsolutePath} does not exist, creating now") + s"bitcoin.conf in datadir=${datadir.getAbsolutePath} does not exist, creating now" + ) BitcoindConfig.writeConfigToFile(this, datadir) } - /** Converts the config back to a string that can be written - * to file, and passed to `bitcoind` + /** Converts the config back to a string that can be written to file, and + * passed to `bitcoind` */ lazy val toWriteableString: String = lines.mkString("\n") @@ -81,18 +82,19 @@ case class BitcoindConfig( private lazy val ourNetworkString: String = networkString(network) - /** Splits the provided lines into pairs of keys/values - * based on `=`, and then applies the provided - * `collect` function on those pairs + /** Splits the provided lines into pairs of keys/values based on `=`, and then + * applies the provided `collect` function on those pairs */ - private def collectFrom(lines: Seq[String])( - collect: PartialFunction[(String, String), String]): Seq[String] = { + private def collectFrom( + lines: Seq[String] + )(collect: PartialFunction[(String, String), String]): Seq[String] = { val splittedPairs = { val splitLines = lines.map( _.split("=") .map(_.trim) - .toList) + .toList + ) splitLines.collect { case h :: t :: _ => h -> t @@ -102,11 +104,12 @@ case class BitcoindConfig( splittedPairs.collect(collect) } - /** Applies the given partial function to all key/value pairs - * found in this config + /** Applies the given partial function to all key/value pairs found in this + * config */ - private val collectAllLines: PartialFunction[(String, String), String] => Seq[ - String] = collectFrom(lines)(_) + private val collectAllLines + : PartialFunction[(String, String), String] => Seq[String] = + collectFrom(lines)(_) /** The blockchain network associated with this `bitcoind` config */ lazy val network: NetworkParameters = { @@ -120,15 +123,15 @@ case class BitcoindConfig( (networkOpt, networkStrOpt) match { case (None, Some(badStr)) => logger.warn( - s"'$badStr' is not a valid Bitcoin network! Defaulting to mainnet") + s"'$badStr' is not a valid Bitcoin network! Defaulting to mainnet" + ) case _ => } networkOpt.getOrElse(MainNet) } - /** First searches for option prefixed with network, - * then section with header + /** First searches for option prefixed with network, then section with header * and lastly just raw option */ private[config] def getValue(key: String): Option[String] = @@ -136,9 +139,8 @@ case class BitcoindConfig( .orElse(readSectionHeaderOpt(key)) .orElse(readRawOpt(key)) - /** Searches the config for a key matching the provided - * string that's prefixed by the network we're currently - * on + /** Searches the config for a key matching the provided string that's prefixed + * by the network we're currently on */ private def readPrefixOpt(key: String): Option[String] = { val prefixedOptKey = s"$ourNetworkString.$key" @@ -151,9 +153,8 @@ case class BitcoindConfig( }.headOption } - /** Searches the config for a key matching the provided - * string that's under a section header matching the - * network we're on. + /** Searches the config for a key matching the provided string that's under a + * section header matching the network we're on. */ private def readSectionHeaderOpt(key: String): Option[String] = { val startIndexOpt = lines.indexOf(s"[$ourNetworkString]") match { @@ -189,9 +190,8 @@ case class BitcoindConfig( } yield result } - /** Searches the config for a key matching the provided - * string that's _not_ in a section header or prefixed - * by a network. + /** Searches the config for a key matching the provided string that's _not_ in + * a section header or prefixed by a network. */ private def readRawOpt(key: String): Option[String] = { val linesToSearchIn = lines.takeWhile(!_.startsWith("[")) @@ -252,14 +252,15 @@ case class BitcoindConfig( val lines = newLine +: ourLines val newConfig = BitcoindConfig(lines, datadir) logger.debug( - s"Appending new config with $key=$value to datadir=${datadir.getAbsolutePath}") + s"Appending new config with $key=$value to datadir=${datadir.getAbsolutePath}" + ) BitcoindConfig.writeConfigToFile(newConfig, datadir) newConfig } - /** Creates a new config with the given key and values, - * with the given network prefixed to the key + /** Creates a new config with the given key and values, with the given network + * prefixed to the key * * Old config: * {{{ @@ -276,7 +277,8 @@ case class BitcoindConfig( def withOption( key: String, value: String, - network: NetworkParameters): BitcoindConfig = + network: NetworkParameters + ): BitcoindConfig = withOption(key = s"${networkString(network)}.$key", value = value) def withDatadir(newDatadir: File): BitcoindConfig = { @@ -292,8 +294,8 @@ object BitcoindConfig /** The empty `bitcoind` config */ lazy val empty: BitcoindConfig = BitcoindConfig("", DEFAULT_DATADIR) - /** Constructs a `bitcoind` config from the given string, - * by splitting it on newlines + /** Constructs a `bitcoind` config from the given string, by splitting it on + * newlines */ override def apply(config: String, datadir: File): BitcoindConfig = apply(config.split("\n").toList, datadir) @@ -305,7 +307,8 @@ object BitcoindConfig /** Reads the given file and construct a `bitcoind` config from it */ override def apply( config: File, - datadir: File = DEFAULT_DATADIR): BitcoindConfig = { + datadir: File = DEFAULT_DATADIR + ): BitcoindConfig = { import org.bitcoins.core.compat.JavaConverters._ val lines = Files .readAllLines(config.toPath) @@ -324,9 +327,8 @@ object BitcoindConfig apply(dir.toPath.resolve("bitcoin.conf")) } - /** If there is a `bitcoin.conf` in the default - * data directory, this is read. Otherwise, the - * default configuration is returned. + /** If there is a `bitcoin.conf` in the default data directory, this is read. + * Otherwise, the default configuration is returned. */ override def fromDefaultDatadir: BitcoindConfig = { if (DEFAULT_CONF_FILE.isFile) { @@ -336,21 +338,26 @@ object BitcoindConfig } } - /** @see https://en.bitcoin.it/wiki/Data_directory + /** @see + * https://en.bitcoin.it/wiki/Data_directory */ override val DEFAULT_DATADIR: File = { val path = if (Properties.isMac) { - Paths.get(Properties.userHome, - "Library", - "Application Support", - "Bitcoin") + Paths.get( + Properties.userHome, + "Library", + "Application Support", + "Bitcoin" + ) } else if (Properties.isWin) { - Paths.get("C:", - "Users", - Properties.userName, - "Appdata", - "Roaming", - "Bitcoin") + Paths.get( + "C:", + "Users", + Properties.userName, + "Appdata", + "Roaming", + "Bitcoin" + ) } else { Paths.get(Properties.userHome, ".bitcoin") } @@ -362,12 +369,13 @@ object BitcoindConfig .resolve("bitcoin.conf") .toFile - /** Writes the config to the data directory within it, if it doesn't - * exist. Returns the written file. + /** Writes the config to the data directory within it, if it doesn't exist. + * Returns the written file. */ override def writeConfigToFile( config: BitcoindConfig, - datadir: File): Path = { + datadir: File + ): Path = { val confStr = config.lines.mkString("\n") @@ -376,7 +384,8 @@ object BitcoindConfig if (datadir == DEFAULT_DATADIR && confFile.toFile == DEFAULT_CONF_FILE) { logger.warn( - s"We will not overwrite the existing bitcoin.conf in default datadir") + s"We will not overwrite the existing bitcoin.conf in default datadir" + ) } else { Files.write(confFile, confStr.getBytes) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala index 3d6631f489..05ef56be51 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindInstance.scala @@ -38,11 +38,15 @@ sealed trait BitcoindInstanceLocal extends BitcoindInstance { def datadir: File // would like to check .canExecute as well, but we've run into issues on some machines - require(binary.isFile, - s"bitcoind binary path (${binary.getAbsolutePath}) must be a file") + require( + binary.isFile, + s"bitcoind binary path (${binary.getAbsolutePath}) must be a file" + ) - require(binary.exists, - s"bitcoind binary path (${binary.getAbsolutePath}) does not exist!") + require( + binary.exists, + s"bitcoind binary path (${binary.getAbsolutePath}) does not exist!" + ) def getVersion: BitcoindVersion = { @@ -66,7 +70,8 @@ sealed trait BitcoindInstanceLocal extends BitcoindInstance { BitcoindVersion.V24 case _: String => logger.warn( - s"Unsupported Bitcoin Core version: $foundVersion. The latest supported version is ${BitcoindVersion.newest}") + s"Unsupported Bitcoin Core version: $foundVersion. The latest supported version is ${BitcoindVersion.newest}" + ) BitcoindVersion.newest } } @@ -111,13 +116,15 @@ object BitcoindInstanceLocal }, datadir: File = BitcoindConfig.DEFAULT_DATADIR )(implicit system: ActorSystem): BitcoindInstanceLocal = { - BitcoindInstanceLocalImpl(network, - uri, - rpcUri, - authCredentials, - zmqConfig = zmqConfig, - binary = binary, - datadir = datadir) + BitcoindInstanceLocalImpl( + network, + uri, + rpcUri, + authCredentials, + zmqConfig = zmqConfig, + binary = binary, + datadir = datadir + ) } lazy val DEFAULT_BITCOIND_LOCATION: Option[File] = { @@ -146,7 +153,8 @@ object BitcoindInstanceLocal /** Constructs a `bitcoind` instance from the given datadir, using the * `bitcoin.conf` found within (if any) * - * @throws IllegalArgumentException if the given datadir does not exist + * @throws IllegalArgumentException + * if the given datadir does not exist */ def fromDatadir( datadir: File = BitcoindConfig.DEFAULT_DATADIR, @@ -168,8 +176,9 @@ object BitcoindInstanceLocal } } - def fromDataDir(dir: File)(implicit - system: ActorSystem): BitcoindInstanceLocal = { + def fromDataDir( + dir: File + )(implicit system: ActorSystem): BitcoindInstanceLocal = { fromDatadir( dir, DEFAULT_BITCOIND_LOCATION match { @@ -182,7 +191,8 @@ object BitcoindInstanceLocal /** Construct a `bitcoind` from the given config file. If no `datadir` setting * is found, the parent directory to the given file is used. * - * @throws IllegalArgumentException if the given config file does not exist + * @throws IllegalArgumentException + * if the given config file does not exist */ def fromConfFile( file: File = BitcoindConfig.DEFAULT_CONF_FILE, @@ -199,8 +209,9 @@ object BitcoindInstanceLocal fromConfig(conf, binary) } - def fromConfigFile(file: File)(implicit - system: ActorSystem): BitcoindInstanceLocal = { + def fromConfigFile( + file: File + )(implicit system: ActorSystem): BitcoindInstanceLocal = { fromConfFile( file, DEFAULT_BITCOIND_LOCATION match { @@ -220,13 +231,15 @@ object BitcoindInstanceLocal )(implicit system: ActorSystem): BitcoindInstanceLocal = { val authCredentials = BitcoindAuthCredentials.fromConfig(config) - BitcoindInstanceLocalImpl(config.network, - config.uri, - config.rpcUri, - authCredentials, - zmqConfig = ZmqConfig.fromConfig(config), - binary = binary, - datadir = config.datadir) + BitcoindInstanceLocalImpl( + config.network, + config.uri, + config.rpcUri, + authCredentials, + zmqConfig = ZmqConfig.fromConfig(config), + binary = binary, + datadir = config.datadir + ) } override val DEFAULT_DATADIR: Path = BitcoindConfig.DEFAULT_DATADIR.toPath @@ -255,12 +268,14 @@ object BitcoindInstanceRemote zmqConfig: ZmqConfig = ZmqConfig(), proxyParams: Option[Socks5ProxyParams] = None )(implicit system: ActorSystem): BitcoindInstanceRemote = { - BitcoindInstanceRemoteImpl(network, - uri, - rpcUri, - authCredentials, - zmqConfig = zmqConfig, - proxyParams = proxyParams) + BitcoindInstanceRemoteImpl( + network, + uri, + rpcUri, + authCredentials, + zmqConfig = zmqConfig, + proxyParams = proxyParams + ) } def fromConfFile( @@ -273,8 +288,9 @@ object BitcoindInstanceRemote fromConfig(conf) } - override def fromConfigFile(file: File)(implicit - system: ActorSystem): BitcoindInstanceRemote = { + override def fromConfigFile( + file: File + )(implicit system: ActorSystem): BitcoindInstanceRemote = { fromConfFile( file ) @@ -284,16 +300,19 @@ object BitcoindInstanceRemote config: BitcoindRpcAppConfig )(implicit system: ActorSystem): BitcoindInstanceRemote = { - BitcoindInstanceRemoteImpl(config.network, - config.uri, - config.rpcUri, - config.authCredentials, - zmqConfig = config.zmqConfig, - proxyParams = None) + BitcoindInstanceRemoteImpl( + config.network, + config.uri, + config.rpcUri, + config.authCredentials, + zmqConfig = config.zmqConfig, + proxyParams = None + ) } - override def fromDataDir(dir: File)(implicit - system: ActorSystem): BitcoindInstanceRemote = { + override def fromDataDir( + dir: File + )(implicit system: ActorSystem): BitcoindInstanceRemote = { require(dir.exists, s"${dir.getPath} does not exist!") require(dir.isDirectory, s"${dir.getPath} is not a directory!") val conf = BitcoindRpcAppConfig(dir.toPath, Vector.empty) diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala index 99cc9560bd..4803fe31df 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala @@ -17,12 +17,15 @@ import scala.concurrent.duration.DurationInt import scala.concurrent.{Future, Promise} /** Configuration for a BitcoindRpcClient - * @param directory The data directory of the Bitcoin-S instance - * @param confs Optional sequence of configuration overrides + * @param directory + * The data directory of the Bitcoin-S instance + * @param confs + * Optional sequence of configuration overrides */ case class BitcoindRpcAppConfig( baseDatadir: Path, - configOverrides: Vector[Config])(implicit val system: ActorSystem) + configOverrides: Vector[Config] +)(implicit val system: ActorSystem) extends AppConfig { import system.dispatcher @@ -33,7 +36,8 @@ case class BitcoindRpcAppConfig( override protected[bitcoins] type ConfigType = BitcoindRpcAppConfig override protected[bitcoins] def newConfigOfType( - configs: Vector[Config]): BitcoindRpcAppConfig = + configs: Vector[Config] + ): BitcoindRpcAppConfig = BitcoindRpcAppConfig(baseDatadir, configs) override def start(): Future[Unit] = Future.unit @@ -47,8 +51,11 @@ case class BitcoindRpcAppConfig( config.getStringOrNone("bitcoin-s.bitcoind-rpc.binary").map(new File(_)) lazy val bitcoindDataDir = new File( - config.getStringOrElse("bitcoin-s.bitcoind-rpc.datadir", - BitcoindConfig.DEFAULT_DATADIR.toString)) + config.getStringOrElse( + "bitcoin-s.bitcoind-rpc.datadir", + BitcoindConfig.DEFAULT_DATADIR.toString + ) + ) lazy val host = new URI({ val baseUrl = { @@ -157,15 +164,18 @@ case class BitcoindRpcAppConfig( ) case None => - BitcoindInstanceRemote(network = network, - uri = uri, - rpcUri = rpcUri, - authCredentials = authCredentials, - zmqConfig = zmqConfig, - proxyParams = socks5ProxyParams) + BitcoindInstanceRemote( + network = network, + uri = uri, + rpcUri = rpcUri, + authCredentials = authCredentials, + zmqConfig = zmqConfig, + proxyParams = socks5ProxyParams + ) } - /** Creates a bitcoind rpc client based on the [[bitcoindInstance]] configured */ + /** Creates a bitcoind rpc client based on the [[bitcoindInstance]] configured + */ lazy val clientF: Future[BitcoindRpcClient] = { bitcoindInstance match { case local: BitcoindInstanceLocal => @@ -173,16 +183,16 @@ case class BitcoindRpcAppConfig( val client = BitcoindRpcClient.fromVersion(version, bitcoindInstance) Future.successful(client) case _: BitcoindInstanceRemote => - //first get a generic rpc client so we can retrieve - //the proper version of the remote running bitcoind + // first get a generic rpc client so we can retrieve + // the proper version of the remote running bitcoind val noVersionRpc = new BitcoindRpcClient(bitcoindInstance) val versionF = getBitcoindVersion(noVersionRpc) - //if we don't retrieve the proper version, we can - //end up with exceptions on an rpc client that actually supports - //specific features that are not supported across all versions of bitcoind - //such as blockfilters - //see: https://github.com/bitcoin-s/bitcoin-s/issues/3695#issuecomment-929492945 + // if we don't retrieve the proper version, we can + // end up with exceptions on an rpc client that actually supports + // specific features that are not supported across all versions of bitcoind + // such as blockfilters + // see: https://github.com/bitcoin-s/bitcoin-s/issues/3695#issuecomment-929492945 versionF.map { version => BitcoindRpcClient.fromVersion(version, instance = bitcoindInstance) } @@ -190,10 +200,11 @@ case class BitcoindRpcAppConfig( } private def getBitcoindVersion( - client: BitcoindRpcClient): Future[BitcoindVersion] = { + client: BitcoindRpcClient + ): Future[BitcoindVersion] = { val promise = Promise[BitcoindVersion]() val interval = 1.second - val maxTries = 300 //5 minutes + val maxTries = 300 // 5 minutes for { _ <- AsyncUtil.retryUntilSatisfiedF( conditionF = { () => @@ -223,12 +234,13 @@ object BitcoindRpcAppConfig override val moduleName: String = "bitcoind" - /** Constructs a node configuration from the default Bitcoin-S - * data directory and given list of configuration overrides. + /** Constructs a node configuration from the default Bitcoin-S data directory + * and given list of configuration overrides. */ override def fromDatadir(datadir: Path, confs: Vector[Config])(implicit - system: ActorSystem): BitcoindRpcAppConfig = + system: ActorSystem + ): BitcoindRpcAppConfig = BitcoindRpcAppConfig(datadir, confs) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/ZmqConfig.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/ZmqConfig.scala index efce4039bc..b2db8e13db 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/ZmqConfig.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/ZmqConfig.scala @@ -28,26 +28,31 @@ object ZmqConfig extends BitcoinSLogger { hashTx: Option[InetSocketAddress] = None, rawTx: Option[InetSocketAddress] = None ): ZmqConfig = - ZmqConfigImpl(hashBlock = hashBlock, - rawBlock = rawBlock, - hashTx = hashTx, - rawTx = rawTx) + ZmqConfigImpl( + hashBlock = hashBlock, + rawBlock = rawBlock, + hashTx = hashTx, + rawTx = rawTx + ) - /** Creates a `ZmqConfig` with all `URI`s set to - * `localhost` and the same port + /** Creates a `ZmqConfig` with all `URI`s set to `localhost` and the same port */ def fromPort(port: Int): ZmqConfig = { val uri = new InetSocketAddress("tcp://127.0.0.1", port) - ZmqConfig(hashBlock = Some(uri), - rawBlock = Some(uri), - hashTx = Some(uri), - rawTx = Some(uri)) + ZmqConfig( + hashBlock = Some(uri), + rawBlock = Some(uri), + hashTx = Some(uri), + rawTx = Some(uri) + ) } def fromConfig(config: BitcoindConfig): ZmqConfig = - ZmqConfig(hashBlock = config.zmqpubhashblock, - hashTx = config.zmqpubhashtx, - rawBlock = config.zmqpubrawblock, - rawTx = config.zmqpubrawtx) + ZmqConfig( + hashBlock = config.zmqpubhashblock, + hashTx = config.zmqpubhashtx, + rawBlock = config.zmqpubrawblock, + rawTx = config.zmqpubrawtx + ) } diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/AppConfigFactoryActorSystem.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/AppConfigFactoryActorSystem.scala index e120a269ee..852a7c1573 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/AppConfigFactoryActorSystem.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/AppConfigFactoryActorSystem.scala @@ -3,6 +3,7 @@ package org.bitcoins.rpc.util import org.apache.pekko.actor.ActorSystem import org.bitcoins.commons.config.{AppConfig, AppConfigFactoryBase} -/** An AppConfigFactory that has implicit actor systems passed into the datadir */ +/** An AppConfigFactory that has implicit actor systems passed into the datadir + */ trait AppConfigFactoryActorSystem[C <: AppConfig] extends AppConfigFactoryBase[C, ActorSystem] diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/BitcoindStreamUtil.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/BitcoindStreamUtil.scala index 38ce1fa0af..0f3a21fa00 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/BitcoindStreamUtil.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/BitcoindStreamUtil.scala @@ -11,13 +11,15 @@ import scala.concurrent.ExecutionContext object BitcoindStreamUtil { - /** Creates a flow that you can feed block hashes too and the block header and block will get emitted downstream */ + /** Creates a flow that you can feed block hashes too and the block header and + * block will get emitted downstream + */ def fetchBlocksBitcoind( bitcoindRpcClient: BitcoindRpcClient, - parallelism: Int)(implicit ec: ExecutionContext): Flow[ - DoubleSha256DigestBE, - (Block, GetBlockHeaderResult), - NotUsed] = { + parallelism: Int + )(implicit + ec: ExecutionContext + ): Flow[DoubleSha256DigestBE, (Block, GetBlockHeaderResult), NotUsed] = { Flow[DoubleSha256DigestBE].mapAsync(parallelism = parallelism) { hash => val blockF = bitcoindRpcClient.getBlockRaw(hash) val blockHeaderResultF = bitcoindRpcClient.getBlockHeader(hash) diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/RpcUtil.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/RpcUtil.scala index 35f0f7b154..5da21b081e 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/RpcUtil.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/util/RpcUtil.scala @@ -14,7 +14,8 @@ abstract class RpcUtil extends AsyncUtil { def awaitServerShutdown( server: BitcoindRpcClient, duration: FiniteDuration = 300.milliseconds, - maxTries: Int = 50)(implicit ec: ExecutionContext): Future[Unit] = { + maxTries: Int = 50 + )(implicit ec: ExecutionContext): Future[Unit] = { retryUntilSatisfiedF(() => server.isStoppedF, duration, maxTries) } diff --git a/chain-test/src/test/scala/org/bitcoins/chain/ChainCallbacksTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/ChainCallbacksTest.scala index 5773413d36..40b2509164 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/ChainCallbacksTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/ChainCallbacksTest.scala @@ -65,11 +65,13 @@ class ChainCallbacksTest extends ChainDbUnitTest { val nextCompactFilterHeaderDb = CompactFilterHeaderDb( hashBE = DoubleSha256DigestBE.fromHex( - "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), + "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" + ), previousFilterHeaderBE = ChainTestUtil.genesisFilterHeaderDb.hashBE, height = 1, filterHashBE = DoubleSha256DigestBE.fromHex( - "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f"), + "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f" + ), blockHashBE = newValidHeader.hashBE ) @@ -77,7 +79,8 @@ class ChainCallbacksTest extends ChainDbUnitTest { _ <- chainHandler.processHeader(newValidHeader.blockHeader) _ <- chainHandler.processFilterHeader( nextCompactFilterHeaderDb.filterHeader, - nextCompactFilterHeaderDb.blockHashBE) + nextCompactFilterHeaderDb.blockHashBE + ) result <- resultP.future } yield assert(result) } @@ -106,7 +109,8 @@ class ChainCallbacksTest extends ChainDbUnitTest { val nextCompactFilterHeaderDb = CompactFilterHeaderDb( hashBE = DoubleSha256DigestBE.fromHex( - "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), + "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" + ), previousFilterHeaderBE = ChainTestUtil.genesisFilterHeaderDb.hashBE, height = 1, filterHashBE = hashBE.flip, @@ -122,13 +126,16 @@ class ChainCallbacksTest extends ChainDbUnitTest { ) val filterMessage = - CompactFilterMessage(nextCompactFilter.blockHashBE.flip, - nextCompactFilter.golombFilter) + CompactFilterMessage( + nextCompactFilter.blockHashBE.flip, + nextCompactFilter.golombFilter + ) for { _ <- chainHandler.processHeader(newValidHeader.blockHeader) _ <- chainHandler.processFilterHeader( nextCompactFilterHeaderDb.filterHeader, - nextCompactFilterHeaderDb.blockHashBE) + nextCompactFilterHeaderDb.blockHashBE + ) _ <- chainHandler.processFilter(filterMessage) result <- resultP.future } yield assert(result) diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BitcoindChainHandlerViaZmqTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BitcoindChainHandlerViaZmqTest.scala index a54c4b8fe5..98159752a3 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BitcoindChainHandlerViaZmqTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BitcoindChainHandlerViaZmqTest.scala @@ -32,13 +32,14 @@ class BitcoindChainHandlerViaZmqTest extends ChainDbUnitTest { address <- bitcoind.getNewAddress hash +: _ <- bitcoind.generateToAddress(1, address) _ <- { - //test case is totally async since we - //can't monitor processing flow for zmq - //so we just need to await until we - //have fully processed the header + // test case is totally async since we + // can't monitor processing flow for zmq + // so we just need to await until we + // have fully processed the header AsyncUtil.awaitConditionF( () => chainHandler.getHeader(hash).map(_.isDefined), - interval = 250.millis) + interval = 250.millis + ) } header <- chainHandler.getHeader(hash) } yield assert(header.get.hashBE == hash) diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BlockchainTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BlockchainTest.scala index 70b6349693..ebf84769ae 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BlockchainTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/BlockchainTest.scala @@ -53,18 +53,20 @@ class BlockchainTest extends ChainUnitTest { case ChainFixture.Empty => val accum = new mutable.ArrayBuffer[BlockHeaderDb](5) accum.+=(ChainTestUtil.genesisHeaderDb) - //generate 4 headers + // generate 4 headers 0.until(4).foreach { _ => val newHeader = BlockHeaderHelper.buildNextHeader(accum.last) accum.+=(newHeader) } - //now given the last header, and the other headers we should reconstruct the blockchain + // now given the last header, and the other headers we should reconstruct the blockchain val headers = accum.dropRight(1).toVector val tip = accum.last - val reconstructed = Blockchain.reconstructFromHeaders(childHeader = tip, - ancestors = headers) + val reconstructed = Blockchain.reconstructFromHeaders( + childHeader = tip, + ancestors = headers + ) assert(reconstructed.length == 1) val chain = reconstructed.head @@ -82,8 +84,10 @@ class BlockchainTest extends ChainUnitTest { val thirdHeader = BlockHeaderHelper.buildNextHeader(missingHeader) val reconstructed = - Blockchain.reconstructFromHeaders(thirdHeader, - Vector(ChainTestUtil.genesisHeaderDb)) + Blockchain.reconstructFromHeaders( + thirdHeader, + Vector(ChainTestUtil.genesisHeaderDb) + ) assert(reconstructed.isEmpty) } @@ -95,10 +99,12 @@ class BlockchainTest extends ChainUnitTest { val chain = Blockchain(Vector(second, genesis)) assertThrows[IllegalArgumentException] { - BlockchainUpdate.Failed(chain, - Vector(genesis), - second.blockHeader, - TipUpdateResult.BadNonce(second.blockHeader)) + BlockchainUpdate.Failed( + chain, + Vector(genesis), + second.blockHeader, + TipUpdateResult.BadNonce(second.blockHeader) + ) } } diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerCachedTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerCachedTest.scala index 4cc2746951..a44edc9b2f 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerCachedTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerCachedTest.scala @@ -48,11 +48,11 @@ class ChainHandlerCachedTest extends ChainDbUnitTest { chainHandler.chainConfig.chain.genesisBlock.blockHeader val assert1F = for { rangeOpt <- - chainHandler.nextBlockHeaderBatchRange(prevStopHash = - DoubleSha256DigestBE.empty, - stopHash = - genesisHeader.hashBE, - batchSize = 1) + chainHandler.nextBlockHeaderBatchRange( + prevStopHash = DoubleSha256DigestBE.empty, + stopHash = genesisHeader.hashBE, + batchSize = 1 + ) } yield { val marker = rangeOpt.get assert(rangeOpt.nonEmpty) @@ -60,12 +60,13 @@ class ChainHandlerCachedTest extends ChainDbUnitTest { assert(marker.stopBlockHash == genesisHeader.hash) } - //let's process a block header, and then be able to fetch that header as the last stopHash + // let's process a block header, and then be able to fetch that header as the last stopHash val blockHeaderDb = { - BlockHeaderDbHelper.fromBlockHeader(height = 0, - chainWork = - Pow.getBlockProof(genesisHeader), - bh = genesisHeader) + BlockHeaderDbHelper.fromBlockHeader( + height = 0, + chainWork = Pow.getBlockProof(genesisHeader), + bh = genesisHeader + ) } val blockHeader = BlockHeaderHelper.buildNextHeader(blockHeaderDb) @@ -76,10 +77,11 @@ class ChainHandlerCachedTest extends ChainDbUnitTest { for { chainApi <- chainApi2 rangeOpt <- - chainApi.nextBlockHeaderBatchRange(prevStopHash = - DoubleSha256DigestBE.empty, - stopHash = blockHeader.hashBE, - batchSize = 2) + chainApi.nextBlockHeaderBatchRange( + prevStopHash = DoubleSha256DigestBE.empty, + stopHash = blockHeader.hashBE, + batchSize = 2 + ) } yield { val marker = rangeOpt.get assert(rangeOpt.nonEmpty) @@ -96,8 +98,8 @@ class ChainHandlerCachedTest extends ChainDbUnitTest { val newHeaderCF = reorgFixtureF.map(_.headerDb2) val batchSize = 100 - //two competing headers B,C built off of A - //so just pick the first headerB to be our next block header batch + // two competing headers B,C built off of A + // so just pick the first headerB to be our next block header batch val assert0F = for { chainHandler <- chainHandlerF newHeaderB <- newHeaderBF @@ -105,18 +107,21 @@ class ChainHandlerCachedTest extends ChainDbUnitTest { blockHeaderBatchOpt <- chainHandler.nextBlockHeaderBatchRange( prevStopHash = ChainTestUtil.regTestGenesisHeaderDb.hashBE, stopHash = newHeaderB.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get - ChainHandlerTest.checkReorgHeaders(header1 = newHeaderB, - header2 = newHeaderC, - bestHash = marker.stopBlockHash.flip) + ChainHandlerTest.checkReorgHeaders( + header1 = newHeaderB, + header2 = newHeaderC, + bestHash = marker.stopBlockHash.flip + ) assert(newHeaderB.height == marker.startHeight) } - //two competing headers B,C built off of A - //pick headerC to be our next block header batch + // two competing headers B,C built off of A + // pick headerC to be our next block header batch val assert1F = for { _ <- assert0F chainHandler <- chainHandlerF @@ -125,19 +130,22 @@ class ChainHandlerCachedTest extends ChainDbUnitTest { blockHeaderBatchOpt <- chainHandler.nextBlockHeaderBatchRange( prevStopHash = ChainTestUtil.regTestGenesisHeaderDb.hashBE, stopHash = newHeaderC.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get - ChainHandlerTest.checkReorgHeaders(header1 = newHeaderB, - header2 = newHeaderC, - bestHash = marker.stopBlockHash.flip) + ChainHandlerTest.checkReorgHeaders( + header1 = newHeaderB, + header2 = newHeaderC, + bestHash = marker.stopBlockHash.flip + ) assert(newHeaderC.height == marker.startHeight) } - //now let's build a new block header ontop of C and process it - //when we call chainHandler.nextBlockHeaderBatchRange it - //should be C's hash instead of B's hash + // now let's build a new block header ontop of C and process it + // when we call chainHandler.nextBlockHeaderBatchRange it + // should be C's hash instead of B's hash for { _ <- assert1F chainHandler <- chainHandlerF @@ -147,7 +155,8 @@ class ChainHandlerCachedTest extends ChainDbUnitTest { blockHeaderBatchOpt <- chainApiD.nextBlockHeaderBatchRange( prevStopHash = ChainTestUtil.regTestGenesisHeaderDb.hashBE, stopHash = headerD.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) count <- chainApiD.getBlockCount() } yield { assert(count == 2) @@ -164,9 +173,11 @@ class ChainHandlerCachedTest extends ChainDbUnitTest { val assert1F = for { bestBlockHash <- chainHandler.getBestBlockHash() rangeOpt <- - chainHandler.nextBlockHeaderBatchRange(prevStopHash = bestBlockHash, - stopHash = bestBlockHash, - batchSize = 1) + chainHandler.nextBlockHeaderBatchRange( + prevStopHash = bestBlockHash, + stopHash = bestBlockHash, + batchSize = 1 + ) } yield { assert(rangeOpt.isEmpty) } diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerTest.scala index 7a3f8f53df..95cd74b40e 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/ChainHandlerTest.scala @@ -58,11 +58,13 @@ class ChainHandlerTest extends ChainDbUnitTest { ) private def insertGenesisFilterHeaderAndFilter( - chainHandler: ChainHandler): Future[Unit] = { + chainHandler: ChainHandler + ): Future[Unit] = { for { _ <- chainHandler.processFilterHeader( ChainTestUtil.genesisFilterHeaderDb.filterHeader, - ChainTestUtil.genesisHeaderDb.hashBE) + ChainTestUtil.genesisHeaderDb.hashBE + ) _ <- chainHandler.processFilter(ChainTestUtil.genesisFilterMessage) } yield () } @@ -136,9 +138,11 @@ class ChainHandlerTest extends ChainDbUnitTest { bestHash <- chainHandler.getBestBlockHash() newHeaderC <- newHeaderCF } yield { - ChainHandlerTest.checkReorgHeaders(header1 = newHeaderB, - header2 = newHeaderC, - bestHash = bestHash) + ChainHandlerTest.checkReorgHeaders( + header1 = newHeaderB, + header2 = newHeaderC, + bestHash = bestHash + ) } // build a new header D off of C which was seen later @@ -198,22 +202,23 @@ class ChainHandlerTest extends ChainDbUnitTest { val newHeaderBF = reorgFixtureF.map(_.headerDb1) val newHeaderCF = reorgFixtureF.map(_.headerDb2) - //we are going to generate two new blocks on chain C + // we are going to generate two new blocks on chain C val chainHandlerEWithHeaderF: Future[(ChainApi, BlockHeaderDb)] = for { newHeaderC <- newHeaderCF chainHandler <- chainHandlerCF headerD = BlockHeaderHelper.buildNextHeader(newHeaderC) headerE = BlockHeaderHelper.buildNextHeader(headerD) chainHandlerE <- chainHandler.processHeaders( - Vector(headerD.blockHeader, headerE.blockHeader)) + Vector(headerD.blockHeader, headerE.blockHeader) + ) } yield (chainHandlerE, headerE) val chainHandlerEF = chainHandlerEWithHeaderF.map(_._1) val headerEF = chainHandlerEWithHeaderF.map(_._2) - //now we are going to attempt to generate a block on top of B - //we should _not_ reorg to a new best tip after adding block F ontop of B - //the best hash should still be header E's best hash. + // now we are going to attempt to generate a block on top of B + // we should _not_ reorg to a new best tip after adding block F ontop of B + // the best hash should still be header E's best hash. val chainHandlerFF = for { chainHandler <- chainHandlerEF @@ -240,9 +245,11 @@ class ChainHandlerTest extends ChainDbUnitTest { assert(initFhCount == 0) assert(genesisFilterHeader.size == 1) assert( - genesisFilterHeader.contains(ChainTestUtil.genesisFilterHeaderDb)) + genesisFilterHeader.contains(ChainTestUtil.genesisFilterHeaderDb) + ) assert( - genesisFilterHeader.head.filterHeader == ChainTestUtil.genesisFilterHeaderDb.filterHeader) + genesisFilterHeader.head.filterHeader == ChainTestUtil.genesisFilterHeaderDb.filterHeader + ) assert(count == 0) } } @@ -254,10 +261,12 @@ class ChainHandlerTest extends ChainDbUnitTest { val firstFilterHeader = FilterHeader( filterHash = DoubleSha256Digest.fromBytes(ECPrivateKey.freshPrivateKey.bytes), - prevHeaderHash = DoubleSha256Digest.empty) + prevHeaderHash = DoubleSha256Digest.empty + ) val newChainHandlerF = chainHandler.processFilterHeader( firstFilterHeader, - DoubleSha256DigestBE.fromBytes(ECPrivateKey.freshPrivateKey.bytes)) + DoubleSha256DigestBE.fromBytes(ECPrivateKey.freshPrivateKey.bytes) + ) recoverToSucceededIf[UnknownBlockHash](newChainHandlerF) } } @@ -267,13 +276,16 @@ class ChainHandlerTest extends ChainDbUnitTest { ChainTestUtil.genesisFilterHeaderDb, CompactFilterHeaderDb( hashBE = DoubleSha256DigestBE.fromHex( - "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), + "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" + ), previousFilterHeaderBE = ChainTestUtil.genesisFilterHeaderDb.hashBE, height = 1, filterHashBE = DoubleSha256DigestBE.fromHex( - "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f"), + "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f" + ), blockHashBE = DoubleSha256DigestBE.fromHex( - "aaa1a2a3a4a5a6a7a8a9aaabacadaeafaaa1a2a3a4a5a6a7a8a9aaabacadaeaf") + "aaa1a2a3a4a5a6a7a8a9aaabacadaeafaaa1a2a3a4a5a6a7a8a9aaabacadaeaf" + ) ) ) @@ -292,14 +304,18 @@ class ChainHandlerTest extends ChainDbUnitTest { ChainTestUtil.genesisFilterHeaderDb, CompactFilterHeaderDb( hashBE = DoubleSha256DigestBE.fromHex( - "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), + "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" + ), previousFilterHeaderBE = DoubleSha256DigestBE.fromHex( - "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), + "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" + ), height = 1, filterHashBE = DoubleSha256DigestBE.fromHex( - "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f"), + "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f" + ), blockHashBE = DoubleSha256DigestBE.fromHex( - "aaa1a2a3a4a5a6a7a8a9aaabacadaeafaaa1a2a3a4a5a6a7a8a9aaabacadaeaf") + "aaa1a2a3a4a5a6a7a8a9aaabacadaeafaaa1a2a3a4a5a6a7a8a9aaabacadaeaf" + ) ) ) @@ -307,27 +323,35 @@ class ChainHandlerTest extends ChainDbUnitTest { ChainTestUtil.genesisFilterHeaderDb, CompactFilterHeaderDb( hashBE = DoubleSha256DigestBE.fromHex( - "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), + "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f" + ), previousFilterHeaderBE = DoubleSha256DigestBE.fromHex( - "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f"), + "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f" + ), height = 1, filterHashBE = DoubleSha256DigestBE.fromHex( - "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f"), + "555152535455565758595a5b5c5d5e5f555152535455565758595a5b5c5d5e5f" + ), blockHashBE = DoubleSha256DigestBE.fromHex( - "aaa1a2a3a4a5a6a7a8a9aaabacadaeafaaa1a2a3a4a5a6a7a8a9aaabacadaeaf") + "aaa1a2a3a4a5a6a7a8a9aaabacadaeafaaa1a2a3a4a5a6a7a8a9aaabacadaeaf" + ) ) ) for { _ <- chainHandler.verifyFilterHeaders(goodBatch) _ <- recoverToSucceededIf[IllegalArgumentException]( - chainHandler.verifyFilterHeaders(invalidGenesisFilterHeaderBatch)) + chainHandler.verifyFilterHeaders(invalidGenesisFilterHeaderBatch) + ) _ <- recoverToSucceededIf[IllegalArgumentException]( - chainHandler.verifyFilterHeaders(invalidFilterHeaderBatch)) + chainHandler.verifyFilterHeaders(invalidFilterHeaderBatch) + ) _ <- recoverToSucceededIf[IllegalArgumentException]( - chainHandler.verifyFilterHeaders(selfReferenceFilterHeaderBatch)) + chainHandler.verifyFilterHeaders(selfReferenceFilterHeaderBatch) + ) _ <- recoverToSucceededIf[IllegalArgumentException]( - chainHandler.verifyFilterHeaders(unknownFilterHeaderBatch)) + chainHandler.verifyFilterHeaders(unknownFilterHeaderBatch) + ) } yield succeed } @@ -343,7 +367,8 @@ class ChainHandlerTest extends ChainDbUnitTest { assert(count1 == 0) assert(genesisFilter.contains(ChainTestUtil.genesisFilterDb)) assert( - genesisFilter.head.golombFilter == ChainTestUtil.genesisFilterDb.golombFilter) + genesisFilter.head.golombFilter == ChainTestUtil.genesisFilterDb.golombFilter + ) } } } @@ -355,12 +380,15 @@ class ChainHandlerTest extends ChainDbUnitTest { _ <- chainHandler.processHeader(nextBlockHeader) blockHashBE <- chainHandler.getHeadersAtHeight(1).map(_.head.hashBE) golombFilter = BlockFilter.fromHex("017fa880", blockHashBE.flip) - firstFilter = CompactFilterMessage(blockHash = blockHashBE.flip, - filter = golombFilter) + firstFilter = CompactFilterMessage( + blockHash = blockHashBE.flip, + filter = golombFilter + ) firstFilterHeader = FilterHeader( filterHash = DoubleSha256Digest.fromBytes(ECPrivateKey.freshPrivateKey.bytes), - prevHeaderHash = ChainTestUtil.genesisFilterHeaderDb.hashBE.flip) + prevHeaderHash = ChainTestUtil.genesisFilterHeaderDb.hashBE.flip + ) newChainHandler <- chainHandler.processFilterHeader(firstFilterHeader, blockHashBE) process <- newChainHandler.processFilter(firstFilter) @@ -377,9 +405,10 @@ class ChainHandlerTest extends ChainDbUnitTest { val blockHashBE = DoubleSha256DigestBE.fromBytes(ECPrivateKey.freshPrivateKey.bytes) val golombFilter = BlockFilter.fromHex("017fa880", blockHashBE.flip) - val firstFilterHeader = FilterHeader(filterHash = golombFilter.hash, - prevHeaderHash = - DoubleSha256Digest.empty) + val firstFilterHeader = FilterHeader( + filterHash = golombFilter.hash, + prevHeaderHash = DoubleSha256Digest.empty + ) val unknownBlockF = for { realBlockHashBE <- chainHandler @@ -406,7 +435,8 @@ class ChainHandlerTest extends ChainDbUnitTest { assert( newChainHandler .asInstanceOf[ChainHandler] - .blockFilterCheckpoints == Map(realBlockHashBE -> filterHashBE)) + .blockFilterCheckpoints == Map(realBlockHashBE -> filterHashBE) + ) } } @@ -416,11 +446,11 @@ class ChainHandlerTest extends ChainDbUnitTest { chainHandler.chainConfig.chain.genesisBlock.blockHeader val assert1F = for { rangeOpt <- - chainHandler.nextBlockHeaderBatchRange(prevStopHash = - DoubleSha256DigestBE.empty, - stopHash = - genesisHeader.hashBE, - batchSize = 1) + chainHandler.nextBlockHeaderBatchRange( + prevStopHash = DoubleSha256DigestBE.empty, + stopHash = genesisHeader.hashBE, + batchSize = 1 + ) } yield { assert(rangeOpt.nonEmpty) val marker = rangeOpt.get @@ -428,12 +458,13 @@ class ChainHandlerTest extends ChainDbUnitTest { assert(marker.stopBlockHash == genesisHeader.hash) } - //let's process a block header, and then be able to fetch that header as the last stopHash + // let's process a block header, and then be able to fetch that header as the last stopHash val blockHeaderDb = { - BlockHeaderDbHelper.fromBlockHeader(height = 0, - chainWork = - Pow.getBlockProof(genesisHeader), - bh = genesisHeader) + BlockHeaderDbHelper.fromBlockHeader( + height = 0, + chainWork = Pow.getBlockProof(genesisHeader), + bh = genesisHeader + ) } val blockHeader = BlockHeaderHelper.buildNextHeader(blockHeaderDb) @@ -444,9 +475,11 @@ class ChainHandlerTest extends ChainDbUnitTest { for { chainApi <- chainApi2 rangeOpt <- - chainApi.nextBlockHeaderBatchRange(DoubleSha256DigestBE.empty, - stopHash = blockHeader.hashBE, - batchSize = 2) + chainApi.nextBlockHeaderBatchRange( + DoubleSha256DigestBE.empty, + stopHash = blockHeader.hashBE, + batchSize = 2 + ) } yield { val marker = rangeOpt.get assert(rangeOpt.nonEmpty) @@ -463,8 +496,8 @@ class ChainHandlerTest extends ChainDbUnitTest { val newHeaderCF = reorgFixtureF.map(_.headerDb2) val batchSize = 100 - //two competing headers B,C built off of A - //first specify header B to be syncing filter headers from + // two competing headers B,C built off of A + // first specify header B to be syncing filter headers from val assert0F = for { chainHandler <- chainHandlerF newHeaderB <- newHeaderBF @@ -472,19 +505,22 @@ class ChainHandlerTest extends ChainDbUnitTest { blockHeaderBatchOpt <- chainHandler.nextBlockHeaderBatchRange( prevStopHash = ChainTestUtil.regTestGenesisHeaderDb.hashBE, stopHash = newHeaderB.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get - ChainHandlerTest.checkReorgHeaders(header1 = newHeaderB, - header2 = newHeaderC, - bestHash = marker.stopBlockHash.flip) + ChainHandlerTest.checkReorgHeaders( + header1 = newHeaderB, + header2 = newHeaderC, + bestHash = marker.stopBlockHash.flip + ) assert(newHeaderB.height == marker.startHeight) assert(newHeaderB.hashBE == marker.stopBlockHash.flip) } - //two competing headers B,C built off of A - //first specify header C to be syncing filter headers from + // two competing headers B,C built off of A + // first specify header C to be syncing filter headers from val assert1F = for { _ <- assert0F chainHandler <- chainHandlerF @@ -493,20 +529,23 @@ class ChainHandlerTest extends ChainDbUnitTest { blockHeaderBatchOpt <- chainHandler.nextBlockHeaderBatchRange( prevStopHash = ChainTestUtil.regTestGenesisHeaderDb.hashBE, stopHash = newHeaderC.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get - ChainHandlerTest.checkReorgHeaders(header1 = newHeaderB, - header2 = newHeaderC, - bestHash = marker.stopBlockHash.flip) + ChainHandlerTest.checkReorgHeaders( + header1 = newHeaderB, + header2 = newHeaderC, + bestHash = marker.stopBlockHash.flip + ) assert(newHeaderC.height == marker.startHeight) assert(newHeaderC.hashBE == marker.stopBlockHash.flip) } - //now let's build a new block header ontop of C and process it - //when we call chainHandler.nextBlockHeaderBatchRange it - //should be C's hash instead of B's hash + // now let's build a new block header ontop of C and process it + // when we call chainHandler.nextBlockHeaderBatchRange it + // should be C's hash instead of B's hash for { _ <- assert1F chainHandler <- chainHandlerF @@ -516,7 +555,8 @@ class ChainHandlerTest extends ChainDbUnitTest { blockHeaderBatchOpt <- chainApiD.nextBlockHeaderBatchRange( prevStopHash = ChainTestUtil.regTestGenesisHeaderDb.hashBE, stopHash = headerD.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) count <- chainApiD.getBlockCount() } yield { assert(count == 2) @@ -533,9 +573,11 @@ class ChainHandlerTest extends ChainDbUnitTest { val assert1F = for { bestBlockHash <- chainHandler.getBestBlockHash() rangeOpt <- - chainHandler.nextBlockHeaderBatchRange(prevStopHash = bestBlockHash, - stopHash = bestBlockHash, - batchSize = 1) + chainHandler.nextBlockHeaderBatchRange( + prevStopHash = bestBlockHash, + stopHash = bestBlockHash, + batchSize = 1 + ) } yield { assert(rangeOpt.isEmpty, s"rangeOpt=$rangeOpt") } @@ -549,8 +591,8 @@ class ChainHandlerTest extends ChainDbUnitTest { val newHeaderBF = reorgFixtureF.map(_.headerDb1) val newHeaderCF = reorgFixtureF.map(_.headerDb2) - //two competing headers B,C built off of A - //first specify header C to be syncing filter headers from + // two competing headers B,C built off of A + // first specify header C to be syncing filter headers from val assert1F = for { chainHandler <- chainHandlerF newHeaderB <- newHeaderBF @@ -558,21 +600,24 @@ class ChainHandlerTest extends ChainDbUnitTest { blockHeaderBatchOpt <- chainHandler.nextBlockHeaderBatchRange( prevStopHash = ChainTestUtil.regTestGenesisHeaderDb.hashBE, stopHash = newHeaderC.hashBE, - batchSize = 1) + batchSize = 1 + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get - ChainHandlerTest.checkReorgHeaders(header1 = newHeaderB, - header2 = newHeaderC, - bestHash = marker.stopBlockHash.flip) + ChainHandlerTest.checkReorgHeaders( + header1 = newHeaderB, + header2 = newHeaderC, + bestHash = marker.stopBlockHash.flip + ) assert(marker.startHeight == 1) assert(newHeaderC.hashBE == marker.stopBlockHash.flip) } val headerDF = newHeaderCF.map(BlockHeaderHelper.buildNextHeader) - //now let's build a new block header ontop of C and process it - //when we call chainHandler.nextBlockHeaderBatchRange it - //should be C's hash instead of D's hash due to batchSize + // now let's build a new block header ontop of C and process it + // when we call chainHandler.nextBlockHeaderBatchRange it + // should be C's hash instead of D's hash due to batchSize val assert2F = for { _ <- assert1F chainHandler <- chainHandlerF @@ -582,7 +627,8 @@ class ChainHandlerTest extends ChainDbUnitTest { blockHeaderBatchOpt <- chainApiD.nextBlockHeaderBatchRange( prevStopHash = ChainTestUtil.regTestGenesisHeaderDb.hashBE, stopHash = headerD.hashBE, - batchSize = 1) + batchSize = 1 + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get @@ -597,7 +643,8 @@ class ChainHandlerTest extends ChainDbUnitTest { blockHeaderBatchOpt <- chainHandler.nextBlockHeaderBatchRange( prevStopHash = ChainTestUtil.regTestGenesisHeaderDb.hashBE, stopHash = headerD.hashBE, - batchSize = 2) + batchSize = 2 + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get @@ -605,17 +652,19 @@ class ChainHandlerTest extends ChainDbUnitTest { assert(headerD.hashBE == marker.stopBlockHash.flip) } - //must return None in the case of reorg scenario between prevStopHash / stopHash + // must return None in the case of reorg scenario between prevStopHash / stopHash for { _ <- assert3F chainHandler <- chainHandlerF headerB <- newHeaderBF headerD <- headerDF - //note headerB and headerD are not part of the same chain as D is built ontop of C + // note headerB and headerD are not part of the same chain as D is built ontop of C blockHeaderBatchOpt <- - chainHandler.nextBlockHeaderBatchRange(prevStopHash = headerB.hashBE, - stopHash = headerD.hashBE, - batchSize = 1) + chainHandler.nextBlockHeaderBatchRange( + prevStopHash = headerB.hashBE, + stopHash = headerD.hashBE, + batchSize = 1 + ) } yield { assert(blockHeaderBatchOpt.isEmpty) } @@ -623,9 +672,9 @@ class ChainHandlerTest extends ChainDbUnitTest { it must "generate the next range of block headers correctly if its outside of our in memory blockchain" in { chainHandler => - //need to generate a bunch of block headers first + // need to generate a bunch of block headers first val target = - 2500 //our limit for in memory blockchains is 2016 headers currently (difficulty interval) + 2500 // our limit for in memory blockchains is 2016 headers currently (difficulty interval) val buildF = ChainUnitTest.buildNHeaders(chainHandler, target) val chainParams = chainHandler.chainConfig.network.chainParams val batchSize = 2000 @@ -640,7 +689,8 @@ class ChainHandlerTest extends ChainDbUnitTest { range <- chainHandler.nextBlockHeaderBatchRange( prevStopHash = prevStopHash, stopHash = stopBlockHeaderDb.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) } yield { assert(range.nonEmpty) assert(range.get.startHeight == startHeight) @@ -656,27 +706,30 @@ class ChainHandlerTest extends ChainDbUnitTest { val newHeaderCF = reorgFixtureF.map(_.headerDb2) val batchSize = 100 - //two competing headers B,C built off of A - //first specify header B to be syncing filter headers from + // two competing headers B,C built off of A + // first specify header B to be syncing filter headers from val assert0F = for { chainHandler <- chainHandlerF newHeaderB <- newHeaderBF newHeaderC <- newHeaderCF blockHeaderBatchOpt <- chainHandler.nextFilterHeaderBatchRange( stopBlockHash = newHeaderB.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get - ChainHandlerTest.checkReorgHeaders(header1 = newHeaderB, - header2 = newHeaderC, - bestHash = marker.stopBlockHash.flip) + ChainHandlerTest.checkReorgHeaders( + header1 = newHeaderB, + header2 = newHeaderC, + bestHash = marker.stopBlockHash.flip + ) assert(marker.startHeight == 0) assert(marker.stopBlockHash.flip == newHeaderB.hashBE) } - //two competing headers B,C built off of A - //first specify header C to be syncing filter headers from + // two competing headers B,C built off of A + // first specify header C to be syncing filter headers from val assert1F = for { _ <- assert0F chainHandler <- chainHandlerF @@ -684,20 +737,23 @@ class ChainHandlerTest extends ChainDbUnitTest { newHeaderC <- newHeaderCF blockHeaderBatchOpt <- chainHandler.nextFilterHeaderBatchRange( stopBlockHash = newHeaderC.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get - ChainHandlerTest.checkReorgHeaders(header1 = newHeaderB, - header2 = newHeaderC, - bestHash = marker.stopBlockHash.flip) + ChainHandlerTest.checkReorgHeaders( + header1 = newHeaderB, + header2 = newHeaderC, + bestHash = marker.stopBlockHash.flip + ) assert(marker.startHeight == 0) assert(marker.stopBlockHash.flip == newHeaderC.hashBE) } - //now let's build a new block header ontop of C and process it - //when we call chainHandler.nextFilterHeaderBatchRange it - //should be C's hash instead of B's hash + // now let's build a new block header ontop of C and process it + // when we call chainHandler.nextFilterHeaderBatchRange it + // should be C's hash instead of B's hash for { _ <- assert1F chainHandler <- chainHandlerF @@ -706,7 +762,8 @@ class ChainHandlerTest extends ChainDbUnitTest { chainApiD <- chainHandler.processHeader(headerD.blockHeader) blockHeaderBatchOpt <- chainApiD.nextFilterHeaderBatchRange( stopBlockHash = headerD.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) count <- chainApiD.getBlockCount() } yield { assert(count == 2) @@ -724,9 +781,10 @@ class ChainHandlerTest extends ChainDbUnitTest { chainHandler.chainConfig.chain.genesisBlock.blockHeader val assert1F = for { rangeOpt <- - chainHandler.nextFilterHeaderBatchRange(stopBlockHash = - genesisHeader.hashBE, - 1) + chainHandler.nextFilterHeaderBatchRange( + stopBlockHash = genesisHeader.hashBE, + 1 + ) } yield { assert(rangeOpt.nonEmpty) val marker = rangeOpt.get @@ -734,12 +792,13 @@ class ChainHandlerTest extends ChainDbUnitTest { assert(marker.stopBlockHash == genesisHeader.hash) } - //let's process a block header, and then be able to fetch that header as the last stopHash + // let's process a block header, and then be able to fetch that header as the last stopHash val blockHeaderDb = { - BlockHeaderDbHelper.fromBlockHeader(height = 0, - chainWork = - Pow.getBlockProof(genesisHeader), - bh = genesisHeader) + BlockHeaderDbHelper.fromBlockHeader( + height = 0, + chainWork = Pow.getBlockProof(genesisHeader), + bh = genesisHeader + ) } val blockHeader = BlockHeaderHelper.buildNextHeader(blockHeaderDb) @@ -750,9 +809,10 @@ class ChainHandlerTest extends ChainDbUnitTest { for { chainApi <- chainApi2 rangeOpt <- - chainApi.nextFilterHeaderBatchRange(stopBlockHash = - blockHeader.hashBE, - batchSize = 2) + chainApi.nextFilterHeaderBatchRange( + stopBlockHash = blockHeader.hashBE, + batchSize = 2 + ) } yield { val marker = rangeOpt.get assert(rangeOpt.nonEmpty) @@ -768,21 +828,24 @@ class ChainHandlerTest extends ChainDbUnitTest { val newHeaderBF = reorgFixtureF.map(_.headerDb1) val newHeaderCF = reorgFixtureF.map(_.headerDb2) - //two competing headers B,C built off of A - //first specify header C to be syncing filter headers from + // two competing headers B,C built off of A + // first specify header C to be syncing filter headers from val assert1F = for { chainHandler <- chainHandlerF newHeaderB <- newHeaderBF newHeaderC <- newHeaderCF blockHeaderBatchOpt <- chainHandler.nextFilterHeaderBatchRange( stopBlockHash = newHeaderC.hashBE, - batchSize = 2) + batchSize = 2 + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get - ChainHandlerTest.checkReorgHeaders(header1 = newHeaderB, - header2 = newHeaderC, - bestHash = marker.stopBlockHash.flip) + ChainHandlerTest.checkReorgHeaders( + header1 = newHeaderB, + header2 = newHeaderC, + bestHash = marker.stopBlockHash.flip + ) assert(marker.startHeight == 0) assert(newHeaderC.hashBE == marker.stopBlockHash.flip) } @@ -790,9 +853,9 @@ class ChainHandlerTest extends ChainDbUnitTest { val headerDF = { newHeaderCF.map(headerC => BlockHeaderHelper.buildNextHeader(headerC)) } - //now let's build a new block header ontop of C and process it - //when we call chainHandler.nextFilterHeaderBatchRange with batchSize=3 - //should get D's hash back as the stop hash + // now let's build a new block header ontop of C and process it + // when we call chainHandler.nextFilterHeaderBatchRange with batchSize=3 + // should get D's hash back as the stop hash val assert3F = for { _ <- assert1F chainHandler <- chainHandlerF @@ -800,7 +863,8 @@ class ChainHandlerTest extends ChainDbUnitTest { chainApiD <- chainHandler.processHeader(headerD.blockHeader) blockHeaderBatchOpt <- chainApiD.nextFilterHeaderBatchRange( stopBlockHash = headerD.hashBE, - batchSize = 3) + batchSize = 3 + ) } yield { assert(blockHeaderBatchOpt.isDefined) val marker = blockHeaderBatchOpt.get @@ -819,11 +883,11 @@ class ChainHandlerTest extends ChainDbUnitTest { val assert1F = for { chainHandler <- chainHandlerF newHeaderC <- newHeaderCF - rangeOpt <- chainHandler.nextFilterHeaderBatchRange(stopBlockHash = - newHeaderC.hashBE, - batchSize = 2, - startHeightOpt = - Some(0)) + rangeOpt <- chainHandler.nextFilterHeaderBatchRange( + stopBlockHash = newHeaderC.hashBE, + batchSize = 2, + startHeightOpt = Some(0) + ) } yield { assert(rangeOpt.nonEmpty, s"rangeOpt=$rangeOpt") val range = rangeOpt.get @@ -835,9 +899,9 @@ class ChainHandlerTest extends ChainDbUnitTest { it must "generate the next range of filters correctly if its outside of our in memory blockchain" in { chainHandler => - //need to generate a bunch of block headers first + // need to generate a bunch of block headers first val target = - 2500 //our limit for in memory blockchains is 2016 headers currently (difficulty interval) + 2500 // our limit for in memory blockchains is 2016 headers currently (difficulty interval) val buildF = ChainUnitTest.buildNHeaders(chainHandler, target) val batchSize = 2000 val startHeight = 0 @@ -849,7 +913,8 @@ class ChainHandlerTest extends ChainDbUnitTest { .map(_.head.hashBE) range <- chainHandler.nextFilterHeaderBatchRange( stopBlockHash = stopBlockHeaderDb.hashBE, - batchSize = batchSize) + batchSize = batchSize + ) } yield { assert(range.nonEmpty) assert(range.get.startHeight == startHeight) @@ -968,9 +1033,11 @@ class ChainHandlerTest extends ChainDbUnitTest { filters <- chainHandler.getFiltersBetweenHeights(0, 1) } yield { val genesis = ChainTestUtil.genesisFilterDb - val genesisFilterResponse = FilterResponse(genesis.golombFilter, - genesis.blockHashBE, - genesis.height) + val genesisFilterResponse = FilterResponse( + genesis.golombFilter, + genesis.blockHashBE, + genesis.height + ) assert(filters == Vector(genesisFilterResponse)) } @@ -1080,19 +1147,20 @@ class ChainHandlerTest extends ChainDbUnitTest { object ChainHandlerTest { /** Checks that - * 1. The header1 & header2 have the same chainwork - * 2. Checks that header1 and header2 have the same time - * 3. Checks bestHash is one of header1.hashBE or header2.hashBE + * 1. The header1 & header2 have the same chainwork 2. Checks that header1 + * and header2 have the same time 3. Checks bestHash is one of + * header1.hashBE or header2.hashBE */ def checkReorgHeaders( header1: BlockHeaderDb, header2: BlockHeaderDb, - bestHash: DoubleSha256DigestBE): Assertion = { + bestHash: DoubleSha256DigestBE + ): Assertion = { Assertions.assert(header1.chainWork == header2.chainWork) Assertions.assert(header1.time == header2.time) - //if both chainwork and time are the same, we are left to - //how the database serves up the data - //just make sure it is one of the two headers + // if both chainwork and time are the same, we are left to + // how the database serves up the data + // just make sure it is one of the two headers Assertions.assert(Vector(header1.hashBE, header2.hashBE).contains(bestHash)) } } diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/MainnetChainHandlerTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/MainnetChainHandlerTest.scala index 6ee6ae6c4d..79034ac35a 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/MainnetChainHandlerTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/MainnetChainHandlerTest.scala @@ -42,28 +42,36 @@ class MainnetChainHandlerTest extends ChainDbUnitTest { chainHandler: ChainHandlerCached => val blockHeaders = headersResult.drop( - ChainUnitTest.FIRST_POW_CHANGE - ChainUnitTest.FIRST_BLOCK_HEIGHT) + ChainUnitTest.FIRST_POW_CHANGE - ChainUnitTest.FIRST_BLOCK_HEIGHT + ) val firstBlockHeaderDb = BlockHeaderDbHelper.fromBlockHeader( ChainUnitTest.FIRST_POW_CHANGE - 2, Pow.getBlockProof(ChainTestUtil.blockHeader562462), - ChainTestUtil.blockHeader562462) + ChainTestUtil.blockHeader562462 + ) val secondBlockHeaderDb = { val chainWork = firstBlockHeaderDb.chainWork + Pow.getBlockProof( - ChainTestUtil.blockHeader562463) - BlockHeaderDbHelper.fromBlockHeader(ChainUnitTest.FIRST_POW_CHANGE - 1, - chainWork, - ChainTestUtil.blockHeader562463) + ChainTestUtil.blockHeader562463 + ) + BlockHeaderDbHelper.fromBlockHeader( + ChainUnitTest.FIRST_POW_CHANGE - 1, + chainWork, + ChainTestUtil.blockHeader562463 + ) } val thirdBlockHeaderDb = { val chainWork = secondBlockHeaderDb.chainWork + Pow.getBlockProof( - ChainTestUtil.blockHeader562464) - BlockHeaderDbHelper.fromBlockHeader(ChainUnitTest.FIRST_POW_CHANGE, - chainWork, - ChainTestUtil.blockHeader562464) + ChainTestUtil.blockHeader562464 + ) + BlockHeaderDbHelper.fromBlockHeader( + ChainUnitTest.FIRST_POW_CHANGE, + chainWork, + ChainTestUtil.blockHeader562464 + ) } /* @@ -83,7 +91,8 @@ class MainnetChainHandlerTest extends ChainDbUnitTest { // Takes way too long to do all blocks val blockHeadersToTest = blockHeaders.tail .take( - (2 * chainHandler.chainConfig.chain.difficultyChangeInterval + 1)) + (2 * chainHandler.chainConfig.chain.difficultyChangeInterval + 1) + ) val processedF = handler.processHeaders(blockHeadersToTest) @@ -97,19 +106,25 @@ class MainnetChainHandlerTest extends ChainDbUnitTest { it must "have getBestBlockHash return the header with the most work, not the highest" in { tempHandler: ChainHandlerCached => val dummyHeader = - BlockHeaderDbHelper.fromBlockHeader(1, - BigInt(0), - ChainTestUtil.blockHeader562462) + BlockHeaderDbHelper.fromBlockHeader( + 1, + BigInt(0), + ChainTestUtil.blockHeader562462 + ) val highestHeader = - BlockHeaderDbHelper.fromBlockHeader(2, - BigInt(0), - ChainTestUtil.blockHeader562463) + BlockHeaderDbHelper.fromBlockHeader( + 2, + BigInt(0), + ChainTestUtil.blockHeader562463 + ) val headerWithMostWork = - BlockHeaderDbHelper.fromBlockHeader(1, - BigInt(1000), - ChainTestUtil.blockHeader562464) + BlockHeaderDbHelper.fromBlockHeader( + 1, + BigInt(1000), + ChainTestUtil.blockHeader562464 + ) val tallestBlockchain = Blockchain(Vector(highestHeader, dummyHeader, genesis)) @@ -129,22 +144,29 @@ class MainnetChainHandlerTest extends ChainDbUnitTest { chainHandler: ChainHandlerCached => val blockHeaders = headersResult.drop( - ChainUnitTest.FIRST_POW_CHANGE - ChainUnitTest.FIRST_BLOCK_HEIGHT) + ChainUnitTest.FIRST_POW_CHANGE - ChainUnitTest.FIRST_BLOCK_HEIGHT + ) val firstBlockHeaderDb = - BlockHeaderDbHelper.fromBlockHeader(ChainUnitTest.FIRST_POW_CHANGE - 2, - BigInt(0), - ChainTestUtil.blockHeader562462) + BlockHeaderDbHelper.fromBlockHeader( + ChainUnitTest.FIRST_POW_CHANGE - 2, + BigInt(0), + ChainTestUtil.blockHeader562462 + ) val secondBlockHeaderDb = - BlockHeaderDbHelper.fromBlockHeader(ChainUnitTest.FIRST_POW_CHANGE - 1, - BigInt(0), - ChainTestUtil.blockHeader562463) + BlockHeaderDbHelper.fromBlockHeader( + ChainUnitTest.FIRST_POW_CHANGE - 1, + BigInt(0), + ChainTestUtil.blockHeader562463 + ) val thirdBlockHeaderDb = - BlockHeaderDbHelper.fromBlockHeader(ChainUnitTest.FIRST_POW_CHANGE, - BigInt(0), - ChainTestUtil.blockHeader562464) + BlockHeaderDbHelper.fromBlockHeader( + ChainUnitTest.FIRST_POW_CHANGE, + BigInt(0), + ChainTestUtil.blockHeader562464 + ) /* * We need to insert one block before the first POW check because it is used on the next @@ -158,36 +180,41 @@ class MainnetChainHandlerTest extends ChainDbUnitTest { createdF.flatMap { _ => val blockchain = Blockchain.fromHeaders(firstThreeBlocks.reverse) - val handler = ChainHandlerCached(chainHandler.blockHeaderDAO, - chainHandler.filterHeaderDAO, - chainHandler.filterDAO, - chainHandler.stateDAO, - Vector(blockchain), - Map.empty) + val handler = ChainHandlerCached( + chainHandler.blockHeaderDAO, + chainHandler.filterHeaderDAO, + chainHandler.filterDAO, + chainHandler.stateDAO, + Vector(blockchain), + Map.empty + ) val processorF = Future.successful(handler) // Takes way too long to do all blocks val blockHeadersToTest = blockHeaders.tail .take( - (2 * chainHandler.chainConfig.chain.difficultyChangeInterval + 1).toInt) + (2 * chainHandler.chainConfig.chain.difficultyChangeInterval + 1).toInt + ) - processHeaders(processorF = processorF, - headers = blockHeadersToTest, - height = ChainUnitTest.FIRST_POW_CHANGE + 1) + processHeaders( + processorF = processorF, + headers = blockHeadersToTest, + height = ChainUnitTest.FIRST_POW_CHANGE + 1 + ) } } it must "properly recalculate chain work" in { tempHandler: ChainHandlerCached => val headersWithNoWork = Vector( - BlockHeaderDbHelper.fromBlockHeader(3, - BigInt(0), - ChainTestUtil.blockHeader562464), - BlockHeaderDbHelper.fromBlockHeader(2, - BigInt(0), - ChainTestUtil.blockHeader562463), - BlockHeaderDbHelper.fromBlockHeader(1, - BigInt(0), - ChainTestUtil.blockHeader562462) + BlockHeaderDbHelper + .fromBlockHeader(3, BigInt(0), ChainTestUtil.blockHeader562464), + BlockHeaderDbHelper + .fromBlockHeader(2, BigInt(0), ChainTestUtil.blockHeader562463), + BlockHeaderDbHelper.fromBlockHeader( + 1, + BigInt(0), + ChainTestUtil.blockHeader562462 + ) ) val noWorkGenesis = genesis.copy(chainWork = BigInt(0)) @@ -212,7 +239,8 @@ class MainnetChainHandlerTest extends ChainDbUnitTest { val grouped = blockchains.head.groupBy(_.hashBE) assert( grouped - .forall(_._2.size == 1)) + .forall(_._2.size == 1) + ) assert(headerDb.hashBE == headersWithNoWork.head.hashBE) assert(headerDb.chainWork == BigInt(12885098501L)) } diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/sync/ChainSyncTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/sync/ChainSyncTest.scala index 1915e2c7c9..8202a94ddc 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/sync/ChainSyncTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/sync/ChainSyncTest.scala @@ -19,18 +19,20 @@ class ChainSyncTest extends ChainWithBitcoindNewestCachedUnitTest { bitcoindWithChainHandler: BitcoindBaseVersionChainHandlerViaRpc => val bitcoind = bitcoindWithChainHandler.bitcoindRpc val chainHandler = bitcoindWithChainHandler.chainHandler - //first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions + // first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions val getBestBlockHashFunc = SyncUtil.getBestBlockHashFunc(bitcoind) val getBlockHeaderFunc = SyncUtil.getBlockHeaderFunc(bitcoind) - //let's generate a block on bitcoind + // let's generate a block on bitcoind val block1F = bitcoind.generate(1) val newChainHandlerF: Future[ChainApi] = block1F.flatMap { _ => - ChainSync.sync(chainHandler = chainHandler, - getBlockHeaderFunc = getBlockHeaderFunc, - getBestBlockHashFunc = getBestBlockHashFunc) + ChainSync.sync( + chainHandler = chainHandler, + getBlockHeaderFunc = getBlockHeaderFunc, + getBestBlockHashFunc = getBestBlockHashFunc + ) } for { @@ -46,7 +48,7 @@ class ChainSyncTest extends ChainWithBitcoindNewestCachedUnitTest { bitcoindWithChainHandler: BitcoindBaseVersionChainHandlerViaRpc => val bitcoind = bitcoindWithChainHandler.bitcoindRpc val chainHandler = bitcoindWithChainHandler.chainHandler - //first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions + // first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions val getBestBlockHashFunc = { () => bitcoind.getBestBlockHash() } @@ -55,19 +57,22 @@ class ChainSyncTest extends ChainWithBitcoindNewestCachedUnitTest { bitcoind.getBlockHeader(hash).map(_.blockHeader) } - //note we are not generating a block on bitcoind + // note we are not generating a block on bitcoind val newChainHandlerF: Future[ChainApi] = - ChainSync.sync(chainHandler = chainHandler, - getBlockHeaderFunc = getBlockHeaderFunc, - getBestBlockHashFunc = getBestBlockHashFunc) + ChainSync.sync( + chainHandler = chainHandler, + getBlockHeaderFunc = getBlockHeaderFunc, + getBestBlockHashFunc = getBestBlockHashFunc + ) val newChainHandler2F = for { newChainHandler <- newChainHandlerF - //sync it again to make sure we don't fail + // sync it again to make sure we don't fail newChainHandler2 <- ChainSync.sync( chainHandler = newChainHandler.asInstanceOf[ChainHandler], getBlockHeaderFunc = getBlockHeaderFunc, - getBestBlockHashFunc = getBestBlockHashFunc) + getBestBlockHashFunc = getBestBlockHashFunc + ) bitcoinSCount <- newChainHandler2.getBlockCount() bitcoindCount <- bitcoind.getBlockCount() } yield assert(bitcoinSCount == bitcoindCount) @@ -79,7 +84,7 @@ class ChainSyncTest extends ChainWithBitcoindNewestCachedUnitTest { bitcoindWithChainHandler => val bitcoind = bitcoindWithChainHandler.bitcoindRpc val chainHandler = bitcoindWithChainHandler.chainHandler - //first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions + // first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions val getBestBlockHashFunc = SyncUtil.getBestBlockHashFunc(bitcoind) val getBlockHeaderFunc = SyncUtil.getBlockHeaderFunc(bitcoind) @@ -90,9 +95,11 @@ class ChainSyncTest extends ChainWithBitcoindNewestCachedUnitTest { } yield hashes val sync1F: Future[ChainApi] = generate1F.flatMap { _ => - ChainSync.sync(chainHandler = chainHandler, - getBlockHeaderFunc = getBlockHeaderFunc, - getBestBlockHashFunc = getBestBlockHashFunc) + ChainSync.sync( + chainHandler = chainHandler, + getBlockHeaderFunc = getBlockHeaderFunc, + getBestBlockHashFunc = getBestBlockHashFunc + ) } val assertion1F = for { @@ -107,15 +114,16 @@ class ChainSyncTest extends ChainWithBitcoindNewestCachedUnitTest { assert(bestHash == bitcoindBestBlockHash) } - //let's call sync again and make sure nothing bad happens + // let's call sync again and make sure nothing bad happens val sync2F = for { _ <- assertion1F chainApiSync1 <- sync1F chainApiSync2 <- - ChainSync.sync(chainHandler = - chainApiSync1.asInstanceOf[ChainHandler], - getBlockHeaderFunc = getBlockHeaderFunc, - getBestBlockHashFunc = getBestBlockHashFunc) + ChainSync.sync( + chainHandler = chainApiSync1.asInstanceOf[ChainHandler], + getBlockHeaderFunc = getBlockHeaderFunc, + getBestBlockHashFunc = getBestBlockHashFunc + ) count <- chainApiSync2.getBlockCount() _ <- generate1F bestHash <- chainApiSync2.getBestBlockHash() diff --git a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/sync/FilterSyncTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/sync/FilterSyncTest.scala index c0e74dfcf3..638f1402fb 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/blockchain/sync/FilterSyncTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/blockchain/sync/FilterSyncTest.scala @@ -89,7 +89,8 @@ class FilterSyncTest extends ChainWithBitcoindNewestCachedUnitTest { val sync2F = synced1F.flatMap { chainApi => syncHelper( - fixture.copy(chainHandler = chainApi.asInstanceOf[ChainHandler])) + fixture.copy(chainHandler = chainApi.asInstanceOf[ChainHandler]) + ) } for { @@ -102,8 +103,8 @@ class FilterSyncTest extends ChainWithBitcoindNewestCachedUnitTest { } private def syncHelper( - bitcoindChainHandler: BitcoindBaseVersionChainHandlerViaRpc): Future[ - ChainApi] = { + bitcoindChainHandler: BitcoindBaseVersionChainHandlerViaRpc + ): Future[ChainApi] = { val filterType = FilterType.Basic val BitcoindBaseVersionChainHandlerViaRpc(bitcoind, chainHandler) = bitcoindChainHandler @@ -113,13 +114,14 @@ class FilterSyncTest extends ChainWithBitcoindNewestCachedUnitTest { val getFilterFunc: BlockHeader => Future[FilterWithHeaderHash] = SyncUtil.getFilterFunc(bitcoind, filterType) - //first sync the chain + // first sync the chain val syncedHeadersF: Future[ChainApi] = ChainSync.sync( chainHandler = chainHandler, getBlockHeaderFunc = getBlockHeaderFunc, - getBestBlockHashFunc = getBestBlockHashFunc) + getBestBlockHashFunc = getBestBlockHashFunc + ) - //now sync filters + // now sync filters syncedHeadersF.flatMap { syncedChainHandler => FilterSync.syncFilters( chainApi = syncedChainHandler, diff --git a/chain-test/src/test/scala/org/bitcoins/chain/config/ChainAppConfigTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/config/ChainAppConfigTest.scala index 27494e1f8f..08b8b713d4 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/config/ChainAppConfigTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/config/ChainAppConfigTest.scala @@ -15,11 +15,12 @@ class ChainAppConfigTest extends ChainUnitTest { val tempDir = Files.createTempDirectory("bitcoin-s") val config = ChainAppConfig(baseDatadir = tempDir, Vector.empty) - //if we don't turn off logging here, isInitF a few lines down will - //produce some nasty error logs since we are testing initialization - //of the chain project + // if we don't turn off logging here, isInitF a few lines down will + // produce some nasty error logs since we are testing initialization + // of the chain project val chainAppConfig = cachedChainConf.withOverrides( - ConfigFactory.parseString("bitcoin-s.logging.level=OFF")) + ConfigFactory.parseString("bitcoin-s.logging.level=OFF") + ) behavior of "ChainAppConfig" @@ -94,7 +95,7 @@ class ChainAppConfigTest extends ChainUnitTest { appConfig.addCallbacks(printlnCallback) assert(!appConfig.isCallbackEmpty) - //clear the callback + // clear the callback appConfig.clearCallbacks() assert(appConfig.isCallbackEmpty) } diff --git a/chain-test/src/test/scala/org/bitcoins/chain/models/BlockHeaderDAOTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/models/BlockHeaderDAOTest.scala index aae0ac1008..e70886e921 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/models/BlockHeaderDAOTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/models/BlockHeaderDAOTest.scala @@ -49,7 +49,7 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { val blockHeader = BlockHeaderHelper.buildNextHeader(genesisHeaderDb) val createdF = blockHeaderDAO.create(blockHeader) - //delete the header in the db + // delete the header in the db val deletedF = { createdF.flatMap { _ => blockHeaderDAO.delete(blockHeader) @@ -108,7 +108,8 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { val headerDbsF = createdF.flatMap(_ => blockHeaderDAO.findClosestBeforeTime( - UInt32(TimeUtil.currentEpochSecond))) + UInt32(TimeUtil.currentEpochSecond) + )) headerDbsF.map { headerDbOpt => assert(headerDbOpt.isDefined) @@ -133,7 +134,7 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { val blockHeader2 = BlockHeaderHelper.buildNextHeader(blockHeader) - //insert another header and make sure that is the new last header + // insert another header and make sure that is the new last header assert1F.flatMap { _ => val created2F = blockHeaderDAO.create(blockHeader2) val chainTip2F = created2F.flatMap(_ => blockHeaderDAO.getBestChainTips) @@ -157,7 +158,7 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { blockHeaderDAO: BlockHeaderDAO => val reorgFixtureF = buildBlockHeaderDAOCompetingHeaders(blockHeaderDAO) - //now we have 2 competing tips, chainTips should return both competing headers + // now we have 2 competing tips, chainTips should return both competing headers val firstAssertionF = for { reorgFixture <- reorgFixtureF headerDb1 = reorgFixture.headerDb1 @@ -169,9 +170,9 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { assert(chainTips.contains(headerDb2)) } - //ok, now we are going to build a new header off of headerDb1 - //however, headerDb2 is _still_ a possible chainTip that we can reorg - //too. So we should still have both of them returned + // ok, now we are going to build a new header off of headerDb1 + // however, headerDb2 is _still_ a possible chainTip that we can reorg + // too. So we should still have both of them returned for { _ <- firstAssertionF reorgFixture <- reorgFixtureF @@ -189,7 +190,7 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { blockHeaderDAO: BlockHeaderDAO => val reorgFixtureF = buildBlockHeaderDAOCompetingHeaders(blockHeaderDAO) - //now we have 2 competing tips, so we should return 2 chains + // now we have 2 competing tips, so we should return 2 chains val firstAssertionF = for { _ <- reorgFixtureF chains <- blockHeaderDAO.getBlockchains() @@ -217,7 +218,7 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { assert(headers.head.height == 1) } - //create one at height 2 + // create one at height 2 val blockHeader2 = BlockHeaderHelper.buildNextHeader(blockHeader) val created2F = blockHeaderDAO.create(blockHeader2) @@ -265,7 +266,7 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { val blockHeader1 = BlockHeaderHelper.buildNextHeader(genesisHeaderDb) val created2F = createdF.flatMap(_ => blockHeaderDAO.create(blockHeader1)) - //now make sure they are both at height 1 + // now make sure they are both at height 1 val getHeightF = created2F.flatMap(_ => blockHeaderDAO.getAtHeight(1)) getHeightF.map { case headers => @@ -309,14 +310,16 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { val createdF = blockHeaderDAO.create(blockHeader) val noGenesisAncestorsF = - blockHeaderDAO.getNAncestors(childHash = - genesisHeaderDb.blockHeader.hashBE, - n = 1) + blockHeaderDAO.getNAncestors( + childHash = genesisHeaderDb.blockHeader.hashBE, + n = 1 + ) val foundGenesisF = - blockHeaderDAO.getNAncestors(childHash = - genesisHeaderDb.blockHeader.hashBE, - n = 0) + blockHeaderDAO.getNAncestors( + childHash = genesisHeaderDb.blockHeader.hashBE, + n = 0 + ) val emptyAssertion = for { noGenesisAncestors <- noGenesisAncestorsF foundGenesis <- foundGenesisF @@ -330,9 +333,10 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { val oneChildF = for { created <- createdF - children <- blockHeaderDAO.getNAncestors(childHash = - created.blockHeader.hashBE, - n = 1) + children <- blockHeaderDAO.getNAncestors( + childHash = created.blockHeader.hashBE, + n = 1 + ) } yield { assert(children.length == 2) assert(children == Vector(created, genesisHeaderDb)) @@ -357,13 +361,15 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { BlockHeaderDbHelper.fromBlockHeader( 1, BigInt(1, hex"fffef2bf0566ab".toArray), - ChainTestUtil.blockHeader562462) + ChainTestUtil.blockHeader562462 + ) val db2 = BlockHeaderDbHelper.fromBlockHeader( 2, BigInt(1, hex"01253721228459eac00c".toArray), - ChainTestUtil.blockHeader562463) + ChainTestUtil.blockHeader562463 + ) for { _ <- blockerHeaderDAO.createAll(Vector(db1, db2)) @@ -377,9 +383,11 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { val chainWork = BigInt(1, bytes.toArray) val db = - BlockHeaderDbHelper.fromBlockHeader(1, - chainWork, - ChainTestUtil.blockHeader562462) + BlockHeaderDbHelper.fromBlockHeader( + 1, + chainWork, + ChainTestUtil.blockHeader562462 + ) for { _ <- blockerHeaderDAO.create(db) @@ -429,32 +437,35 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { ) val chain1 = Vector( - BlockHeaderDbHelper.fromBlockHeader(3, - BigInt(2), - ChainTestUtil.blockHeader562464), - BlockHeaderDbHelper.fromBlockHeader(2, - BigInt(1), - ChainTestUtil.blockHeader562463), - BlockHeaderDbHelper.fromBlockHeader(1, - BigInt(0), - ChainTestUtil.blockHeader562462) + BlockHeaderDbHelper + .fromBlockHeader(3, BigInt(2), ChainTestUtil.blockHeader562464), + BlockHeaderDbHelper + .fromBlockHeader(2, BigInt(1), ChainTestUtil.blockHeader562463), + BlockHeaderDbHelper.fromBlockHeader( + 1, + BigInt(0), + ChainTestUtil.blockHeader562462 + ) ) val chain2 = Vector( BlockHeaderDbHelper.fromBlockHeader(2, BigInt(1), duplicate2), - BlockHeaderDbHelper.fromBlockHeader(1, - BigInt(0), - ChainTestUtil.blockHeader562462) + BlockHeaderDbHelper.fromBlockHeader( + 1, + BigInt(0), + ChainTestUtil.blockHeader562462 + ) ) val chain3 = Vector( BlockHeaderDbHelper.fromBlockHeader(3, BigInt(2), duplicate3), - BlockHeaderDbHelper.fromBlockHeader(2, - BigInt(1), - ChainTestUtil.blockHeader562463), - BlockHeaderDbHelper.fromBlockHeader(1, - BigInt(0), - ChainTestUtil.blockHeader562462) + BlockHeaderDbHelper + .fromBlockHeader(2, BigInt(1), ChainTestUtil.blockHeader562463), + BlockHeaderDbHelper.fromBlockHeader( + 1, + BigInt(0), + ChainTestUtil.blockHeader562462 + ) ) val chain4 = Vector( @@ -462,10 +473,12 @@ class BlockHeaderDAOTest extends ChainDbUnitTest { ) val expectedChains = - Vector(Blockchain(chain1), - Blockchain(chain2), - Blockchain(chain3), - Blockchain(chain4)) + Vector( + Blockchain(chain1), + Blockchain(chain2), + Blockchain(chain3), + Blockchain(chain4) + ) val headers = expectedChains.flatMap(_.headers).distinct diff --git a/chain-test/src/test/scala/org/bitcoins/chain/models/ChainStateDescriptorDAOTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/models/ChainStateDescriptorDAOTest.scala index 92d1a92ded..04d254d15d 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/models/ChainStateDescriptorDAOTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/models/ChainStateDescriptorDAOTest.scala @@ -26,7 +26,9 @@ class ChainStateDescriptorDAOTest extends ChainDbUnitTest { read <- dao.read(SyncDescriptor.tpe) _ = assert( read == Some( - ChainStateDescriptorDb(SyncDescriptor.tpe, SyncDescriptor(false)))) + ChainStateDescriptorDb(SyncDescriptor.tpe, SyncDescriptor(false)) + ) + ) sync <- dao.isSyncing _ = assert(!sync) @@ -35,7 +37,9 @@ class ChainStateDescriptorDAOTest extends ChainDbUnitTest { read <- dao.read(SyncDescriptor.tpe) _ = assert( read == Some( - ChainStateDescriptorDb(SyncDescriptor.tpe, SyncDescriptor(true)))) + ChainStateDescriptorDb(SyncDescriptor.tpe, SyncDescriptor(true)) + ) + ) sync <- dao.isSyncing _ = assert(sync) } yield succeed @@ -53,26 +57,41 @@ class ChainStateDescriptorDAOTest extends ChainDbUnitTest { read1 <- dao.read(IsInitialBlockDownload.tpe) _ = assert( - read1 == Some(ChainStateDescriptorDb(IsInitialBlockDownload.tpe, - IsInitialBlockDownload(true)))) + read1 == Some( + ChainStateDescriptorDb( + IsInitialBlockDownload.tpe, + IsInitialBlockDownload(true) + ) + ) + ) isIBDOpt2 <- dao.getIsIBD() _ = assert(isIBDOpt2.isDefined && isIBDOpt2.get.isIBDRunning == true) _ <- dao.updateIsIbd(false) read2 <- dao.read(ChainStateDescriptorType.IsInitialBlockDownload) _ = assert( - read2 == Some(ChainStateDescriptorDb(IsInitialBlockDownload.tpe, - IsInitialBlockDownload(false)))) + read2 == Some( + ChainStateDescriptorDb( + IsInitialBlockDownload.tpe, + IsInitialBlockDownload(false) + ) + ) + ) isIBDOpt3 <- dao.getIsIBD() _ = assert(isIBDOpt3.isDefined && isIBDOpt3.get.isIBDRunning == false) - //cannot revert IBD + // cannot revert IBD _ <- dao.updateIsIbd(true) read3 <- dao.read(IsInitialBlockDownload.tpe) _ = assert( - read3 == Some(ChainStateDescriptorDb(IsInitialBlockDownload.tpe, - IsInitialBlockDownload(false)))) + read3 == Some( + ChainStateDescriptorDb( + IsInitialBlockDownload.tpe, + IsInitialBlockDownload(false) + ) + ) + ) isIBDOpt4 <- dao.getIsIBD() _ = assert(isIBDOpt4.isDefined && isIBDOpt4.get.isIBDRunning == false) } yield succeed diff --git a/chain-test/src/test/scala/org/bitcoins/chain/models/CompactFilterDAOTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/models/CompactFilterDAOTest.scala index c7d044a841..5a147d45bb 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/models/CompactFilterDAOTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/models/CompactFilterDAOTest.scala @@ -83,7 +83,8 @@ class CompactFilterDAOTest extends ChainDbUnitTest { val blockHeaderDbHeavyWork = { blockHeaderDbLightWork.copy( chainWork = blockHeaderDbLightWork.chainWork + 1, - hashBE = CryptoGenerators.doubleSha256Digest.sample.get.flip) + hashBE = CryptoGenerators.doubleSha256Digest.sample.get.flip + ) } val headers = Vector(blockHeaderDbLightWork, blockHeaderDbHeavyWork) val blockHeaderDbF = blockHeaderDAO.createAll(headers) diff --git a/chain-test/src/test/scala/org/bitcoins/chain/models/CompactFilterHeaderDAOTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/models/CompactFilterHeaderDAOTest.scala index 17046b15b4..f27b89e016 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/models/CompactFilterHeaderDAOTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/models/CompactFilterHeaderDAOTest.scala @@ -119,7 +119,8 @@ class CompactFilterHeaderDAOTest extends ChainDbUnitTest { val blockHeaderDbHeavyWork = { blockHeaderDbLightWork.copy( chainWork = blockHeaderDbLightWork.chainWork + 1, - hashBE = CryptoGenerators.doubleSha256Digest.sample.get.flip) + hashBE = CryptoGenerators.doubleSha256Digest.sample.get.flip + ) } val headers = Vector(blockHeaderDbLightWork, blockHeaderDbHeavyWork) val blockHeaderDbF = blockHeaderDAO.createAll(headers) @@ -149,7 +150,8 @@ class CompactFilterHeaderDAOTest extends ChainDbUnitTest { } private def randomFilterHeader( - blockHeader: BlockHeaderDb): CompactFilterHeaderDb = { + blockHeader: BlockHeaderDb + ): CompactFilterHeaderDb = { CompactFilterHeaderDb( CryptoGenerators.doubleSha256Digest.sample.get.flip, filterHashBE = CryptoGenerators.doubleSha256Digest.sample.get.flip, diff --git a/chain-test/src/test/scala/org/bitcoins/chain/pow/BitcoinPowTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/pow/BitcoinPowTest.scala index d0cc360ab4..f1bcf7a18f 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/pow/BitcoinPowTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/pow/BitcoinPowTest.scala @@ -30,12 +30,15 @@ class BitcoinPowTest extends ChainDbUnitTest { it must "NOT calculate a POW change when one is not needed" inFixtured { case ChainFixture.Empty => val blockchain = Blockchain.fromHeaders( - Vector(ChainTestUtil.ValidPOWChange.blockHeaderDb566494)) + Vector(ChainTestUtil.ValidPOWChange.blockHeaderDb566494) + ) val header2 = ChainTestUtil.ValidPOWChange.blockHeaderDb566495 val nextWork = - Pow.getNetworkWorkRequired(newPotentialTip = header2.blockHeader, - blockchain = blockchain) + Pow.getNetworkWorkRequired( + newPotentialTip = header2.blockHeader, + blockchain = blockchain + ) assert(nextWork == blockchain.tip.nBits) } @@ -47,9 +50,11 @@ class BitcoinPowTest extends ChainDbUnitTest { val expectedNextWork = ChainTestUtil.ValidPOWChange.blockHeader566496.nBits val calculatedWork = - Pow.calculateNextWorkRequired(currentTipDb, - firstBlockDb, - MainNetChainParams) + Pow.calculateNextWorkRequired( + currentTipDb, + firstBlockDb, + MainNetChainParams + ) assert(calculatedWork == expectedNextWork) } @@ -63,10 +68,12 @@ class BitcoinPowTest extends ChainDbUnitTest { .until(ChainUnitTest.FIRST_POW_CHANGE + 1 + iterations) .toVector val assertionFs: Future[Assertion] = FutureUtil - .batchExecute(elements = iterator, - f = batchCheckHeaderPOW(_: Vector[Int], blockHeaderDAO), - init = succeed, - batchSize = 1000) + .batchExecute( + elements = iterator, + f = batchCheckHeaderPOW(_: Vector[Int], blockHeaderDAO), + init = succeed, + batchSize = 1000 + ) assertionFs } @@ -94,7 +101,8 @@ class BitcoinPowTest extends ChainDbUnitTest { /** Helper method to check headers proof of work in batches */ private def batchCheckHeaderPOW( iterator: Vector[Int], - blockHeaderDAO: BlockHeaderDAO): Future[Assertion] = { + blockHeaderDAO: BlockHeaderDAO + ): Future[Assertion] = { val nestedAssertions: Vector[Future[Assertion]] = { iterator.map { height => val blockF = blockHeaderDAO.getAtHeight(height + 1).map(_.head) diff --git a/chain-test/src/test/scala/org/bitcoins/chain/validation/TipValidationTest.scala b/chain-test/src/test/scala/org/bitcoins/chain/validation/TipValidationTest.scala index 33c971eaef..40b0acb7f0 100644 --- a/chain-test/src/test/scala/org/bitcoins/chain/validation/TipValidationTest.scala +++ b/chain-test/src/test/scala/org/bitcoins/chain/validation/TipValidationTest.scala @@ -21,7 +21,7 @@ class TipValidationTest extends ChainDbUnitTest { behavior of "TipValidation" - //blocks 566,092 and 566,093 + // blocks 566,092 and 566,093 val newValidTip = BlockHeaderHelper.header1 val currentTipDb = BlockHeaderHelper.header2Db val blockchain = Blockchain.fromHeaders(Vector(currentTipDb)) @@ -31,7 +31,8 @@ class TipValidationTest extends ChainDbUnitTest { BlockHeaderDbHelper.fromBlockHeader( 566093, currentTipDb.chainWork + Pow.getBlockProof(newValidTip), - newValidTip) + newValidTip + ) val expected = TipUpdateResult.Success(newValidTipDb) runTest(newValidTip, expected, blockchain) @@ -62,7 +63,8 @@ class TipValidationTest extends ChainDbUnitTest { private def runTest( header: BlockHeader, expected: TipUpdateResult, - blockchain: Blockchain): Assertion = { + blockchain: Blockchain + ): Assertion = { val result = TipValidation.checkNewTip(header, blockchain) assert(result == expected) } diff --git a/chain/src/main/scala/org/bitcoins/chain/ChainCallbacks.scala b/chain/src/main/scala/org/bitcoins/chain/ChainCallbacks.scala index 1d80c36f4e..c0ae591e19 100644 --- a/chain/src/main/scala/org/bitcoins/chain/ChainCallbacks.scala +++ b/chain/src/main/scala/org/bitcoins/chain/ChainCallbacks.scala @@ -12,63 +12,73 @@ trait ChainCallbacks extends ModuleCallbacks[ChainCallbacks] with BitcoinSLogger { - def onBlockHeaderConnected: CallbackHandler[ - Vector[(Int, BlockHeader)], - OnBlockHeaderConnected] + def onBlockHeaderConnected + : CallbackHandler[Vector[(Int, BlockHeader)], OnBlockHeaderConnected] - def onCompactFilterHeaderConnected: CallbackHandler[ - Vector[CompactFilterHeaderDb], - OnCompactFilterHeaderConnected] + def onCompactFilterHeaderConnected + : CallbackHandler[Vector[ + CompactFilterHeaderDb + ], + OnCompactFilterHeaderConnected] - def onCompactFilterConnected: CallbackHandler[ - Vector[CompactFilterDb], - OnCompactFilterConnected] + def onCompactFilterConnected + : CallbackHandler[Vector[CompactFilterDb], OnCompactFilterConnected] def onSyncFlagChanged: CallbackHandler[Boolean, OnSyncFlagChanged] override def +(other: ChainCallbacks): ChainCallbacks def executeOnBlockHeaderConnectedCallbacks( - heightHeaderTuple: Vector[(Int, BlockHeader)])(implicit - ec: ExecutionContext): Future[Unit] = { + heightHeaderTuple: Vector[(Int, BlockHeader)] + )(implicit ec: ExecutionContext): Future[Unit] = { onBlockHeaderConnected.execute( heightHeaderTuple, (err: Throwable) => logger.error( s"${onBlockHeaderConnected.name} Callback failed with error: ", - err)) + err + ) + ) } def executeOnCompactFilterHeaderConnectedCallbacks( - filterHeaders: Vector[CompactFilterHeaderDb])(implicit - ec: ExecutionContext): Future[Unit] = { + filterHeaders: Vector[CompactFilterHeaderDb] + )(implicit ec: ExecutionContext): Future[Unit] = { onCompactFilterHeaderConnected.execute( filterHeaders, (err: Throwable) => logger.error( s"${onCompactFilterHeaderConnected.name} Callback failed with err", - err)) + err + ) + ) } def executeOnCompactFilterConnectedCallbacks( - filters: Vector[CompactFilterDb])(implicit - ec: ExecutionContext): Future[Unit] = { + filters: Vector[CompactFilterDb] + )(implicit ec: ExecutionContext): Future[Unit] = { onCompactFilterConnected.execute( filters, (err: Throwable) => logger.error( s"${onCompactFilterConnected.name} Callback failed with err", - err)) + err + ) + ) } - def executeOnSyncFlagChanged(syncing: Boolean)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnSyncFlagChanged( + syncing: Boolean + )(implicit ec: ExecutionContext): Future[Unit] = { onSyncFlagChanged.execute( syncing, (err: Throwable) => - logger.error(s"${onSyncFlagChanged.name} Callback failed with error: ", - err)) + logger.error( + s"${onSyncFlagChanged.name} Callback failed with error: ", + err + ) + ) } } @@ -86,17 +96,21 @@ trait OnSyncFlagChanged extends Callback[Boolean] object ChainCallbacks extends CallbackFactory[ChainCallbacks] { private case class ChainCallbacksImpl( - onBlockHeaderConnected: CallbackHandler[ - Vector[(Int, BlockHeader)], - OnBlockHeaderConnected], + onBlockHeaderConnected: CallbackHandler[Vector[ + (Int, BlockHeader) + ], + OnBlockHeaderConnected], onCompactFilterHeaderConnected: CallbackHandler[ - Vector[CompactFilterHeaderDb], + Vector[ + CompactFilterHeaderDb + ], OnCompactFilterHeaderConnected], - onCompactFilterConnected: CallbackHandler[ - Vector[CompactFilterDb], - OnCompactFilterConnected], - onSyncFlagChanged: CallbackHandler[Boolean, OnSyncFlagChanged]) - extends ChainCallbacks { + onCompactFilterConnected: CallbackHandler[Vector[ + CompactFilterDb + ], + OnCompactFilterConnected], + onSyncFlagChanged: CallbackHandler[Boolean, OnSyncFlagChanged] + ) extends ChainCallbacks { override def +(other: ChainCallbacks): ChainCallbacks = copy( @@ -115,7 +129,8 @@ object ChainCallbacks extends CallbackFactory[ChainCallbacks] { ChainCallbacks(onBlockHeaderConnected = Vector(f)) def onCompactFilterHeaderConnected( - f: OnCompactFilterHeaderConnected): ChainCallbacks = { + f: OnCompactFilterHeaderConnected + ): ChainCallbacks = { ChainCallbacks(onCompactFilterHeaderConnected = Vector(f)) } @@ -134,24 +149,30 @@ object ChainCallbacks extends CallbackFactory[ChainCallbacks] { onCompactFilterHeaderConnected: Vector[OnCompactFilterHeaderConnected] = Vector.empty, onCompactFilterConnected: Vector[OnCompactFilterConnected] = Vector.empty, - onSyncFlagChanged: Vector[OnSyncFlagChanged] = - Vector.empty): ChainCallbacks = + onSyncFlagChanged: Vector[OnSyncFlagChanged] = Vector.empty + ): ChainCallbacks = ChainCallbacksImpl( onBlockHeaderConnected = CallbackHandler[Vector[(Int, BlockHeader)], OnBlockHeaderConnected]( "onBlockHeaderConnected", - onBlockHeaderConnected), + onBlockHeaderConnected + ), onCompactFilterHeaderConnected = - CallbackHandler[Vector[CompactFilterHeaderDb], + CallbackHandler[Vector[ + CompactFilterHeaderDb + ], OnCompactFilterHeaderConnected]( "onCompactFilterHeaderConnected", - onCompactFilterHeaderConnected), + onCompactFilterHeaderConnected + ), onCompactFilterConnected = CallbackHandler[Vector[CompactFilterDb], OnCompactFilterConnected]( "onCompactFilterConnected", - onCompactFilterConnected), - onSyncFlagChanged = - CallbackHandler[Boolean, OnSyncFlagChanged]("onSyncFlagChanged", - onSyncFlagChanged) + onCompactFilterConnected + ), + onSyncFlagChanged = CallbackHandler[Boolean, OnSyncFlagChanged]( + "onSyncFlagChanged", + onSyncFlagChanged + ) ) } diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/BaseBlockChain.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/BaseBlockChain.scala index 3e2535c22b..04667639d9 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/BaseBlockChain.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/BaseBlockChain.scala @@ -21,12 +21,10 @@ import scala.annotation.tailrec // objects (they have to be in the same file as the trait/class), this was // the least ugly workaround I could come up with. -/** In memory implementation of a blockchain - * This data structure maintains the state of a - * blockchain in memory, the headers can be accessed - * with [[headers]]. The headers are stored with the most - * recent header at index 0, the second most recent header at index 1 etc - * You can walk the chain by +/** In memory implementation of a blockchain This data structure maintains the + * state of a blockchain in memory, the headers can be accessed with + * [[headers]]. The headers are stored with the most recent header at index 0, + * the second most recent header at index 1 etc You can walk the chain by * {{{ * headers.map(h => println(h)) * }}} @@ -34,12 +32,15 @@ import scala.annotation.tailrec private[blockchain] trait BaseBlockChain extends SeqWrapper[BlockHeaderDb] { protected[blockchain] def compObjectFromHeaders( - headers: scala.collection.immutable.Seq[BlockHeaderDb]): Blockchain + headers: scala.collection.immutable.Seq[BlockHeaderDb] + ): Blockchain lazy val tip: BlockHeaderDb = headers.head - require(headers.size <= 1 || headers(1).height == tip.height - 1, - s"Headers must be in descending order, got ${headers.take(5)}") + require( + headers.size <= 1 || headers(1).height == tip.height - 1, + s"Headers must be in descending order, got ${headers.take(5)}" + ) /** The height of the chain */ lazy val height: Int = tip.height @@ -54,7 +55,9 @@ private[blockchain] trait BaseBlockChain extends SeqWrapper[BlockHeaderDb] { def findAtHeight(height: Int): Option[BlockHeaderDb] = find(_.height == height) - /** Splits the blockchain at the header, returning a new blockchain where the best tip is the given header */ + /** Splits the blockchain at the header, returning a new blockchain where the + * best tip is the given header + */ def fromHeader(header: BlockHeaderDb): Option[Blockchain] = { val headerIdxOpt = findHeaderIdx(header.hashBE) headerIdxOpt.map { idx => @@ -64,7 +67,10 @@ private[blockchain] trait BaseBlockChain extends SeqWrapper[BlockHeaderDb] { } } - /** Unsafe version for [[org.bitcoins.chain.blockchain.Blockchain.fromHeader() fromHeader]] that can throw [[NoSuchElementException]] */ + /** Unsafe version for + * [[org.bitcoins.chain.blockchain.Blockchain.fromHeader() fromHeader]] that + * can throw [[NoSuchElementException]] + */ def fromValidHeader(header: BlockHeaderDb): Blockchain = { fromHeader(header).get } @@ -97,31 +103,38 @@ private[blockchain] trait BaseBlockChainCompObject extends ChainVerificationLogger { def fromHeaders( - headers: scala.collection.immutable.Seq[BlockHeaderDb]): Blockchain + headers: scala.collection.immutable.Seq[BlockHeaderDb] + ): Blockchain /** Attempts to connect the given block header with the given blockchain - * @param header the block header to connect to our chain - * @param blockchain the blockchain we are attempting to connect to + * @param header + * the block header to connect to our chain + * @param blockchain + * the blockchain we are attempting to connect to */ def connectTip(header: BlockHeader, blockchain: Blockchain)(implicit - conf: ChainAppConfig): ConnectTipResult = { + conf: ChainAppConfig + ): ConnectTipResult = { logger.debug( - s"Attempting to add new tip=${header.hashBE.hex} with prevhash=${header.previousBlockHashBE.hex} to chain") + s"Attempting to add new tip=${header.hashBE.hex} with prevhash=${header.previousBlockHashBE.hex} to chain" + ) val tipResult: ConnectTipResult = { findPrevBlockHeaderIdx(header, blockchain) match { case None => logger.debug( - s"No common ancestor found in the chain with tip=${blockchain.tip.hashBE.hex} to connect to hash=${header.hashBE.hex} prevHash=${header.previousBlockHashBE.hex}. This may be because we have a competing reorg!") + s"No common ancestor found in the chain with tip=${blockchain.tip.hashBE.hex} to connect to hash=${header.hashBE.hex} prevHash=${header.previousBlockHashBE.hex}. This may be because we have a competing reorg!" + ) val err = TipUpdateResult.BadPreviousBlockHash(header) val failed = ConnectTipResult.BadTip(err) failed case Some(prevHeaderIdx) => - //found a header to connect to! + // found a header to connect to! val prevBlockHeader = blockchain.headers(prevHeaderIdx) logger.debug( - s"Attempting to add new tip=${header.hashBE.hex} with prevhash=${header.previousBlockHashBE.hex} to chain of ${blockchain.length} headers with tip ${blockchain.tip.hashBE.hex}") + s"Attempting to add new tip=${header.hashBE.hex} with prevhash=${header.previousBlockHashBE.hex} to chain of ${blockchain.length} headers with tip ${blockchain.tip.hashBE.hex}" + ) val chain = blockchain.fromValidHeader(prevBlockHeader) val tipResult = TipValidation.checkNewTip(newPotentialTip = header, chain) @@ -129,7 +142,8 @@ private[blockchain] trait BaseBlockChainCompObject tipResult match { case success: TipUpdateResult.Success => logger.debug( - s"Successfully verified=${success.header.hashBE.hex}, connecting to chain") + s"Successfully verified=${success.header.hashBE.hex}, connecting to chain" + ) val connectionIdx = blockchain.length - prevHeaderIdx // we construct a new blockchain by prepending the headers vector from the old one with the new tip @@ -137,20 +151,23 @@ private[blockchain] trait BaseBlockChainCompObject if (connectionIdx != blockchain.length) { val newChain = Blockchain( success.headerDb +: blockchain.headers.takeRight( - connectionIdx)) - //means we have a reorg, since we aren't connecting to latest tip + connectionIdx + ) + ) + // means we have a reorg, since we aren't connecting to latest tip ConnectTipResult.Reorg(success, newChain) } else { val olderChain = if (blockchain.size < 2016) { blockchain.headers } else blockchain.headers.take(2015) val newChain = Blockchain(success.headerDb +: olderChain) - //we just extended the latest tip + // we just extended the latest tip ConnectTipResult.ExtendChain(success, newChain) } case fail: TipUpdateResult.Failure => logger.warn( - s"Could not verify header=${header.hashBE.hex}, reason=$fail") + s"Could not verify header=${header.hashBE.hex}, reason=$fail" + ) ConnectTipResult.BadTip(fail) } } @@ -158,16 +175,19 @@ private[blockchain] trait BaseBlockChainCompObject tipResult } - /** Iterates through each given blockchains attempting to connect the given headers to that chain + /** Iterates through each given blockchains attempting to connect the given + * headers to that chain * - * @return The final updates for each chain + * @return + * The final updates for each chain */ def connectHeadersToChains( headers: Vector[BlockHeader], - blockchains: Vector[Blockchain])(implicit - chainAppConfig: ChainAppConfig): Vector[BlockchainUpdate] = { + blockchains: Vector[Blockchain] + )(implicit chainAppConfig: ChainAppConfig): Vector[BlockchainUpdate] = { logger.debug( - s"Attempting to connect ${headers.length} headers to ${blockchains.length} blockchains") + s"Attempting to connect ${headers.length} headers to ${blockchains.length} blockchains" + ) val initUpdates: Vector[BlockchainUpdate] = blockchains.map { blockchain => BlockchainUpdate.Successful(blockchain, Vector.empty) @@ -177,41 +197,47 @@ private[blockchain] trait BaseBlockChainCompObject lastUpdates .flatMap { lastUpdate => val connectTipResult = - Blockchain.connectTip(header = h, - blockchain = lastUpdate.blockchain) + Blockchain.connectTip( + header = h, + blockchain = lastUpdate.blockchain + ) parseConnectTipResult(connectTipResult, lastUpdate) } } } /** Parses a connect tip result, and depending on the result it - * 1. Extends the current chain by one block - * 2. Causes a re-org, which returns the old best tip and the new competing chain - * 3. Fails to connect tip, in which case it returns the old best chain + * 1. Extends the current chain by one block 2. Causes a re-org, which + * returns the old best tip and the new competing chain 3. Fails to + * connect tip, in which case it returns the old best chain */ private def parseConnectTipResult( connectTipResult: ConnectTipResult, - lastUpdate: BlockchainUpdate): Vector[BlockchainUpdate] = { + lastUpdate: BlockchainUpdate + ): Vector[BlockchainUpdate] = { lastUpdate match { case _: BlockchainUpdate.Successful => connectTipResult match { case ConnectTipResult.ExtendChain(tipUpdateResult, newChain) => val update = BlockchainUpdate.Successful( newChain, - tipUpdateResult.headerDb +: lastUpdate.successfulHeaders) + tipUpdateResult.headerDb +: lastUpdate.successfulHeaders + ) Vector(update) case ConnectTipResult.Reorg(tipUpdateResult, newChain) => val competingUpdate = BlockchainUpdate.Successful( newChain, - tipUpdateResult.headerDb +: lastUpdate.successfulHeaders) + tipUpdateResult.headerDb +: lastUpdate.successfulHeaders + ) Vector(lastUpdate, competingUpdate) case ConnectTipResult.BadTip(tipUpdateResult) => val failedUpdate = BlockchainUpdate.Failed( lastUpdate.blockchain, lastUpdate.successfulHeaders, tipUpdateResult.header, - tipUpdateResult) + tipUpdateResult + ) Vector(failedUpdate) } @@ -225,7 +251,8 @@ private[blockchain] trait BaseBlockChainCompObject */ private def findPrevBlockHeaderIdx( header: BlockHeader, - blockchain: Blockchain): Option[Int] = { + blockchain: Blockchain + ): Option[Int] = { // Let's see if we are lucky and the latest tip is the parent. val latestTip = blockchain.tip if (latestTip.hashBE == header.previousBlockHashBE) { @@ -237,12 +264,14 @@ private[blockchain] trait BaseBlockChainCompObject } } - /** Walks backwards from the current header searching through ancestors if [[current.previousBlockHashBE]] is in [[ancestors]] - * This does not validate other things such as POW. + /** Walks backwards from the current header searching through ancestors if + * [[current.previousBlockHashBE]] is in [[ancestors]] This does not validate + * other things such as POW. */ final def connectWalkBackwards( current: BlockHeaderDb, - ancestors: Vector[BlockHeaderDb]): Vector[BlockHeaderDb] = { + ancestors: Vector[BlockHeaderDb] + ): Vector[BlockHeaderDb] = { val groupByHeight: Map[Int, Vector[BlockHeaderDb]] = { ancestors.groupBy(_.height) } @@ -250,7 +279,8 @@ private[blockchain] trait BaseBlockChainCompObject @tailrec def loop( current: BlockHeaderDb, - accum: Vector[BlockHeaderDb]): Vector[BlockHeaderDb] = { + accum: Vector[BlockHeaderDb] + ): Vector[BlockHeaderDb] = { val prevHeight = current.height - 1 val possibleHeadersOpt: Option[Vector[BlockHeaderDb]] = groupByHeight.get(prevHeight) @@ -269,36 +299,38 @@ private[blockchain] trait BaseBlockChainCompObject loop(current, Vector.empty) } - /** Walks backwards from a child header reconstructing a blockchain - * This validates things like POW, difficulty change etc. + /** Walks backwards from a child header reconstructing a blockchain This + * validates things like POW, difficulty change etc. */ def reconstructFromHeaders( childHeader: BlockHeaderDb, - ancestors: Vector[BlockHeaderDb])(implicit - chainAppConfig: ChainAppConfig): Vector[Blockchain] = { - //now all hashes are connected correctly forming a - //valid blockchain in term of hashes connected to each other + ancestors: Vector[BlockHeaderDb] + )(implicit chainAppConfig: ChainAppConfig): Vector[Blockchain] = { + // now all hashes are connected correctly forming a + // valid blockchain in term of hashes connected to each other val orderedHeaders = connectWalkBackwards(current = childHeader, ancestors = ancestors) val initBlockchainOpt = { if (orderedHeaders.isEmpty || orderedHeaders.length == 1) { - //for the case of _ +: Vector() this means only our - //child header is in the chain, which means we - //weren't able to form a blockchain + // for the case of _ +: Vector() this means only our + // child header is in the chain, which means we + // weren't able to form a blockchain None } else { - //find our first header as we need it's Db representation - //rather than just the raw header + // find our first header as we need it's Db representation + // rather than just the raw header val dbOpt = ancestors.find(_.hashBE == orderedHeaders.head.hashBE) Some(Blockchain.fromHeaders(Vector(dbOpt.get))) } } - //now let's connect headers + // now let's connect headers val blockchainUpdateOpt = initBlockchainOpt.map { initBlockchain => - Blockchain.connectHeadersToChains(orderedHeaders.tail.map(_.blockHeader), - Vector(initBlockchain)) + Blockchain.connectHeadersToChains( + orderedHeaders.tail.map(_.blockHeader), + Vector(initBlockchain) + ) } blockchainUpdateOpt match { diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/Blockchain.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/Blockchain.scala index 8588f8e91c..2f155c0648 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/Blockchain.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/Blockchain.scala @@ -6,7 +6,8 @@ import org.bitcoins.core.api.chain.db.BlockHeaderDb case class Blockchain(headers: Vector[BlockHeaderDb]) extends BaseBlockChain { protected[blockchain] def compObjectFromHeaders( - headers: scala.collection.immutable.Seq[BlockHeaderDb]) = + headers: scala.collection.immutable.Seq[BlockHeaderDb] + ) = Blockchain.fromHeaders(headers) } @@ -14,6 +15,7 @@ case class Blockchain(headers: Vector[BlockHeaderDb]) extends BaseBlockChain { object Blockchain extends BaseBlockChainCompObject { override def fromHeaders( - headers: scala.collection.immutable.Seq[BlockHeaderDb]): Blockchain = + headers: scala.collection.immutable.Seq[BlockHeaderDb] + ): Blockchain = Blockchain(headers.toVector) } diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/BlockchainUpdate.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/BlockchainUpdate.scala index f6159207e9..9038719a25 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/BlockchainUpdate.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/BlockchainUpdate.scala @@ -4,17 +4,24 @@ import org.bitcoins.chain.validation.TipUpdateResult import org.bitcoins.core.api.chain.db.BlockHeaderDb import org.bitcoins.core.protocol.blockchain.BlockHeader -/** Represens the state of a batch of [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeaders]] being added to our blockchain +/** Represens the state of a batch of + * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeaders]] being + * added to our blockchain * - * An example of a [[org.bitcoins.chain.blockchain.BlockchainUpdate.Failed Failed]] update - * is when we receive a [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] that is invalid and because of a + * An example of a + * [[org.bitcoins.chain.blockchain.BlockchainUpdate.Failed Failed]] update is + * when we receive a + * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] that is + * invalid and because of a * [[org.bitcoins.chain.validation.TipUpdateResult.Failure TipUpdateFailure]] - * because of [[org.bitcoins.chain.validation.TipUpdateResult.BadPOW BadPOW]] or a - * [[org.bitcoins.chain.validation.TipUpdateResult.BadNonce BadNonce]] etc + * because of [[org.bitcoins.chain.validation.TipUpdateResult.BadPOW BadPOW]] + * or a [[org.bitcoins.chain.validation.TipUpdateResult.BadNonce BadNonce]] etc */ sealed abstract class BlockchainUpdate { - /** The successful headers in this batch blockchain update that need to be persisted */ + /** The successful headers in this batch blockchain update that need to be + * persisted + */ def successfulHeaders: Vector[BlockHeaderDb] /** Our current blockchain */ @@ -24,14 +31,15 @@ sealed abstract class BlockchainUpdate { object BlockchainUpdate { - /** The key thing we receive here is [[org.bitcoins.chain.models.BlockHeaderDb BlockHeaderDb]] - * with a height assigned to it this happens after - * calling [[org.bitcoins.chain.blockchain.ChainHandler.processHeaders ChainHandler.processHeaders]] + /** The key thing we receive here is + * [[org.bitcoins.chain.models.BlockHeaderDb BlockHeaderDb]] with a height + * assigned to it this happens after calling + * [[org.bitcoins.chain.blockchain.ChainHandler.processHeaders ChainHandler.processHeaders]] */ case class Successful( blockchain: Blockchain, - successfulHeaders: Vector[BlockHeaderDb]) - extends BlockchainUpdate { + successfulHeaders: Vector[BlockHeaderDb] + ) extends BlockchainUpdate { if (successfulHeaders.nonEmpty) { require( blockchain.tip == successfulHeaders.head, @@ -42,18 +50,19 @@ object BlockchainUpdate { } /** Means we failed to update the given blockchain with _ALL_ given headers - * This means we could have had a partially successful update, with the headers/blockchain - * returned in this case class + * This means we could have had a partially successful update, with the + * headers/blockchain returned in this case class */ case class Failed( blockchain: Blockchain, successfulHeaders: Vector[BlockHeaderDb], failedHeader: BlockHeader, - tipUpdateFailure: TipUpdateResult.Failure) - extends BlockchainUpdate { + tipUpdateFailure: TipUpdateResult.Failure + ) extends BlockchainUpdate { require( !blockchain.exists(_.blockHeader == failedHeader), - s"Our blockchain should not contain the failed header=${failedHeader}") + s"Our blockchain should not contain the failed header=${failedHeader}" + ) if (successfulHeaders.nonEmpty) { require( diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainException.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainException.scala index 4e006b8e50..a8ce64f438 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainException.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainException.scala @@ -4,22 +4,23 @@ package org.bitcoins.chain.blockchain sealed abstract class ChainException(message: String) extends RuntimeException(message) -/** [[org.bitcoins.chain.blockchain.ChainHandler]] cannot find a compact - * filter or header by its filter hash +/** [[org.bitcoins.chain.blockchain.ChainHandler]] cannot find a compact filter + * or header by its filter hash */ case class UnknownFilterHash(message: String) extends ChainException(message) -/** [[org.bitcoins.chain.blockchain.ChainHandler]] cannot find a blockchain - * item by its block hash +/** [[org.bitcoins.chain.blockchain.ChainHandler]] cannot find a blockchain item + * by its block hash */ case class UnknownBlockHash(message: String) extends ChainException(message) -/** [[org.bitcoins.chain.blockchain.ChainHandler]] cannot find a blockchain - * item by its height +/** [[org.bitcoins.chain.blockchain.ChainHandler]] cannot find a blockchain item + * by its height */ case class UnknownBlockHeight(message: String) extends ChainException(message) -/** [[org.bitcoins.chain.blockchain.ChainHandler]] tried to process multiple filters for the same block hash +/** [[org.bitcoins.chain.blockchain.ChainHandler]] tried to process multiple + * filters for the same block hash */ case class DuplicateFilters(message: String) extends ChainException(message) diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainHandler.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainHandler.scala index 6e4f392603..c311c082fc 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainHandler.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainHandler.scala @@ -18,29 +18,32 @@ import org.bitcoins.crypto.{CryptoUtil, DoubleSha256DigestBE} import scala.annotation.tailrec import scala.concurrent._ -/** Chain Handler is meant to be the reference implementation - * of [[ChainApi ChainApi]], this is the entry point in to the - * chain project. +/** Chain Handler is meant to be the reference implementation of + * [[ChainApi ChainApi]], this is the entry point in to the chain project. * - * This implementation of [[ChainApi]] reads all values directly from the database. If you want an optimized version - * that caches headers locally please see [[ChainHandlerCached]] + * This implementation of [[ChainApi]] reads all values directly from the + * database. If you want an optimized version that caches headers locally + * please see [[ChainHandlerCached]] * - * @param blockHeaderDAO block header DB - * @param filterHeaderDAO filter header DB - * @param filterDAO filter DB - * @param blockFilterCheckpoints compact filter checkpoints for filter header verification in form of a map (block header hash -> filter header hash) - * @param chainConfig config file + * @param blockHeaderDAO + * block header DB + * @param filterHeaderDAO + * filter header DB + * @param filterDAO + * filter DB + * @param blockFilterCheckpoints + * compact filter checkpoints for filter header verification in form of a map + * (block header hash -> filter header hash) + * @param chainConfig + * config file */ class ChainHandler( val blockHeaderDAO: BlockHeaderDAO, val filterHeaderDAO: CompactFilterHeaderDAO, val filterDAO: CompactFilterDAO, val stateDAO: ChainStateDescriptorDAO, - val blockFilterCheckpoints: Map[ - DoubleSha256DigestBE, - DoubleSha256DigestBE])(implicit - val chainConfig: ChainAppConfig, - executionContext: ExecutionContext) + val blockFilterCheckpoints: Map[DoubleSha256DigestBE, DoubleSha256DigestBE] +)(implicit val chainConfig: ChainAppConfig, executionContext: ExecutionContext) extends ChainApi with ChainVerificationLogger { @@ -53,10 +56,12 @@ class ChainHandler( /** Given a set of blockchains, determines which one has the best header */ protected def getBestBlockHeaderHelper( - chains: Vector[Blockchain]): BlockHeaderDb = { + chains: Vector[Blockchain] + ): BlockHeaderDb = { logger.trace( - s"Finding best block hash out of chains.length=${chains.length}") - //https://bitcoin.org/en/glossary/block-chain + s"Finding best block hash out of chains.length=${chains.length}" + ) + // https://bitcoin.org/en/glossary/block-chain val groupedChains = chains.groupBy(_.tip.chainWork) val maxWork = groupedChains.keys.max val chainsByWork = groupedChains(maxWork) @@ -74,10 +79,11 @@ class ChainHandler( .map(_.tip.hashBE.hex) .mkString(", ") logger.warn( - s"We have multiple competing blockchains with same work, selecting by time: $tips") - //since we have same chainwork, just take the oldest tip - //as that's "more likely" to have been propagated first - //and had more miners building on top of it + s"We have multiple competing blockchains with same work, selecting by time: $tips" + ) + // since we have same chainwork, just take the oldest tip + // as that's "more likely" to have been propagated first + // and had more miners building on top of it chainsByWork.minBy(_.tip.time).tip } } @@ -96,35 +102,41 @@ class ChainHandler( /** @inheritdoc */ override def getHeader( - hash: DoubleSha256DigestBE): Future[Option[BlockHeaderDb]] = { + hash: DoubleSha256DigestBE + ): Future[Option[BlockHeaderDb]] = { getHeaders(Vector(hash)).map(_.head) } - override def getHeaders(hashes: Vector[DoubleSha256DigestBE]): Future[ - Vector[Option[BlockHeaderDb]]] = { + override def getHeaders( + hashes: Vector[DoubleSha256DigestBE] + ): Future[Vector[Option[BlockHeaderDb]]] = { blockHeaderDAO.findByHashes(hashes) } protected def processHeadersWithChains( headers: Vector[BlockHeader], - blockchains: Vector[Blockchain]): Future[ChainApi] = { + blockchains: Vector[Blockchain] + ): Future[ChainApi] = { if (headers.isEmpty) { Future.successful(this) } else { val headersWeAlreadyHave = blockchains.flatMap(_.headers) - //if we already have the header don't process it again + // if we already have the header don't process it again val filteredHeaders = headers.filterNot(h => headersWeAlreadyHave.exists(_.hashBE == h.hashBE)) if (filteredHeaders.isEmpty) { return Future.failed( - DuplicateHeaders(s"Received duplicate block headers.")) + DuplicateHeaders(s"Received duplicate block headers.") + ) } val blockchainUpdates: Vector[BlockchainUpdate] = { - Blockchain.connectHeadersToChains(headers = filteredHeaders, - blockchains = blockchains) + Blockchain.connectHeadersToChains( + headers = filteredHeaders, + blockchains = blockchains + ) } val successfullyValidatedHeaders = blockchainUpdates @@ -136,22 +148,26 @@ class ChainHandler( } if (headersToBeCreated.isEmpty) { - //this means we are given zero headers that were valid. - //Return a failure in this case to avoid issue 2365 - //https://github.com/bitcoin-s/bitcoin-s/issues/2365 - Future.failed(InvalidBlockHeader( - s"Failed to connect any headers to our internal chain state, failures=$blockchainUpdates")) + // this means we are given zero headers that were valid. + // Return a failure in this case to avoid issue 2365 + // https://github.com/bitcoin-s/bitcoin-s/issues/2365 + Future.failed( + InvalidBlockHeader( + s"Failed to connect any headers to our internal chain state, failures=$blockchainUpdates" + ) + ) } else { val chains = blockchainUpdates.map(_.blockchain) val createdF = blockHeaderDAO.createAll(headersToBeCreated) - val newChainHandler = ChainHandler(blockHeaderDAO, - filterHeaderDAO, - filterDAO, - stateDAO, - blockFilterCheckpoints = - blockFilterCheckpoints) + val newChainHandler = ChainHandler( + blockHeaderDAO, + filterHeaderDAO, + filterDAO, + stateDAO, + blockFilterCheckpoints = blockFilterCheckpoints + ) createdF.map { headers => if (chainConfig.callBacks.onBlockHeaderConnected.nonEmpty) { @@ -165,7 +181,8 @@ class ChainHandler( } chains.foreach { c => logger.info( - s"Processed headers from height=${c.height - headers.length} to ${c.height}. Best hash=${c.tip.hashBE.hex}") + s"Processed headers from height=${c.height - headers.length} to ${c.height}. Best hash=${c.tip.hashBE.hex}" + ) } newChainHandler } @@ -175,7 +192,8 @@ class ChainHandler( /** @inheritdoc */ override def processHeaders( - headers: Vector[BlockHeader]): Future[ChainApi] = { + headers: Vector[BlockHeader] + ): Future[ChainApi] = { val blockchainsF = blockHeaderDAO.getBlockchains() val resultF = for { blockchains <- blockchainsF @@ -199,7 +217,8 @@ class ChainHandler( override def nextBlockHeaderBatchRange( prevStopHash: DoubleSha256DigestBE, stopHash: DoubleSha256DigestBE, - batchSize: Int): Future[Option[FilterSyncMarker]] = { + batchSize: Int + ): Future[Option[FilterSyncMarker]] = { if (prevStopHash == DoubleSha256DigestBE.empty) { getHeadersAtHeight(batchSize - 1).map { headers => if (headers.length == 1) { @@ -207,12 +226,13 @@ class ChainHandler( Some(fsm) } else { logger.warn( - s"ChainHandler.nextBlockHeaderBatchRange() did not find a single header, got zero or multiple=$headers") + s"ChainHandler.nextBlockHeaderBatchRange() did not find a single header, got zero or multiple=$headers" + ) None } } } else if (prevStopHash == stopHash) { - //means are are in sync + // means are are in sync Future.successful(None) } else { val candidateStartHeadersF = getImmediateChildren(prevStopHash) @@ -224,21 +244,25 @@ class ChainHandler( stopBlockHeader = { stopBlockHeaderOpt.getOrElse { sys.error( - s"Could not find block header associated with stopHash=$stopHash") + s"Could not find block header associated with stopHash=$stopHash" + ) } } fsmOptVec <- { Future.traverse(candidateStartHeaders) { candidateHeader => - getFilterSyncStopHash(candidateStartHeader = candidateHeader, - stopBlockHeader = stopBlockHeader, - batchSize = batchSize) + getFilterSyncStopHash( + candidateStartHeader = candidateHeader, + stopBlockHeader = stopBlockHeader, + batchSize = batchSize + ) } } } yield { val flatten = fsmOptVec.flatten if (flatten.length > 1) { logger.warn( - s"Multiple filter sync makers!!! choosing first one fsmOptVec=$fsmOptVec") + s"Multiple filter sync makers!!! choosing first one fsmOptVec=$fsmOptVec" + ) flatten.headOption } else { flatten.headOption @@ -249,7 +273,8 @@ class ChainHandler( /** Retrieves immediately children of the given blockHash */ private def getImmediateChildren( - blockHashBE: DoubleSha256DigestBE): Future[Vector[BlockHeaderDb]] = { + blockHashBE: DoubleSha256DigestBE + ): Future[Vector[BlockHeaderDb]] = { getHeader(blockHashBE).flatMap { case Some(header) => getHeadersAtHeight(header.height + 1) @@ -258,23 +283,25 @@ class ChainHandler( } } - /** Retrieves a [[FilterSyncMarker]] respecting the batchSize parameter. If the stopBlockHeader is not within the batchSize parameter - * we walk backwards until we find a header within the batchSize limit + /** Retrieves a [[FilterSyncMarker]] respecting the batchSize parameter. If + * the stopBlockHeader is not within the batchSize parameter we walk + * backwards until we find a header within the batchSize limit */ private def getFilterSyncStopHash( candidateStartHeader: BlockHeaderDb, stopBlockHeader: BlockHeaderDb, - batchSize: Int): Future[Option[FilterSyncMarker]] = { + batchSize: Int + ): Future[Option[FilterSyncMarker]] = { val isInBatchSize = stopBlockHeader.height - candidateStartHeader.height <= batchSize val stopHeaderWithinBatchSizeF = if (isInBatchSize) { Future.successful(stopBlockHeader) } else { - //as an optimization only fetch the last blockheader - //within candidateStartHeight + batchSize , we don't have a way to guarantee - //this hash ultimately ends up connected to stopBlockHeaderDb though - //we have to assume its buried under enough work a reorg is unlikely + // as an optimization only fetch the last blockheader + // within candidateStartHeight + batchSize , we don't have a way to guarantee + // this hash ultimately ends up connected to stopBlockHeaderDb though + // we have to assume its buried under enough work a reorg is unlikely getHeadersAtHeight(candidateStartHeader.height + batchSize) .map(_.head) } @@ -299,18 +326,22 @@ class ChainHandler( val isConnected = hasBothBlockHeaderHashes( blockchain = blockchain, prevBlockHeaderHashBE = candidateStartHeader.hashBE, - stopBlockHeaderHashBE = stopHeaderWithinBatchSize.hashBE) + stopBlockHeaderHashBE = stopHeaderWithinBatchSize.hashBE + ) if (isConnected) { - findNextHeader(candidateStartHeader = candidateStartHeader, - stopBlockHeaderDb = stopHeaderWithinBatchSize, - batchSize = batchSize, - blockchain = blockchain) + findNextHeader( + candidateStartHeader = candidateStartHeader, + stopBlockHeaderDb = stopHeaderWithinBatchSize, + batchSize = batchSize, + blockchain = blockchain + ) } else { Future.successful(None) } case None => val exn = new RuntimeException( - s"Could not form a blockchain with stopHash=$stopBlockHeader.hashBE") + s"Could not form a blockchain with stopHash=$stopBlockHeader.hashBE" + ) Future.failed(exn) } } @@ -318,18 +349,21 @@ class ChainHandler( } /** Finds the next stop hash for a filter sync marker. - * @param candidateStartHeader the first block header whose height will be used in the FilterSyncMarker + * @param candidateStartHeader + * the first block header whose height will be used in the FilterSyncMarker */ private def findNextHeader( candidateStartHeader: BlockHeaderDb, stopBlockHeaderDb: BlockHeaderDb, batchSize: Int, - blockchain: Blockchain): Future[Option[FilterSyncMarker]] = { + blockchain: Blockchain + ): Future[Option[FilterSyncMarker]] = { val hasBothHashes = { - hasBothBlockHeaderHashes(blockchain = blockchain, - prevBlockHeaderHashBE = - candidateStartHeader.hashBE, - stopBlockHeaderHashBE = stopBlockHeaderDb.hashBE) + hasBothBlockHeaderHashes( + blockchain = blockchain, + prevBlockHeaderHashBE = candidateStartHeader.hashBE, + stopBlockHeaderHashBE = stopBlockHeaderDb.hashBE + ) } require( hasBothHashes, @@ -359,10 +393,11 @@ class ChainHandler( private def hasBothBlockHeaderHashes( blockchain: Blockchain, prevBlockHeaderHashBE: DoubleSha256DigestBE, - stopBlockHeaderHashBE: DoubleSha256DigestBE): Boolean = { + stopBlockHeaderHashBE: DoubleSha256DigestBE + ): Boolean = { if (prevBlockHeaderHashBE == DoubleSha256DigestBE.empty) { - //carve out here in the case of genesis header, - //blockchains don't contain a block header with hash 0x000..0000 + // carve out here in the case of genesis header, + // blockchains don't contain a block header with hash 0x000..0000 blockchain.exists(_.hashBE == stopBlockHeaderHashBE) } else { val hasHash1 = @@ -378,7 +413,8 @@ class ChainHandler( override def nextFilterHeaderBatchRange( stopBlockHash: DoubleSha256DigestBE, batchSize: Int, - startHeightOpt: Option[Int]): Future[Option[FilterSyncMarker]] = { + startHeightOpt: Option[Int] + ): Future[Option[FilterSyncMarker]] = { val stopBlockHeaderDbOptF = getHeader(stopBlockHash) for { @@ -389,25 +425,31 @@ class ChainHandler( getFilterSyncMarkerFromStopBlockHeader( stopBlockHeaderDb = stopBlockHeaderDb, startHeightOpt = startHeightOpt, - batchSize = batchSize) + batchSize = batchSize + ) case None => val exn = new RuntimeException( - s"Could not find stopBlockHeaderHash=$stopBlockHash in chaindb") + s"Could not find stopBlockHeaderHash=$stopBlockHash in chaindb" + ) Future.failed(exn) } } } yield fsmOpt } - /** @param stopBlockHeaderDb the block header we are stopping, we walk the blockchain backwards from this blockheader - * @param candidateStartHeadersOpt possible start headers that connect with [[stopBlockHeaderDb]] + /** @param stopBlockHeaderDb + * the block header we are stopping, we walk the blockchain backwards from + * this blockheader + * @param candidateStartHeadersOpt + * possible start headers that connect with [[stopBlockHeaderDb]] * @param batchSize * @return */ private def getFilterSyncMarkerFromStopBlockHeader( stopBlockHeaderDb: BlockHeaderDb, startHeightOpt: Option[Int], - batchSize: Int): Future[Option[FilterSyncMarker]] = { + batchSize: Int + ): Future[Option[FilterSyncMarker]] = { val candidateStartHeadersF: Future[Vector[BlockHeaderDb]] = startHeightOpt match { case Some(height) => getHeadersAtHeight(height) @@ -419,11 +461,11 @@ class ChainHandler( case Some(filter) => getHeadersAtHeight(filter.height + 1).flatMap { headers => if (headers.isEmpty) { - //if we have no headers at height + 1 - //we must be in a reorg scenario + // if we have no headers at height + 1 + // we must be in a reorg scenario getHeadersAtHeight(filter.height) } else { - //remove the bestFilter's block header + // remove the bestFilter's block header val filtered = headers.filter(_.hashBE != filter.blockHashBE) Future.successful(filtered) @@ -445,7 +487,8 @@ class ChainHandler( val flatten = fsmOptVec.flatten if (flatten.length > 1) { logger.warn( - s"Multiple filter sync makers!!! choosing first one fsmOptVec=$fsmOptVec") + s"Multiple filter sync makers!!! choosing first one fsmOptVec=$fsmOptVec" + ) flatten.headOption } else { flatten.headOption @@ -456,13 +499,14 @@ class ChainHandler( /** @inheritdoc */ override def processFilterHeaders( filterHeaders: Vector[FilterHeader], - stopHash: DoubleSha256DigestBE): Future[ChainApi] = { - //find filter headers we have seen before + stopHash: DoubleSha256DigestBE + ): Future[ChainApi] = { + // find filter headers we have seen before val duplicateFilterHeadersF: Future[Vector[CompactFilterHeaderDb]] = { filterHeaderDAO.findByHashes(filterHeaders.map(_.hash.flip)) } - //only add new filter headers to our database + // only add new filter headers to our database val newFilterHeadersF = for { duplicates <- duplicateFilterHeadersF } yield { @@ -484,14 +528,17 @@ class ChainHandler( } yield { if (blockHeaders.size != newFilterHeaders.size) { throw UnknownBlockHash( - s"Filter header batch size does not match block header batch size newFilterHeaders=${newFilterHeaders.size} != blockHeaders=${blockHeaders.size}") + s"Filter header batch size does not match block header batch size newFilterHeaders=${newFilterHeaders.size} != blockHeaders=${blockHeaders.size}" + ) } blockHeaders.indices.toVector.map { i => val blockHeader = blockHeaders(i) val filterHeader = newFilterHeaders(i) - CompactFilterHeaderDbHelper.fromFilterHeader(filterHeader, - blockHeader.hashBE, - blockHeader.height) + CompactFilterHeaderDbHelper.fromFilterHeader( + filterHeader, + blockHeader.hashBE, + blockHeader.height + ) } } @@ -500,7 +547,8 @@ class ChainHandler( _ <- verifyFilterHeaders(filterHeadersToCreate) _ <- filterHeaderDAO.createAll(filterHeadersToCreate) _ <- chainConfig.callBacks.executeOnCompactFilterHeaderConnectedCallbacks( - filterHeadersToCreate) + filterHeadersToCreate + ) } yield { val minHeightOpt = filterHeadersToCreate.minByOption(_.height) val maxHeightOpt = filterHeadersToCreate.maxByOption(_.height) @@ -508,7 +556,8 @@ class ChainHandler( (minHeightOpt, maxHeightOpt) match { case (Some(minHeight), Some(maxHeight)) => logger.info( - s"Processed filters headers from height=${minHeight.height} to ${maxHeight.height}. Best filterheader.blockHash=${maxHeight.blockHashBE.hex}") + s"Processed filters headers from height=${minHeight.height} to ${maxHeight.height}. Best filterheader.blockHash=${maxHeight.blockHashBE.hex}" + ) this // Should never have the case where we have (Some, None) or (None, Some) because that means the vec would be both empty and non empty case (_, _) => @@ -520,13 +569,14 @@ class ChainHandler( /** @inheritdoc */ override def processFilters( - messages: Vector[CompactFilterMessage]): Future[ChainApi] = { - //find filters we have seen before + messages: Vector[CompactFilterMessage] + ): Future[ChainApi] = { + // find filters we have seen before val duplicateFiltersF: Future[Vector[CompactFilterDb]] = { filterDAO.findByBlockHashes(messages.map(_.blockHash.flip)) } - //only add new filters to our database + // only add new filters to our database val newFiltersF = for { duplicates <- duplicateFiltersF } yield messages.filterNot(f => @@ -534,7 +584,8 @@ class ChainHandler( logger.debug( s"processFilters: len=${messages.length} messages.blockHash=${messages - .map(_.blockHash.flip)}") + .map(_.blockHash.flip)}" + ) val filterHeadersF = { for { newFilters <- newFiltersF @@ -543,15 +594,18 @@ class ChainHandler( } yield filterHeaders } - val filtersByBlockHashF: Future[ - Map[DoubleSha256DigestBE, CompactFilterMessage]] = { + val filtersByBlockHashF + : Future[Map[DoubleSha256DigestBE, CompactFilterMessage]] = { for { newFilters <- newFiltersF result = newFilters.groupBy(_.blockHash.flip).map { case (blockHash, messages) => if (messages.size > 1) { - Future.failed(DuplicateFilters( - s"Attempt to process ${messages.length} duplicate filters for blockHashBE=$blockHash")) + Future.failed( + DuplicateFilters( + s"Attempt to process ${messages.length} duplicate filters for blockHashBE=$blockHash" + ) + ) } else { Future.successful((blockHash, messages.head)) } @@ -576,7 +630,8 @@ class ChainHandler( } _ <- filterDAO.createAll(compactFilterDbs) _ <- chainConfig.callBacks.executeOnCompactFilterConnectedCallbacks( - compactFilterDbs) + compactFilterDbs + ) } yield { val minHeightOpt = compactFilterDbs.minByOption(_.height) val maxHeightOpt = compactFilterDbs.maxByOption(_.height) @@ -584,36 +639,40 @@ class ChainHandler( (minHeightOpt, maxHeightOpt) match { case (Some(minHeight), Some(maxHeight)) => logger.info( - s"Processed filters from height=${minHeight.height} to ${maxHeight.height}. Best filter.blockHash=${maxHeight.blockHashBE.hex}") + s"Processed filters from height=${minHeight.height} to ${maxHeight.height}. Best filter.blockHash=${maxHeight.blockHashBE.hex}" + ) this // Should never have the case where we have (Some, None) or (None, Some) because that means the vec would be both empty and non empty case (_, _) => logger.warn( - s"Was unable to process any filters minHeightOpt=$minHeightOpt maxHeightOpt=$maxHeightOpt compactFilterDbs.length=${compactFilterDbs.length} filterHeaders.length=${filterHeaders.length}") + s"Was unable to process any filters minHeightOpt=$minHeightOpt maxHeightOpt=$maxHeightOpt compactFilterDbs.length=${compactFilterDbs.length} filterHeaders.length=${filterHeaders.length}" + ) this } } } - /** Verifies if the previous headers exist either in the batch [[filterHeaders]] - * or in the database, throws if it doesn't + /** Verifies if the previous headers exist either in the batch + * [[filterHeaders]] or in the database, throws if it doesn't */ def verifyFilterHeaders( - filterHeaders: Vector[CompactFilterHeaderDb]): Future[Unit] = { + filterHeaders: Vector[CompactFilterHeaderDb] + ): Future[Unit] = { val byHash = filterHeaders.foldLeft( - Map.empty[DoubleSha256DigestBE, CompactFilterHeaderDb])((acc, fh) => - acc.updated(fh.hashBE, fh)) + Map.empty[DoubleSha256DigestBE, CompactFilterHeaderDb] + )((acc, fh) => acc.updated(fh.hashBE, fh)) val verify = checkFilterHeader(byHash)(_) FutureUtil.sequentially(filterHeaders)(verify).map(_ => ()) } private def checkFilterHeader( - filtersByHash: Map[DoubleSha256DigestBE, CompactFilterHeaderDb])( - filterHeader: CompactFilterHeaderDb): Future[Unit] = { + filtersByHash: Map[DoubleSha256DigestBE, CompactFilterHeaderDb] + )(filterHeader: CompactFilterHeaderDb): Future[Unit] = { def checkHeight( filterHeader: CompactFilterHeaderDb, - prevHeader: CompactFilterHeaderDb): Unit = { + prevHeader: CompactFilterHeaderDb + ): Unit = { require( prevHeader.height == filterHeader.height - 1, s"Unexpected previous filter header's height: ${prevHeader.height} != ${filterHeader.height - 1}" @@ -623,17 +682,23 @@ class ChainHandler( if (filterHeader.hashBE == filterHeader.previousFilterHeaderBE) { Future.failed( new IllegalArgumentException( - s"Filter header cannot reference to itself: ${filterHeader}")) + s"Filter header cannot reference to itself: ${filterHeader}" + ) + ) } else if (filterHeader.height == 0) { Future { require( filterHeader.previousFilterHeaderBE == DoubleSha256DigestBE.empty, - s"Previous filter header hash for the genesis block must be empty: ${filterHeader}") + s"Previous filter header hash for the genesis block must be empty: ${filterHeader}" + ) } } else { if (filterHeader.previousFilterHeaderBE == DoubleSha256DigestBE.empty) { - Future.failed(new IllegalArgumentException( - s"Previous filter header hash for a regular block must not be empty: ${filterHeader}")) + Future.failed( + new IllegalArgumentException( + s"Previous filter header hash for a regular block must not be empty: ${filterHeader}" + ) + ) } else { filtersByHash.get(filterHeader.previousFilterHeaderBE) match { case Some(prevHeader) => @@ -648,7 +713,8 @@ class ChainHandler( checkHeight(filterHeader, prevHeader) case None => throw new IllegalArgumentException( - s"Previous filter header does not exist: $filterHeader") + s"Previous filter header does not exist: $filterHeader" + ) } } } @@ -657,9 +723,8 @@ class ChainHandler( private def findFilterDbFromMessage( filterHeader: CompactFilterHeaderDb, - messagesByBlockHash: Map[ - DoubleSha256DigestBE, - CompactFilterMessage]): CompactFilterDb = { + messagesByBlockHash: Map[DoubleSha256DigestBE, CompactFilterMessage] + ): CompactFilterDb = { messagesByBlockHash.get(filterHeader.blockHashBE) match { case Some(message) => val filterHashBE = CryptoUtil.doubleSHA256(message.filterBytes).flip @@ -671,20 +736,24 @@ class ChainHandler( throw UnknownFilterHash(errMsg) } val filter = - CompactFilterDbHelper.fromFilterBytes(message.filterBytes, - filterHeader.blockHashBE, - filterHeader.height) + CompactFilterDbHelper.fromFilterBytes( + message.filterBytes, + filterHeader.blockHashBE, + filterHeader.height + ) filter case None => throw UnknownBlockHash( - s"Unknown block hash ${filterHeader.blockHashBE}") + s"Unknown block hash ${filterHeader.blockHashBE}" + ) } } /** @inheritdoc */ override def processCheckpoints( checkpoints: Vector[DoubleSha256DigestBE], - blockHash: DoubleSha256DigestBE): Future[ChainApi] = { + blockHash: DoubleSha256DigestBE + ): Future[ChainApi] = { val blockHeadersF: Future[Seq[BlockHeaderDb]] = Future .traverse(checkpoints.indices.toVector) { i => blockHeaderDAO.getAtHeight(i * 1000) @@ -702,17 +771,20 @@ class ChainHandler( res.updated(blockHeader.hashBE, filterHeaderHash) } - ChainHandler(blockHeaderDAO = blockHeaderDAO, - filterHeaderDAO = filterHeaderDAO, - filterDAO = filterDAO, - stateDAO = stateDAO, - blockFilterCheckpoints = updatedCheckpoints) + ChainHandler( + blockHeaderDAO = blockHeaderDAO, + filterHeaderDAO = filterHeaderDAO, + filterDAO = filterDAO, + stateDAO = stateDAO, + blockFilterCheckpoints = updatedCheckpoints + ) } } /** @inheritdoc */ override def getFilter( - blockHash: DoubleSha256DigestBE): Future[Option[CompactFilterDb]] = { + blockHash: DoubleSha256DigestBE + ): Future[Option[CompactFilterDb]] = { filterDAO.findByBlockHash(blockHash) } @@ -727,12 +799,13 @@ class ChainHandler( /** @inheritdoc */ override def getFilterHeadersAtHeight( - height: Int): Future[Vector[CompactFilterHeaderDb]] = + height: Int + ): Future[Vector[CompactFilterHeaderDb]] = filterHeaderDAO.getAtHeight(height) protected def getBestFilterHeaderWithChains( - blockchains: Vector[Blockchain]): Future[ - Option[CompactFilterHeaderDb]] = { + blockchains: Vector[Blockchain] + ): Future[Option[CompactFilterHeaderDb]] = { val bestFilterHeadersInChain: Future[Option[CompactFilterHeaderDb]] = { val bestChainOpt = blockchains.maxByOption(_.tip.chainWork) bestChainOpt match { @@ -771,29 +844,31 @@ class ChainHandler( } /** This method retrieves the best [[CompactFilterHeaderDb]] from the database - * without any blockchain context, and then uses the [[CompactFilterHeaderDb.blockHashBE]] - * to query our block headers database looking for a filter header that is in the best chain + * without any blockchain context, and then uses the + * [[CompactFilterHeaderDb.blockHashBE]] to query our block headers database + * looking for a filter header that is in the best chain * @return */ - private def bestFilterHeaderSearch(): Future[ - Option[CompactFilterHeaderDb]] = { + private def bestFilterHeaderSearch() + : Future[Option[CompactFilterHeaderDb]] = { val bestFilterHeaderOptF = filterHeaderDAO.getBestFilterHeader - //get best blockchain around our latest filter header + // get best blockchain around our latest filter header val blockchainOptF: Future[Option[Blockchain]] = { for { bestFilterHeaderOpt <- bestFilterHeaderOptF blockchains <- { bestFilterHeaderOpt match { case Some(bestFilterHeader) => - //get blockchains from our current best filter header to - //the next POW of interval, this should be enough to determine - //what is the best chain! + // get blockchains from our current best filter header to + // the next POW of interval, this should be enough to determine + // what is the best chain! blockHeaderDAO.getBlockchainsBetweenHeights( from = bestFilterHeader.height - chainConfig.chain.difficultyChangeInterval, to = - bestFilterHeader.height + chainConfig.chain.difficultyChangeInterval) + bestFilterHeader.height + chainConfig.chain.difficultyChangeInterval + ) case None => Future.successful(Vector.empty) } @@ -826,7 +901,8 @@ class ChainHandler( /** @inheritdoc */ override def getFilterHeader( - blockHash: DoubleSha256DigestBE): Future[Option[CompactFilterHeaderDb]] = + blockHash: DoubleSha256DigestBE + ): Future[Option[CompactFilterHeaderDb]] = filterHeaderDAO.findByBlockHash(blockHash) /** @inheritdoc */ @@ -836,7 +912,8 @@ class ChainHandler( /** @inheritdoc */ override def getFiltersAtHeight( - height: Int): Future[Vector[CompactFilterDb]] = + height: Int + ): Future[Vector[CompactFilterDb]] = filterDAO.getAtHeight(height) /** @inheritdoc */ @@ -849,7 +926,8 @@ class ChainHandler( header .map(_.height) .getOrElse( - throw UnknownBlockHash(s"Unknown block hash ${blockHash.hash}")) + throw UnknownBlockHash(s"Unknown block hash ${blockHash.hash}") + ) } case blockTime: BlockStamp.BlockTime => Future.failed(new RuntimeException(s"Not implemented: $blockTime")) @@ -860,12 +938,14 @@ class ChainHandler( /** @inheritdoc */ override def getBlockHeight( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = getHeader(blockHash).map(_.map(_.height)) /** @inheritdoc */ override def getNumberOfConfirmations( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = { + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = { getBlockHeight(blockHash).flatMap { case None => FutureUtil.none case Some(blockHeight) => @@ -891,7 +971,8 @@ class ChainHandler( override def getFiltersBetweenHeights( startHeight: Int, - endHeight: Int): Future[Vector[FilterResponse]] = + endHeight: Int + ): Future[Vector[FilterResponse]] = filterDAO .getBetweenHeights(startHeight, endHeight) .map(dbos => @@ -901,18 +982,23 @@ class ChainHandler( /** @inheritdoc */ override def getHeadersBetween( from: BlockHeaderDb, - to: BlockHeaderDb): Future[Vector[BlockHeaderDb]] = { + to: BlockHeaderDb + ): Future[Vector[BlockHeaderDb]] = { logger.debug(s"Finding headers from=$from to=$to") def loop( currentF: Future[BlockHeaderDb], - accum: Vector[BlockHeaderDb]): Future[Vector[BlockHeaderDb]] = { + accum: Vector[BlockHeaderDb] + ): Future[Vector[BlockHeaderDb]] = { currentF.flatMap { current => if (current.hashBE == from.hashBE) { Future.successful(current +: accum) } else { val nextOptF = getHeader(current.previousBlockHashBE) - val nextF = nextOptF.map(_.getOrElse( - sys.error(s"Could not find header=${current.previousBlockHashBE}"))) + val nextF = nextOptF.map( + _.getOrElse( + sys.error(s"Could not find header=${current.previousBlockHashBE}") + ) + ) loop(nextF, current +: accum) } } @@ -945,7 +1031,8 @@ class ChainHandler( private def calcChainWork( remainingHeaders: Vector[BlockHeaderDb], accum: Vector[BlockHeaderDb], - lastHeaderWithWorkInDb: BlockHeaderDb): Vector[BlockHeaderDb] = { + lastHeaderWithWorkInDb: BlockHeaderDb + ): Vector[BlockHeaderDb] = { if (remainingHeaders.isEmpty) { accum } else { @@ -957,51 +1044,59 @@ class ChainHandler( prevWork case None => // this should be the case where the accum is - //empty, so this header is the last one we have - //stored in the database + // empty, so this header is the last one we have + // stored in the database lastHeaderWithWorkInDb.chainWork } } val newChainWork = currentChainWork + Pow.getBlockProof(header.blockHeader) val newHeader = header.copy(chainWork = newChainWork) - calcChainWork(remainingHeaders.tail, - accum :+ newHeader, - lastHeaderWithWorkInDb) + calcChainWork( + remainingHeaders.tail, + accum :+ newHeader, + lastHeaderWithWorkInDb + ) } } private def getBatchForRecalc( startHeight: Int, maxHeight: Int, - batchSize: Int): Future[Vector[Blockchain]] = { + batchSize: Int + ): Future[Vector[Blockchain]] = { val batchEndHeight = Math.min(maxHeight, startHeight + batchSize - 1) val headersToCalcF = { logger.trace(s"Fetching from=$startHeight to=$batchEndHeight") - blockHeaderDAO.getBlockchainsBetweenHeights(from = startHeight, - to = batchEndHeight) + blockHeaderDAO.getBlockchainsBetweenHeights( + from = startHeight, + to = batchEndHeight + ) } headersToCalcF } - /** Creates [[numBatches]] of requests to the database fetching [[batchSize]] headers - * starting at [[batchStartHeight]]. These are executed in parallel. After all are fetched - * we join them into one future and return it. + /** Creates [[numBatches]] of requests to the database fetching [[batchSize]] + * headers starting at [[batchStartHeight]]. These are executed in parallel. + * After all are fetched we join them into one future and return it. */ private def batchAndGetBlockchains( batchSize: Int, batchStartHeight: Int, maxHeight: Int, - numBatches: Int): Future[Vector[Blockchain]] = { + numBatches: Int + ): Future[Vector[Blockchain]] = { var counter = batchStartHeight val range = 0.until(numBatches) val batchesNested: Vector[Future[Vector[Blockchain]]] = range.map { _ => val f = if (counter <= maxHeight) { - getBatchForRecalc(startHeight = counter, - maxHeight = maxHeight, - batchSize = batchSize) + getBatchForRecalc( + startHeight = counter, + maxHeight = maxHeight, + batchSize = batchSize + ) } else { Future.successful(Vector.empty) } @@ -1016,7 +1111,8 @@ class ChainHandler( private def runRecalculateChainWork( maxHeight: Int, - lastHeader: BlockHeaderDb): Future[Vector[BlockHeaderDb]] = { + lastHeader: BlockHeaderDb + ): Future[Vector[BlockHeaderDb]] = { val currentHeight = lastHeader.height val numBatches = 1 val batchSize = @@ -1037,34 +1133,38 @@ class ChainHandler( headersToCalc <- headersToCalcF _ = headersToCalc.headOption.map { h => logger.trace( - s"Recalculating chain work... current height: ${h.height} maxHeight=$maxHeight") + s"Recalculating chain work... current height: ${h.height} maxHeight=$maxHeight" + ) } headersWithWork = { headersToCalc.flatMap { chain => - calcChainWork(remainingHeaders = chain.headers.sortBy(_.height), - accum = Vector.empty, - lastHeaderWithWorkInDb = lastHeader) + calcChainWork( + remainingHeaders = chain.headers.sortBy(_.height), + accum = Vector.empty, + lastHeaderWithWorkInDb = lastHeader + ) } } - //unfortunately on sqlite there is a bottle neck here - //sqlite allows you to read in parallel but only write - //sequentially https://stackoverflow.com/a/23350768/967713 - //so while it looks like we are executing in parallel - //in reality there is only one thread that can write to the db - //at a single time + // unfortunately on sqlite there is a bottle neck here + // sqlite allows you to read in parallel but only write + // sequentially https://stackoverflow.com/a/23350768/967713 + // so while it looks like we are executing in parallel + // in reality there is only one thread that can write to the db + // at a single time _ = - logger.trace(s"Upserting from height=${headersWithWork.headOption.map( - _.height)} to height=${headersWithWork.lastOption.map(_.height)}") + logger.trace( + s"Upserting from height=${headersWithWork.headOption + .map(_.height)} to height=${headersWithWork.lastOption.map(_.height)}" + ) _ <- FutureUtil.batchExecute( headersWithWork, blockHeaderDAO.upsertAll, Vector.empty, batchSize ) - _ = logger.trace( - s"Done upserting from height=${headersWithWork.headOption.map( - _.height)} to height=${headersWithWork.lastOption.map(_.height)}") + _ = logger.trace(s"Done upserting from height=${headersWithWork.headOption + .map(_.height)} to height=${headersWithWork.lastOption.map(_.height)}") next <- runRecalculateChainWork(maxHeight, headersWithWork.last) } yield { next @@ -1117,7 +1217,8 @@ class ChainHandler( /** Calculates the chain work for the genesis header */ private def calculateChainWorkGenesisBlock( - genesisHeader: BlockHeaderDb): Future[BlockHeaderDb] = { + genesisHeader: BlockHeaderDb + ): Future[BlockHeaderDb] = { val expectedWork = Pow.getBlockProof(genesisHeader.blockHeader) val genesisWithWork = genesisHeader.copy(chainWork = expectedWork) blockHeaderDAO.update(genesisWithWork) @@ -1129,12 +1230,15 @@ class ChainHandler( filterDAO: CompactFilterDAO = filterDAO, stateDAO: ChainStateDescriptorDAO = stateDAO, blockFilterCheckpoints: Map[DoubleSha256DigestBE, DoubleSha256DigestBE] = - blockFilterCheckpoints): ChainHandler = { - new ChainHandler(blockHeaderDAO = blockHeaderDAO, - filterHeaderDAO = filterHeaderDAO, - filterDAO = filterDAO, - stateDAO = stateDAO, - blockFilterCheckpoints = blockFilterCheckpoints) + blockFilterCheckpoints + ): ChainHandler = { + new ChainHandler( + blockHeaderDAO = blockHeaderDAO, + filterHeaderDAO = filterHeaderDAO, + filterDAO = filterDAO, + stateDAO = stateDAO, + blockFilterCheckpoints = blockFilterCheckpoints + ) } def toChainHandlerCached: Future[ChainHandlerCached] = { @@ -1165,8 +1269,8 @@ class ChainHandler( @tailrec def getNTopHeaders( n: Int, - acc: Vector[Future[Option[BlockHeaderDb]]]): Vector[ - Future[Option[BlockHeaderDb]]] = { + acc: Vector[Future[Option[BlockHeaderDb]]] + ): Vector[Future[Option[BlockHeaderDb]]] = { if (n == 1) acc else { @@ -1178,8 +1282,10 @@ class ChainHandler( } } - val top11 = getNTopHeaders(nMedianTimeSpan, - Vector(getBestBlockHeader().map(Option.apply))) + val top11 = getNTopHeaders( + nMedianTimeSpan, + Vector(getBestBlockHeader().map(Option.apply)) + ) Future .sequence(top11) @@ -1200,7 +1306,7 @@ class ChainHandler( case Some(ibd) => ibd.isIBDRunning case None => - //if we do not have the state descriptor in the database, default to true on IBD + // if we do not have the state descriptor in the database, default to true on IBD true } } @@ -1211,7 +1317,7 @@ class ChainHandler( isSyncing <- isSyncingF _ <- { if (isSyncing == value) { - //do nothing as we are already at this state + // do nothing as we are already at this state Future.unit } else { updateSyncingAndExecuteCallback(value) @@ -1224,8 +1330,10 @@ class ChainHandler( override def isTipStale(): Future[Boolean] = { getBestBlockHeader().map { blockHeaderDb => - NetworkUtil.isBlockHeaderStale(blockHeaderDb.blockHeader, - chainConfig.chain) + NetworkUtil.isBlockHeaderStale( + blockHeaderDb.blockHeader, + chainConfig.chain + ) } } @@ -1235,11 +1343,12 @@ class ChainHandler( isIBDOpt <- isIBDF _ <- { if (isIBDOpt.isDefined && isIBDOpt.get.isIBDRunning == value) { - //do nothing as we are already at this state + // do nothing as we are already at this state Future.unit } else if (isIBDOpt.isDefined && !isIBDOpt.get.isIBDRunning && value) { logger.warn( - s"Can only do IBD once, cannot set flag to true when database flag is false.") + s"Can only do IBD once, cannot set flag to true when database flag is false." + ) Future.unit } else { stateDAO.updateIsIbd(value) @@ -1273,24 +1382,30 @@ object ChainHandler { filterHeaderDAO: CompactFilterHeaderDAO, filterDAO: CompactFilterDAO, stateDAO: ChainStateDescriptorDAO, - blockFilterCheckpoints: Map[DoubleSha256DigestBE, DoubleSha256DigestBE])( - implicit + blockFilterCheckpoints: Map[DoubleSha256DigestBE, DoubleSha256DigestBE] + )(implicit ec: ExecutionContext, - chainAppConfig: ChainAppConfig): ChainHandler = { - new ChainHandler(blockHeaderDAO, - filterHeaderDAO, - filterDAO, - stateDAO, - blockFilterCheckpoints) + chainAppConfig: ChainAppConfig + ): ChainHandler = { + new ChainHandler( + blockHeaderDAO, + filterHeaderDAO, + filterDAO, + stateDAO, + blockFilterCheckpoints + ) } - def fromChainHandlerCached(cached: ChainHandlerCached)(implicit - ec: ExecutionContext): ChainHandler = { - new ChainHandler(blockHeaderDAO = cached.blockHeaderDAO, - filterHeaderDAO = cached.filterHeaderDAO, - filterDAO = cached.filterDAO, - stateDAO = cached.stateDAO, - blockFilterCheckpoints = Map.empty)(cached.chainConfig, ec) + def fromChainHandlerCached( + cached: ChainHandlerCached + )(implicit ec: ExecutionContext): ChainHandler = { + new ChainHandler( + blockHeaderDAO = cached.blockHeaderDAO, + filterHeaderDAO = cached.filterHeaderDAO, + filterDAO = cached.filterDAO, + stateDAO = cached.stateDAO, + blockFilterCheckpoints = Map.empty + )(cached.chainConfig, ec) } /** Constructs a [[ChainHandler chain handler]] from the state in the database @@ -1300,14 +1415,18 @@ object ChainHandler { blockHeaderDAO: BlockHeaderDAO, filterHeaderDAO: CompactFilterHeaderDAO, filterDAO: CompactFilterDAO, - stateDAO: ChainStateDescriptorDAO)(implicit + stateDAO: ChainStateDescriptorDAO + )(implicit ec: ExecutionContext, - chainConfig: ChainAppConfig): ChainHandler = { - new ChainHandler(blockHeaderDAO = blockHeaderDAO, - filterHeaderDAO = filterHeaderDAO, - filterDAO = filterDAO, - stateDAO = stateDAO, - blockFilterCheckpoints = Map.empty) + chainConfig: ChainAppConfig + ): ChainHandler = { + new ChainHandler( + blockHeaderDAO = blockHeaderDAO, + filterHeaderDAO = filterHeaderDAO, + filterDAO = filterDAO, + stateDAO = stateDAO, + blockFilterCheckpoints = Map.empty + ) } def apply( @@ -1317,31 +1436,40 @@ object ChainHandler { stateDAO: ChainStateDescriptorDAO )(implicit ec: ExecutionContext, - chainConfig: ChainAppConfig): ChainHandler = { - new ChainHandler(blockHeaderDAO = blockHeaderDAO, - filterHeaderDAO = filterHeaderDAO, - filterDAO = filterDAO, - stateDAO = stateDAO, - blockFilterCheckpoints = Map.empty) + chainConfig: ChainAppConfig + ): ChainHandler = { + new ChainHandler( + blockHeaderDAO = blockHeaderDAO, + filterHeaderDAO = filterHeaderDAO, + filterDAO = filterDAO, + stateDAO = stateDAO, + blockFilterCheckpoints = Map.empty + ) } def fromDatabase()(implicit ec: ExecutionContext, - chainConfig: ChainAppConfig): ChainHandler = { + chainConfig: ChainAppConfig + ): ChainHandler = { lazy val blockHeaderDAO = BlockHeaderDAO() lazy val filterHeaderDAO = CompactFilterHeaderDAO() lazy val filterDAO = CompactFilterDAO() lazy val stateDAO = ChainStateDescriptorDAO() - ChainHandler.fromDatabase(blockHeaderDAO = blockHeaderDAO, - filterHeaderDAO = filterHeaderDAO, - filterDAO = filterDAO, - stateDAO = stateDAO) + ChainHandler.fromDatabase( + blockHeaderDAO = blockHeaderDAO, + filterHeaderDAO = filterHeaderDAO, + filterDAO = filterDAO, + stateDAO = stateDAO + ) } - /** Converts a [[ChainHandler]] to [[ChainHandlerCached]] by calling [[BlockHeaderDAO.getBlockchains()]] */ - def toChainHandlerCached(chainHandler: ChainHandler)(implicit - ec: ExecutionContext): Future[ChainHandlerCached] = { + /** Converts a [[ChainHandler]] to [[ChainHandlerCached]] by calling + * [[BlockHeaderDAO.getBlockchains()]] + */ + def toChainHandlerCached( + chainHandler: ChainHandler + )(implicit ec: ExecutionContext): Future[ChainHandlerCached] = { val blockchainsF = chainHandler.blockHeaderDAO.getBlockchains() for { blockchains <- blockchainsF diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainHandlerCached.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainHandlerCached.scala index 21d2054b8c..563e11266f 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainHandlerCached.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/ChainHandlerCached.scala @@ -14,10 +14,10 @@ import org.bitcoins.crypto.DoubleSha256DigestBE import scala.concurrent.{ExecutionContext, Future} -/** An optimized version of [[ChainHandler]] that avoids database reads - * for determining what the best block header is. This should be used - * with care as it is possible the cached [[blockchains]] may be out of date! - * Unless you know what you are doing, you should probably use [[ChainHandler]] +/** An optimized version of [[ChainHandler]] that avoids database reads for + * determining what the best block header is. This should be used with care as + * it is possible the cached [[blockchains]] may be out of date! Unless you + * know what you are doing, you should probably use [[ChainHandler]] */ case class ChainHandlerCached( override val blockHeaderDAO: BlockHeaderDAO, @@ -27,14 +27,18 @@ case class ChainHandlerCached( blockchains: Vector[Blockchain], override val blockFilterCheckpoints: Map[ DoubleSha256DigestBE, - DoubleSha256DigestBE])(implicit + DoubleSha256DigestBE + ] +)(implicit override val chainConfig: ChainAppConfig, - executionContext: ExecutionContext) - extends ChainHandler(blockHeaderDAO, - filterHeaderDAO, - filterDAO, - stateDAO, - blockFilterCheckpoints) { + executionContext: ExecutionContext +) extends ChainHandler( + blockHeaderDAO, + filterHeaderDAO, + filterDAO, + stateDAO, + blockFilterCheckpoints + ) { /** Gets the best block header from the given [[blockchains]] parameter */ override def getBestBlockHeader(): Future[BlockHeaderDb] = { @@ -44,7 +48,8 @@ case class ChainHandlerCached( } override def processHeaders( - headers: Vector[BlockHeader]): Future[ChainApi] = { + headers: Vector[BlockHeader] + ): Future[ChainApi] = { processHeadersWithChains(headers = headers, blockchains = blockchains) } @@ -59,17 +64,21 @@ object ChainHandlerCached { blockHeaderDAO: BlockHeaderDAO, filterHeaderDAO: CompactFilterHeaderDAO, filterDAO: CompactFilterDAO, - stateDAO: ChainStateDescriptorDAO)(implicit + stateDAO: ChainStateDescriptorDAO + )(implicit ec: ExecutionContext, - chainConfig: ChainAppConfig): Future[ChainHandlerCached] = { + chainConfig: ChainAppConfig + ): Future[ChainHandlerCached] = { val bestChainsF = blockHeaderDAO.getBlockchains() bestChainsF.map(chains => - new ChainHandlerCached(blockHeaderDAO = blockHeaderDAO, - filterHeaderDAO = filterHeaderDAO, - filterDAO = filterDAO, - stateDAO = stateDAO, - blockchains = chains, - blockFilterCheckpoints = Map.empty)) + new ChainHandlerCached( + blockHeaderDAO = blockHeaderDAO, + filterHeaderDAO = filterHeaderDAO, + filterDAO = filterDAO, + stateDAO = stateDAO, + blockchains = chains, + blockFilterCheckpoints = Map.empty + )) } } diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/ConnectTipResult.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/ConnectTipResult.scala index 7a04122d2f..26a6ae17c8 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/ConnectTipResult.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/ConnectTipResult.scala @@ -4,14 +4,14 @@ import org.bitcoins.chain.validation.TipUpdateResult import org.bitcoins.core.api.chain.db.BlockHeaderDb import org.bitcoins.core.protocol.blockchain.BlockHeader -/** The result indicating how the [[org.bitcoins.chain.validation.TipUpdateResult TipUpdateResult]] - * modified the chain. +/** The result indicating how the + * [[org.bitcoins.chain.validation.TipUpdateResult TipUpdateResult]] modified + * the chain. * * We can * - * 1. Extend the chain - * 2. Reorg the chain - * 3. Fail to connect to anything in the chain + * 1. Extend the chain 2. Reorg the chain 3. Fail to connect to anything in + * the chain */ sealed trait ConnectTipResult { def tipUpdateResult: TipUpdateResult @@ -25,8 +25,8 @@ object ConnectTipResult { /** Indicates we sucuessfully extended our chain by one block */ case class ExtendChain( tipUpdateResult: TipUpdateResult.Success, - newChain: Blockchain) - extends ConnectTipResult { + newChain: Blockchain + ) extends ConnectTipResult { require( headerDb == newChain.tip, s"Cannot extend chain without having tipUpdate be our best tip, tipUpdateResult=${tipUpdateResult.header} chain.tip=${newChain.tip}" @@ -34,23 +34,27 @@ object ConnectTipResult { lazy val headerDb: BlockHeaderDb = tipUpdateResult.headerDb } - /** Means we had a reorg happen, aka the header was connected to - * something that was _not_ our previous best tip - * @param tipUpdateResult the successful connection - * @param newChain the new chain where the best tip is the header we passed in + /** Means we had a reorg happen, aka the header was connected to something + * that was _not_ our previous best tip + * @param tipUpdateResult + * the successful connection + * @param newChain + * the new chain where the best tip is the header we passed in */ case class Reorg( tipUpdateResult: TipUpdateResult.Success, - newChain: Blockchain) - extends ConnectTipResult { + newChain: Blockchain + ) extends ConnectTipResult { require( headerDb == newChain.tip, - s"Cannot reorg without having tipUpdate be our best tip, tipUpdateResult=${tipUpdateResult.header} chain.tip=${newChain.tip}") + s"Cannot reorg without having tipUpdate be our best tip, tipUpdateResult=${tipUpdateResult.header} chain.tip=${newChain.tip}" + ) lazy val headerDb: BlockHeaderDb = tipUpdateResult.headerDb } - /** Means we could not connect the header to anything in the given blockchain */ + /** Means we could not connect the header to anything in the given blockchain + */ case class BadTip(tipUpdateResult: TipUpdateResult.Failure) extends ConnectTipResult diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/ChainSync.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/ChainSync.scala index b0ac93140b..99b30b1948 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/ChainSync.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/ChainSync.scala @@ -11,25 +11,29 @@ import scala.concurrent.{ExecutionContext, Future} abstract class ChainSync extends ChainVerificationLogger { - /** This method checks if our chain handler has the tip of the blockchain as an external source - * If we do not have the same chain, we sync our chain handler until we are at the same best block hash - * @param chainHandler our internal chain handler - * @param getBlockHeaderFunc a function that we can call to retrieve a block - * @param getBestBlockHashFunc a function that can call a third party source (bitcoind, block explorer etc) - * to retrieve what the best block is on the blockchain + /** This method checks if our chain handler has the tip of the blockchain as + * an external source If we do not have the same chain, we sync our chain + * handler until we are at the same best block hash + * @param chainHandler + * our internal chain handler + * @param getBlockHeaderFunc + * a function that we can call to retrieve a block + * @param getBestBlockHashFunc + * a function that can call a third party source (bitcoind, block explorer + * etc) to retrieve what the best block is on the blockchain * @param ec * @return */ def sync( chainHandler: ChainHandler, getBlockHeaderFunc: DoubleSha256DigestBE => Future[BlockHeader], - getBestBlockHashFunc: () => Future[DoubleSha256DigestBE])(implicit - ec: ExecutionContext): Future[ChainApi] = { + getBestBlockHashFunc: () => Future[DoubleSha256DigestBE] + )(implicit ec: ExecutionContext): Future[ChainApi] = { val currentTipsF: Future[Vector[BlockHeaderDb]] = { chainHandler.getBestChainTips() } - //TODO: We are implicitly trusting whatever + // TODO: We are implicitly trusting whatever // getBestBlockHashFunc returns as the best chain // and we don't ever even have to have this connect // with our current best tips @@ -41,10 +45,12 @@ abstract class ChainSync extends ChainVerificationLogger { val updatedChainApi = bestBlockHashF.flatMap { bestBlockHash => currentTipsF.flatMap { tips => - syncTips(chainApi = chainHandler, - tips = tips, - bestBlockHash = bestBlockHash, - getBlockHeaderFunc = getBlockHeaderFunc) + syncTips( + chainApi = chainHandler, + tips = tips, + bestBlockHash = bestBlockHash, + getBlockHeaderFunc = getBlockHeaderFunc + ) } } @@ -52,12 +58,16 @@ abstract class ChainSync extends ChainVerificationLogger { } - /** Keeps walking backwards on the chain until we match one - * of the tips we have in our chain - * @param chainApi the chain api that represents our current chain state - * @param tips the best block header we know about - * @param bestBlockHash the best block header seen by our third party data source - * @param getBlockHeaderFunc how we can retrieve block headers + /** Keeps walking backwards on the chain until we match one of the tips we + * have in our chain + * @param chainApi + * the chain api that represents our current chain state + * @param tips + * the best block header we know about + * @param bestBlockHash + * the best block header seen by our third party data source + * @param getBlockHeaderFunc + * how we can retrieve block headers * @param ec * @return */ @@ -65,24 +75,25 @@ abstract class ChainSync extends ChainVerificationLogger { chainApi: ChainApi, tips: Vector[BlockHeaderDb], bestBlockHash: DoubleSha256DigestBE, - getBlockHeaderFunc: DoubleSha256DigestBE => Future[BlockHeader])(implicit - ec: ExecutionContext): Future[ChainApi] = { + getBlockHeaderFunc: DoubleSha256DigestBE => Future[BlockHeader] + )(implicit ec: ExecutionContext): Future[ChainApi] = { require(tips.nonEmpty, s"Cannot sync without the genesis block") - //we need to walk backwards on the chain until we get to one of our tips + // we need to walk backwards on the chain until we get to one of our tips val tipsBH = tips.map(_.blockHeader) def loop( lastHeaderF: Future[BlockHeader], - accum: Vector[BlockHeader]): Future[Vector[BlockHeader]] = { + accum: Vector[BlockHeader] + ): Future[Vector[BlockHeader]] = { lastHeaderF.flatMap { lastHeader => if (tipsBH.contains(lastHeader)) { - //means we have synced back to a block that we know + // means we have synced back to a block that we know Future.successful(accum) } else { logger.debug(s"Last header=${lastHeader.hashBE.hex}") - //we don't know this block, so we need to keep walking backwards - //to find a block a we know + // we don't know this block, so we need to keep walking backwards + // to find a block a we know val newLastHeaderF = getBlockHeaderFunc(lastHeader.previousBlockHashBE) @@ -96,27 +107,29 @@ abstract class ChainSync extends ChainVerificationLogger { bestHeaderF.map { bestHeader => logger.debug( s"Best tip from third party=${bestHeader.hashBE.hex} currentTips=${tips - .map(_.hashBE.hex)}") + .map(_.hashBE.hex)}" + ) } - //one sanity check to make sure we aren't _ahead_ of our data source + // one sanity check to make sure we aren't _ahead_ of our data source val hasBlockHashF = chainApi.getHeader(bestBlockHash) hasBlockHashF.flatMap { hasBlockHashF: Option[BlockHeaderDb] => if (hasBlockHashF.isDefined) { - //if we have the best block hash in our - //chainstate already, we don't need to search - //for it again! + // if we have the best block hash in our + // chainstate already, we don't need to search + // for it again! Future.successful(chainApi) } else { - //this represents all headers we have received from our external data source - //and need to process with our chain handler + // this represents all headers we have received from our external data source + // and need to process with our chain handler val headersToSyncF = loop(bestHeaderF, Vector.empty) - //now we are going to add them to our chain and return the chain api + // now we are going to add them to our chain and return the chain api headersToSyncF.flatMap { headers => logger.info( - s"Attempting to sync ${headers.length} blockheader to our chainstate") + s"Attempting to sync ${headers.length} blockheader to our chainstate" + ) chainApi.processHeaders(headers) } } diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/FilterSync.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/FilterSync.scala index 49f0e67196..39a90719fc 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/FilterSync.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/FilterSync.scala @@ -12,39 +12,44 @@ import org.bitcoins.crypto.DoubleSha256Digest import scala.collection.mutable import scala.concurrent.{ExecutionContext, Future} -/** A class that is meant to expose and api to sync - * [[GolombFilter]]s and [[FilterHeader]]s from an external - * data source. The important thing to implement is +/** A class that is meant to expose and api to sync [[GolombFilter]]s and + * [[FilterHeader]]s from an external data source. The important thing to + * implement is * {{{ * getFilterFunc: BlockHeader => Future[GolombFilter] * }}} * which will allow us to sync our internal filters against. * - * It should be noted you are entirely trusting the provider - * of the `getFilterFunc` as you aren't able to validate the result - * against another peer that as BIP157 specifies + * It should be noted you are entirely trusting the provider of the + * `getFilterFunc` as you aren't able to validate the result against another + * peer that as BIP157 specifies * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#client-operation]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#client-operation]] */ abstract class FilterSync extends ChainVerificationLogger { def syncFilters( chainApi: ChainApi, getFilterFunc: BlockHeader => Future[FilterWithHeaderHash], - batchSize: Int = 25)(implicit + batchSize: Int = 25 + )(implicit ec: ExecutionContext, - chainAppConfig: ChainAppConfig): Future[ChainApi] = { + chainAppConfig: ChainAppConfig + ): Future[ChainApi] = { val ourBestFilterHeaderOptF = chainApi.getBestFilterHeader() val ourBestBlockHeaderF = chainApi.getBestBlockHeader() for { oursOpt <- ourBestFilterHeaderOptF ourBestBlockHeader <- ourBestBlockHeaderF syncedChainApi <- { - syncFiltersToTip(chainApi = chainApi, - ourBestHeader = ourBestBlockHeader, - ourBestFilterHeaderOpt = oursOpt, - getFilterFunc = getFilterFunc, - batchSize) + syncFiltersToTip( + chainApi = chainApi, + ourBestHeader = ourBestBlockHeader, + ourBestFilterHeaderOpt = oursOpt, + getFilterFunc = getFilterFunc, + batchSize + ) } } yield { syncedChainApi @@ -54,13 +59,19 @@ abstract class FilterSync extends ChainVerificationLogger { private case class BlockFilterAggregated( filterHeader: FilterHeader, filter: GolombFilter, - blockHeader: BlockHeader) + blockHeader: BlockHeader + ) /** Syncs our best filter header to our best block hash - * @param chainApi our current chain state - * @param ourBestHeader the block header we are going to sync filters up until - * @param ourBestFilterHeaderOpt the best filter header we have - * @param getFilterFunc given a block hash it retrieves filter associated with that hash from our external source + * @param chainApi + * our current chain state + * @param ourBestHeader + * the block header we are going to sync filters up until + * @param ourBestFilterHeaderOpt + * the best filter header we have + * @param getFilterFunc + * given a block hash it retrieves filter associated with that hash from + * our external source * @param ec * @return */ @@ -69,9 +80,11 @@ abstract class FilterSync extends ChainVerificationLogger { ourBestHeader: BlockHeaderDb, ourBestFilterHeaderOpt: Option[CompactFilterHeaderDb], getFilterFunc: BlockHeader => Future[FilterWithHeaderHash], - batchSize: Int)(implicit + batchSize: Int + )(implicit ec: ExecutionContext, - chainAppConfig: ChainAppConfig): Future[ChainApi] = { + chainAppConfig: ChainAppConfig + ): Future[ChainApi] = { val firstBlockHash = ourBestFilterHeaderOpt match { case None => logger.info(s"Found no filters in the database, syncing from genesis") @@ -81,24 +94,28 @@ abstract class FilterSync extends ChainVerificationLogger { } if (firstBlockHash == ourBestHeader.hashBE) { logger.info( - s"Our filters are synced with our peers filters, both at blockHash=${firstBlockHash.hex}") + s"Our filters are synced with our peers filters, both at blockHash=${firstBlockHash.hex}" + ) Future.successful(chainApi) } else { logger.info( - s"Beginning sync for filters from filterheader=${firstBlockHash.hex} to blockheader=${ourBestHeader.hashBE.hex}") - //let's fetch all missing filter headers first + s"Beginning sync for filters from filterheader=${firstBlockHash.hex} to blockheader=${ourBestHeader.hashBE.hex}" + ) + // let's fetch all missing filter headers first val bestFilterBlockHeaderF = chainApi.getHeader(firstBlockHash) val headersMissingFiltersF = for { bestFilterBlockHeader <- bestFilterBlockHeaderF - missing <- chainApi.getHeadersBetween(from = bestFilterBlockHeader.get, - to = ourBestHeader) + missing <- chainApi.getHeadersBetween( + from = bestFilterBlockHeader.get, + to = ourBestHeader + ) } yield { - //getHeaderBetween is inclusive with 'from' parameter, - //we only want the inclusive behavior when we are fetching - //from the genesis block hash, so we can get the genesis filter - //else we need the _next_ header after our bestFilterBlockHeader + // getHeaderBetween is inclusive with 'from' parameter, + // we only want the inclusive behavior when we are fetching + // from the genesis block hash, so we can get the genesis filter + // else we need the _next_ header after our bestFilterBlockHeader if ( bestFilterBlockHeader.get.hashBE == chainAppConfig.chain.genesisHashBE ) { @@ -108,8 +125,8 @@ abstract class FilterSync extends ChainVerificationLogger { } } - //because filters can be really large, we don't want to process too many - //at once, so batch them in groups and the process them. + // because filters can be really large, we don't want to process too many + // at once, so batch them in groups and the process them. val groupedHeadersF: Future[Iterator[Vector[BlockHeaderDb]]] = for { missing <- headersMissingFiltersF } yield missing.grouped(batchSize) @@ -123,10 +140,12 @@ abstract class FilterSync extends ChainVerificationLogger { api <- apiF bestFilterOpt <- api.getBestFilterHeader() newApi <- { - fetchFiltersForHeaderGroup(api, - missingHeaders, - bestFilterOpt, - getFilterFunc) + fetchFiltersForHeaderGroup( + api, + missingHeaders, + bestFilterOpt, + getFilterFunc + ) } } yield newApi } @@ -139,9 +158,9 @@ abstract class FilterSync extends ChainVerificationLogger { chainApi: ChainApi, missingHeaders: Vector[BlockHeaderDb], ourBestFilterHeaderOpt: Option[CompactFilterHeaderDb], - getFilterFunc: BlockHeader => Future[FilterWithHeaderHash])(implicit - ec: ExecutionContext): Future[ChainApi] = { - //now that we have headers that are missing filters, let's fetch the filters + getFilterFunc: BlockHeader => Future[FilterWithHeaderHash] + )(implicit ec: ExecutionContext): Future[ChainApi] = { + // now that we have headers that are missing filters, let's fetch the filters val fetchNested = missingHeaders.map { b => val filterF = getFilterFunc(b.blockHeader) @@ -152,7 +171,7 @@ abstract class FilterSync extends ChainVerificationLogger { Future.sequence(fetchNested) } - //now let's build filter headers + // now let's build filter headers val blockFiltersAggF: Future[Vector[BlockFilterAggregated]] = { fetchFiltersF.map { case filters: Vector[(BlockHeaderDb, FilterWithHeaderHash)] => @@ -162,8 +181,10 @@ abstract class FilterSync extends ChainVerificationLogger { val compactFiltersF = blockFiltersAggF.map { filtersAgg => filtersAgg.map { agg => - CompactFilterMessage(blockHash = agg.blockHeader.hash, - filter = agg.filter) + CompactFilterMessage( + blockHash = agg.blockHeader.hash, + filter = agg.filter + ) } } @@ -181,7 +202,8 @@ abstract class FilterSync extends ChainVerificationLogger { case None => logger.info( s"We did not have a block header to process filter headers with! filterHeaders=${filterHeaders} " + - s"compactFilters=${compactFilters} ourBestFilterHeader=${ourBestFilterHeaderOpt}") + s"compactFilters=${compactFilters} ourBestFilterHeader=${ourBestFilterHeaderOpt}" + ) Future.successful(chainApi) case Some(blockHeader) => for { @@ -196,18 +218,18 @@ abstract class FilterSync extends ChainVerificationLogger { } } - /** This builds a [[BlockFilterAggregated]] data structure - * and verifies that the filter header hash from an external - * data source matches the hash of the header we generated internally. - * If the hash does not match, someone is likely feeding you a bad header chain. + /** This builds a [[BlockFilterAggregated]] data structure and verifies that + * the filter header hash from an external data source matches the hash of + * the header we generated internally. If the hash does not match, someone is + * likely feeding you a bad header chain. */ private def buildBlockFilterAggregated( filters: Vector[(BlockHeaderDb, FilterWithHeaderHash)], - ourBestFilterHeaderOpt: Option[CompactFilterHeaderDb]): Vector[ - BlockFilterAggregated] = { + ourBestFilterHeaderOpt: Option[CompactFilterHeaderDb] + ): Vector[BlockFilterAggregated] = { val prevFilterHeaderHash = ourBestFilterHeaderOpt match { - case None => DoubleSha256Digest.empty //for the genesis filter + case None => DoubleSha256Digest.empty // for the genesis filter case Some(ourBestFilterHeader) => ourBestFilterHeader.hashBE.flip } val accum = new mutable.ArrayBuffer[BlockFilterAggregated](filters.length) @@ -215,12 +237,14 @@ abstract class FilterSync extends ChainVerificationLogger { filters.foreach { case (blockHeaderDb, filterWithHash) => val FilterWithHeaderHash(filter, expectedHeaderHash) = filterWithHash val filterHeader = if (accum.isEmpty) { - //first header to connect with our internal headers - //that have already been validated - FilterHeader(filterHash = filter.hash, - prevHeaderHash = prevFilterHeaderHash) + // first header to connect with our internal headers + // that have already been validated + FilterHeader( + filterHash = filter.hash, + prevHeaderHash = prevFilterHeaderHash + ) } else { - //get previous filter header's hash + // get previous filter header's hash val prevHeaderHash = accum.last.filterHeader.hash FilterHeader(filterHash = filter.hash, prevHeaderHash = prevHeaderHash) } @@ -230,9 +254,11 @@ abstract class FilterSync extends ChainVerificationLogger { BlockFilterAggregated(filterHeader, filter, blockHeaderDb.blockHeader) accum.append(agg) } else { - sys.error(s"The header we created was different from the expected hash we received " + - s"from an external data source! Something is wrong. Our filterHeader=${filterHeader} " + - s"expectedHash=$expectedHeaderHash") + sys.error( + s"The header we created was different from the expected hash we received " + + s"from an external data source! Something is wrong. Our filterHeader=${filterHeader} " + + s"expectedHash=$expectedHeaderHash" + ) } } diff --git a/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/FilterWithHeaderHash.scala b/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/FilterWithHeaderHash.scala index b5ba373d08..8577432b35 100644 --- a/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/FilterWithHeaderHash.scala +++ b/chain/src/main/scala/org/bitcoins/chain/blockchain/sync/FilterWithHeaderHash.scala @@ -3,10 +3,13 @@ package org.bitcoins.chain.blockchain.sync import org.bitcoins.core.gcs.GolombFilter import org.bitcoins.crypto.DoubleSha256DigestBE -/** Represents a [[GolombFilter]] with it's [[org.bitcoins.core.gcs.FilterHeader]] associated with it - * This is needed because bitcoin core's 'getblockfilter' rpc returns things in this structure - * @see https://developer.bitcoin.org/reference/rpc/getblockfilter.html#argument-2-filtertype +/** Represents a [[GolombFilter]] with it's + * [[org.bitcoins.core.gcs.FilterHeader]] associated with it This is needed + * because bitcoin core's 'getblockfilter' rpc returns things in this structure + * @see + * https://developer.bitcoin.org/reference/rpc/getblockfilter.html#argument-2-filtertype */ case class FilterWithHeaderHash( filter: GolombFilter, - filterHeaderHash: DoubleSha256DigestBE) + filterHeaderHash: DoubleSha256DigestBE +) diff --git a/chain/src/main/scala/org/bitcoins/chain/config/ChainAppConfig.scala b/chain/src/main/scala/org/bitcoins/chain/config/ChainAppConfig.scala index f4baddc716..c2ace1d51f 100644 --- a/chain/src/main/scala/org/bitcoins/chain/config/ChainAppConfig.scala +++ b/chain/src/main/scala/org/bitcoins/chain/config/ChainAppConfig.scala @@ -14,12 +14,14 @@ import java.nio.file.Path import scala.concurrent.{ExecutionContext, Future} /** Configuration for the Bitcoin-S chain verification module - * @param directory The data directory of the module - * @param confs Optional sequence of configuration overrides + * @param directory + * The data directory of the module + * @param confs + * Optional sequence of configuration overrides */ case class ChainAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( - implicit override val ec: ExecutionContext) - extends DbAppConfig + implicit override val ec: ExecutionContext +) extends DbAppConfig with ChainDbManagement with JdbcProfileComponent[ChainAppConfig] with CallbackConfig[ChainCallbacks] { @@ -29,16 +31,16 @@ case class ChainAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( override protected[bitcoins] type ConfigType = ChainAppConfig override protected[bitcoins] def newConfigOfType( - configs: Vector[Config]): ChainAppConfig = + configs: Vector[Config] + ): ChainAppConfig = ChainAppConfig(baseDatadir, configs) override lazy val appConfig: ChainAppConfig = this override lazy val callbackFactory: ChainCallbacks.type = ChainCallbacks - /** Checks whether or not the chain project is initialized by - * trying to read the genesis block header from our block - * header table + /** Checks whether or not the chain project is initialized by trying to read + * the genesis block header from our block header table */ def isStarted(): Future[Boolean] = { val bhDAO = BlockHeaderDAO()(ec, appConfig) @@ -54,9 +56,9 @@ case class ChainAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( } } - /** Initializes our chain project if it is needed - * This creates the necessary tables for the chain project - * and inserts preliminary data like the genesis block header + /** Initializes our chain project if it is needed This creates the necessary + * tables for the chain project and inserts preliminary data like the genesis + * block header */ override def start(): Future[Unit] = { for { @@ -71,7 +73,8 @@ case class ChainAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( BlockHeaderDbHelper.fromBlockHeader( height = 0, chainWork = Pow.getBlockProof(chain.genesisBlock.blockHeader), - bh = chain.genesisBlock.blockHeader) + bh = chain.genesisBlock.blockHeader + ) val blockHeaderDAO = BlockHeaderDAO()(ec, appConfig) val bhCreatedF = blockHeaderDAO.create(genesisHeader) @@ -83,7 +86,7 @@ case class ChainAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( } } yield { if (isHikariLoggingEnabled) { - //.get is safe because hikari logging is enabled + // .get is safe because hikari logging is enabled startHikariLogger(hikariLoggingInterval.get) () } @@ -103,20 +106,22 @@ case class ChainAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( // try by network, if that fails, try general try { config.getInt( - s"bitcoin-s.$moduleName.neutrino.filter-header-batch-size.${chain.network.chainParams.networkId}") + s"bitcoin-s.$moduleName.neutrino.filter-header-batch-size.${chain.network.chainParams.networkId}" + ) } catch { case _: ConfigException.Missing | _: ConfigException.WrongType => config.getInt( - s"bitcoin-s.$moduleName.neutrino.filter-header-batch-size.default") + s"bitcoin-s.$moduleName.neutrino.filter-header-batch-size.default" + ) } } lazy val filterBatchSize: Int = config.getInt(s"bitcoin-s.${moduleName}.neutrino.filter-batch-size") - /** Whether we should emit block processed events during IBD or not. - * This is because websocket events can overwhelm UIs during IBD. - * If this is set, we won't emit blockprocessed event until ibd is complete. + /** Whether we should emit block processed events during IBD or not. This is + * because websocket events can overwhelm UIs during IBD. If this is set, we + * won't emit blockprocessed event until ibd is complete. */ lazy val ibdBlockProcessedEvents: Boolean = { config.getBoolean(s"bitcoin-s.${moduleName}.websocket.block-processed-ibd") @@ -132,6 +137,7 @@ object ChainAppConfig extends AppConfigFactory[ChainAppConfig] { * data directory and given list of configuration overrides. */ override def fromDatadir(datadir: Path, confs: Vector[Config])(implicit - ec: ExecutionContext): ChainAppConfig = + ec: ExecutionContext + ): ChainAppConfig = ChainAppConfig(datadir, confs) } diff --git a/chain/src/main/scala/org/bitcoins/chain/db/ChainDbManagement.scala b/chain/src/main/scala/org/bitcoins/chain/db/ChainDbManagement.scala index 9798450880..03911bde46 100644 --- a/chain/src/main/scala/org/bitcoins/chain/db/ChainDbManagement.scala +++ b/chain/src/main/scala/org/bitcoins/chain/db/ChainDbManagement.scala @@ -11,8 +11,8 @@ import org.bitcoins.db.{DbManagement, JdbcProfileComponent} import scala.concurrent.ExecutionContext -/** Responsible for creating and destroying database - * tables inside of the Chain project. +/** Responsible for creating and destroying database tables inside of the Chain + * project. */ trait ChainDbManagement extends DbManagement { _: JdbcProfileComponent[ChainAppConfig] => diff --git a/chain/src/main/scala/org/bitcoins/chain/models/BlockHeaderDAO.scala b/chain/src/main/scala/org/bitcoins/chain/models/BlockHeaderDAO.scala index 70e7f761ed..1b18c67263 100644 --- a/chain/src/main/scala/org/bitcoins/chain/models/BlockHeaderDAO.scala +++ b/chain/src/main/scala/org/bitcoins/chain/models/BlockHeaderDAO.scala @@ -11,14 +11,13 @@ import org.bitcoins.db._ import scala.annotation.tailrec import scala.concurrent.{ExecutionContext, Future} -/** This class is responsible for all database access related - * to [[org.bitcoins.core.protocol.blockchain.BlockHeader]]s in - * our chain project +/** This class is responsible for all database access related to + * [[org.bitcoins.core.protocol.blockchain.BlockHeader]]s in our chain project */ case class BlockHeaderDAO()(implicit ec: ExecutionContext, - override val appConfig: ChainAppConfig) - extends CRUD[BlockHeaderDb, DoubleSha256DigestBE] + override val appConfig: ChainAppConfig +) extends CRUD[BlockHeaderDb, DoubleSha256DigestBE] with SlickUtil[BlockHeaderDb, DoubleSha256DigestBE] { import profile.api._ @@ -36,14 +35,14 @@ case class BlockHeaderDAO()(implicit /** Creates all of the given [[BlockHeaderDb]] in the database */ override def createAll( - headers: Vector[BlockHeaderDb]): Future[Vector[BlockHeaderDb]] = { + headers: Vector[BlockHeaderDb] + ): Future[Vector[BlockHeaderDb]] = { createAllNoAutoInc(ts = headers, database = safeDatabase) } - override protected def findAll(ts: Vector[BlockHeaderDb]): Query[ - BlockHeaderTable, - BlockHeaderDb, - Seq] = { + override protected def findAll( + ts: Vector[BlockHeaderDb] + ): Query[BlockHeaderTable, BlockHeaderDb, Seq] = { findByPrimaryKeys(ts.map(_.hashBE)) } @@ -52,11 +51,12 @@ case class BlockHeaderDAO()(implicit safeDatabase.runVec(query).map(_.headOption) } - /** Finds the block headers associated with the hashes. Returns None if we could not find a particular - * hash in the database + /** Finds the block headers associated with the hashes. Returns None if we + * could not find a particular hash in the database */ - def findByHashes(hashes: Vector[DoubleSha256DigestBE]): Future[ - Vector[Option[BlockHeaderDb]]] = { + def findByHashes( + hashes: Vector[DoubleSha256DigestBE] + ): Future[Vector[Option[BlockHeaderDb]]] = { val query = findByPrimaryKeys(hashes) val resultsF: Future[Vector[BlockHeaderDb]] = safeDatabase.runVec(query.result) @@ -67,10 +67,9 @@ case class BlockHeaderDAO()(implicit } } - override def findByPrimaryKeys(hashes: Vector[DoubleSha256DigestBE]): Query[ - BlockHeaderTable, - BlockHeaderDb, - Seq] = { + override def findByPrimaryKeys( + hashes: Vector[DoubleSha256DigestBE] + ): Query[BlockHeaderTable, BlockHeaderDb, Seq] = { table.filter(_.hash.inSet(hashes)) } @@ -81,7 +80,8 @@ case class BlockHeaderDAO()(implicit */ def getAncestorAtHeight( child: BlockHeaderDb, - height: Int): Future[Option[BlockHeaderDb]] = { + height: Int + ): Future[Option[BlockHeaderDb]] = { /* * To avoid making many database reads, we make one database read for all * possibly useful block headers. @@ -108,13 +108,14 @@ case class BlockHeaderDAO()(implicit @tailrec def loop( currentHeader: BlockHeaderDb, - headersByDescHeight: Array[Vector[BlockHeaderDb]]): Option[ - BlockHeaderDb] = { + headersByDescHeight: Array[Vector[BlockHeaderDb]] + ): Option[BlockHeaderDb] = { if (currentHeader.height == height) { Some(currentHeader) } else { val prevHeaderOpt = headersByDescHeight.headOption.flatMap( - _.find(_.hashBE == currentHeader.previousBlockHashBE)) + _.find(_.hashBE == currentHeader.previousBlockHashBE) + ) prevHeaderOpt match { case None => None @@ -133,10 +134,12 @@ case class BlockHeaderDAO()(implicit safeDatabase.runVec(query) } - def getAtHeightQuery(height: Int): profile.StreamingProfileAction[ - Seq[BlockHeaderDb], - BlockHeaderDb, - Effect.Read] = { + def getAtHeightQuery( + height: Int): profile.StreamingProfileAction[Seq[ + BlockHeaderDb + ], + BlockHeaderDb, + Effect.Read] = { table.filter(_.height === height).result } @@ -146,17 +149,22 @@ case class BlockHeaderDAO()(implicit safeDatabase.runVec(query) } - def getAtChainWorkQuery(work: BigInt): profile.StreamingProfileAction[ - Seq[BlockHeaderDb], - BlockHeaderDb, - Effect.Read] = { + def getAtChainWorkQuery( + work: BigInt): profile.StreamingProfileAction[Seq[ + BlockHeaderDb + ], + BlockHeaderDb, + Effect.Read] = { table.filter(_.chainWork === work).result } - /** Gets Block Headers between (inclusive) start height and stop hash, could be out of order */ + /** Gets Block Headers between (inclusive) start height and stop hash, could + * be out of order + */ def getBetweenHeightAndHash( startHeight: Int, - stopHash: DoubleSha256DigestBE): Future[Vector[BlockHeaderDb]] = { + stopHash: DoubleSha256DigestBE + ): Future[Vector[BlockHeaderDb]] = { for { headerOpt <- findByHash(stopHash) res <- headerOpt match { @@ -175,7 +183,8 @@ case class BlockHeaderDAO()(implicit */ def getNAncestors( childHash: DoubleSha256DigestBE, - n: Int): Future[Vector[BlockHeaderDb]] = { + n: Int + ): Future[Vector[BlockHeaderDb]] = { require(n >= 0, s"Cannot get negative ancestors, N=$n") logger.trace(s"Getting $n ancestors for blockhash=$childHash") val headerOptF = findByHash(childHash) @@ -199,7 +208,8 @@ case class BlockHeaderDAO()(implicit } } - /** Gets Block Headers between (inclusive) from and to, could be out of order */ + /** Gets Block Headers between (inclusive) from and to, could be out of order + */ def getBetweenHeights(from: Int, to: Int): Future[Vector[BlockHeaderDb]] = { val query = getBetweenHeightsQuery(from, to) safeDatabase.runVec(query) @@ -207,10 +217,12 @@ case class BlockHeaderDAO()(implicit def getBetweenHeightsQuery( from: Int, - to: Int): profile.StreamingProfileAction[ - Seq[BlockHeaderDb], - BlockHeaderDb, - Effect.Read] = { + to: Int + ): profile.StreamingProfileAction[Seq[ + BlockHeaderDb + ], + BlockHeaderDb, + Effect.Read] = { table.filter(header => header.height >= from && header.height <= to).result } @@ -225,8 +237,10 @@ case class BlockHeaderDAO()(implicit } def findClosestToTime(time: UInt32): Future[BlockHeaderDb] = { - require(time >= UInt32(1231006505), - s"Time must be after the genesis block (1231006505), got $time") + require( + time >= UInt32(1231006505), + s"Time must be after the genesis block (1231006505), got $time" + ) val query = table.filter(_.time === time) @@ -245,10 +259,8 @@ case class BlockHeaderDAO()(implicit } } - private val lowestNoWorkQuery: profile.ProfileAction[ - Int, - NoStream, - Effect.Read] = { + private val lowestNoWorkQuery + : profile.ProfileAction[Int, NoStream, Effect.Read] = { val noWork = table.filter(h => h.chainWork === BigInt(0) || h.chainWork == null) noWork.map(_.height).min.getOrElse(0).result @@ -265,25 +277,22 @@ case class BlockHeaderDAO()(implicit safeDatabase.run(query) } - private val maxHeightQuery: profile.ProfileAction[ - Int, - NoStream, - Effect.Read] = { + private val maxHeightQuery + : profile.ProfileAction[Int, NoStream, Effect.Read] = { val query = table.map(_.height).max.getOrElse(0).result query } - /** Returns the block height of the block with the most work from our database */ + /** Returns the block height of the block with the most work from our database + */ def bestHeight: Future[Int] = { getBestChainTips.map { tips => tips.maxByOption(_.chainWork).map(_.height).getOrElse(0) } } - private val maxWorkQuery: profile.ProfileAction[ - BigInt, - NoStream, - Effect.Read] = { + private val maxWorkQuery + : profile.ProfileAction[BigInt, NoStream, Effect.Read] = { val query = table.map(_.chainWork).max.getOrElse(BigInt(0)).result query } @@ -302,24 +311,26 @@ case class BlockHeaderDAO()(implicit safeDatabase.runVec(aggregate) } - /** Retrieves chain tips my finding duplicates at a certain height - * within a given range. This indicates there was a contentious chain tip - * at some point. + /** Retrieves chain tips my finding duplicates at a certain height within a + * given range. This indicates there was a contentious chain tip at some + * point. * - * It's important to note that this query will NOT return the current best chain tip - * unless that current chain tips is contentious + * It's important to note that this query will NOT return the current best + * chain tip unless that current chain tips is contentious * - * @param lowestHeight the height we will look backwards until. This is inclusive + * @param lowestHeight + * the height we will look backwards until. This is inclusive */ private def forkedChainTips( - lowestHeight: Int): Future[Vector[BlockHeaderDb]] = { + lowestHeight: Int + ): Future[Vector[BlockHeaderDb]] = { val headersQ = table.filter(_.height >= lowestHeight) val headersF = safeDatabase.runVec(headersQ.result) for { headers <- headersF byHeight = headers.groupBy(_.height) - //now find instances where we have duplicate headers at a given height - //this indicates there was at one point a fork + // now find instances where we have duplicate headers at a given height + // this indicates there was at one point a fork forks = byHeight.filter(_._2.length > 1) } yield forks.flatMap(_._2).toVector } @@ -337,18 +348,19 @@ case class BlockHeaderDAO()(implicit .runVec(aggregate) } - /** Retrieves all possible chainTips from the database. Note this does NOT retrieve - * the BEST chain tips. If you need those please call [[getBestChainTips]]. This method - * will search backwards [[appConfig.chain.difficultyChangeInterval]] blocks looking - * for all forks that we have in our chainstate. + /** Retrieves all possible chainTips from the database. Note this does NOT + * retrieve the BEST chain tips. If you need those please call + * [[getBestChainTips]]. This method will search backwards + * [[appConfig.chain.difficultyChangeInterval]] blocks looking for all forks + * that we have in our chainstate. * * We will then return all conflicting headers. * - * Note: - * This method does NOT try and remove headers that are in the best chain. This means - * half the returned headers from this method will be in the best chain. To figure out - * which headers are in the best chain, you will need to walk backwards from [[getBestChainTips]] - * figuring out which headers are a part of the best chain. + * Note: This method does NOT try and remove headers that are in the best + * chain. This means half the returned headers from this method will be in + * the best chain. To figure out which headers are in the best chain, you + * will need to walk backwards from [[getBestChainTips]] figuring out which + * headers are a part of the best chain. */ def getForkedChainTips: Future[Vector[BlockHeaderDb]] = { val mHeight = maxHeight @@ -357,7 +369,7 @@ case class BlockHeaderDAO()(implicit Math.max(lowest, 0) } - //what to do about tips that are in the best chain? + // what to do about tips that are in the best chain? val tipsF = for { lowestHeight <- lowestHeightF result <- forkedChainTips(lowestHeight) @@ -369,16 +381,21 @@ case class BlockHeaderDAO()(implicit } /** Returns competing blockchains that are contained in our BlockHeaderDAO - * Each chain returns the last [[org.bitcoins.core.protocol.blockchain.ChainParams.difficultyChangeInterval difficutly interval]] - * block headers as defined by the network we are on. For instance, on bitcoin mainnet this will be 2016 block headers. - * If no competing tips are found, we only return one [[[org.bitcoins.chain.blockchain.Blockchain Blockchain]], else we - * return n chains for the number of competing [[chainTips tips]] we have - * @see [[org.bitcoins.chain.blockchain.Blockchain Blockchain]] + * Each chain returns the last + * [[org.bitcoins.core.protocol.blockchain.ChainParams.difficultyChangeInterval difficutly interval]] + * block headers as defined by the network we are on. For instance, on + * bitcoin mainnet this will be 2016 block headers. If no competing tips are + * found, we only return one + * [[[org.bitcoins.chain.blockchain.Blockchain Blockchain]], else we return n + * chains for the number of competing [[chainTips tips]] we have + * @see + * [[org.bitcoins.chain.blockchain.Blockchain Blockchain]] * @param ec * @return */ def getBlockchains()(implicit - ec: ExecutionContext): Future[Vector[Blockchain]] = { + ec: ExecutionContext + ): Future[Vector[Blockchain]] = { val chainTipsF = getForkedChainTips val bestTipF = getBestChainTips val staleChainsF = chainTipsF.flatMap { tips => @@ -398,10 +415,10 @@ case class BlockHeaderDAO()(implicit for { staleChains <- staleChainsF bestChains <- bestChainsF - //we need to check the stale chains tips to see if it is contained - //in our best chains. If it is, that means the stale chain - //is a subchain of a best chain. We need to discard it if - //if that is the case to avoid duplicates + // we need to check the stale chains tips to see if it is contained + // in our best chains. If it is, that means the stale chain + // is a subchain of a best chain. We need to discard it if + // if that is the case to avoid duplicates filtered = staleChains.filterNot { c => bestChains.exists { best => best.findAtHeight(c.tip.height) match { @@ -416,17 +433,21 @@ case class BlockHeaderDAO()(implicit } /** Retrieves a blockchain with the best tip being the given header */ - def getBlockchainFrom(header: BlockHeaderDb)(implicit - ec: ExecutionContext): Future[Option[Blockchain]] = { + def getBlockchainFrom( + header: BlockHeaderDb + )(implicit ec: ExecutionContext): Future[Option[Blockchain]] = { val diffInterval = appConfig.chain.difficultyChangeInterval val height = Math.max(0, header.height - diffInterval) getBlockchainFrom(header = header, startHeight = height) } def getBlockchainFrom(header: BlockHeaderDb, startHeight: Int)(implicit - ec: ExecutionContext): Future[Option[Blockchain]] = { - require(startHeight >= 0, - s"Can only have positive startHeight=$startHeight") + ec: ExecutionContext + ): Future[Option[Blockchain]] = { + require( + startHeight >= 0, + s"Can only have positive startHeight=$startHeight" + ) val blockchainsF = getBlockchainsBetweenHeights(from = startHeight, to = header.height) @@ -439,7 +460,8 @@ case class BlockHeaderDAO()(implicit @tailrec private def loop( chains: Vector[Blockchain], - allHeaders: Vector[BlockHeaderDb]): Vector[Blockchain] = { + allHeaders: Vector[BlockHeaderDb] + ): Vector[Blockchain] = { val usedHeaders = chains.flatMap(_.headers).distinct val diff = allHeaders.filter(header => !usedHeaders.exists(_.hashBE == header.hashBE)) @@ -451,19 +473,21 @@ case class BlockHeaderDAO()(implicit val newChainHeaders = Blockchain.connectWalkBackwards(sortedDiff.head, allHeaders) val newChain = Blockchain( - newChainHeaders.sortBy(_.height)(Ordering.Int.reverse)) + newChainHeaders.sortBy(_.height)(Ordering.Int.reverse) + ) loop(chains :+ newChain, allHeaders) } } /** Retrieves a blockchain with the best tip being the given header */ def getBlockchainsBetweenHeights(from: Int, to: Int)(implicit - ec: ExecutionContext): Future[Vector[Blockchain]] = { + ec: ExecutionContext + ): Future[Vector[Blockchain]] = { getBetweenHeights(from = from, to = to).map { headers => if (headers.map(_.height).distinct.size == headers.size) { Vector( - Blockchain.fromHeaders( - headers.sortBy(_.height)(Ordering.Int.reverse))) + Blockchain.fromHeaders(headers.sortBy(_.height)(Ordering.Int.reverse)) + ) } else { val headersByHeight: Vector[(Int, Vector[BlockHeaderDb])] = headers.groupBy(_.height).toVector @@ -487,25 +511,30 @@ case class BlockHeaderDAO()(implicit } /** Retrieves a full blockchain with the best tip being the given header */ - def getFullBlockchainFrom(header: BlockHeaderDb)(implicit - ec: ExecutionContext): Future[Blockchain] = { + def getFullBlockchainFrom( + header: BlockHeaderDb + )(implicit ec: ExecutionContext): Future[Blockchain] = { val headersF = getBetweenHeights(from = 0, to = header.height) headersF.map(headers => Blockchain.fromHeaders(headers.reverse)) } - /** Finds a [[org.bitcoins.core.api.chain.db.BlockHeaderDb block header]] that satisfies the given predicate, else returns None */ - def find(f: BlockHeaderDb => Boolean)(implicit - ec: ExecutionContext): Future[Option[BlockHeaderDb]] = { + /** Finds a [[org.bitcoins.core.api.chain.db.BlockHeaderDb block header]] that + * satisfies the given predicate, else returns None + */ + def find( + f: BlockHeaderDb => Boolean + )(implicit ec: ExecutionContext): Future[Option[BlockHeaderDb]] = { val chainsF = getBlockchains() chainsF.map { chains => val headersOpt: Vector[Option[BlockHeaderDb]] = chains.map(_.headers.find(f)) - //if there are multiple, we just choose the first one for now + // if there are multiple, we just choose the first one for now val result = headersOpt.filter(_.isDefined).flatten if (result.length > 1) { logger.warn( s"Discarding other matching headers for predicate headers=${result - .map(_.hashBE.hex)}") + .map(_.hashBE.hex)}" + ) } result.headOption } @@ -541,16 +570,18 @@ case class BlockHeaderDAO()(implicit def hashIndex = index("block_headers_hash_index", hash) def * = { - (height, - hash, - version, - previousBlockHash, - merkleRootHash, - time, - nBits, - nonce, - hex, - chainWork).<>(BlockHeaderDb.tupled, BlockHeaderDb.unapply) + ( + height, + hash, + version, + previousBlockHash, + merkleRootHash, + time, + nBits, + nonce, + hex, + chainWork + ).<>(BlockHeaderDb.tupled, BlockHeaderDb.unapply) } } diff --git a/chain/src/main/scala/org/bitcoins/chain/models/ChainStateDescriptorDAO.scala b/chain/src/main/scala/org/bitcoins/chain/models/ChainStateDescriptorDAO.scala index 448dd8238d..7c5b5ad2b7 100644 --- a/chain/src/main/scala/org/bitcoins/chain/models/ChainStateDescriptorDAO.scala +++ b/chain/src/main/scala/org/bitcoins/chain/models/ChainStateDescriptorDAO.scala @@ -9,55 +9,58 @@ import scala.concurrent.{ExecutionContext, Future} case class ChainStateDescriptorDb( tpe: ChainStateDescriptorType, - descriptor: ChainStateDescriptor) { - require(descriptor.descriptorType == tpe, - s"descriptorTpe=${descriptor.descriptorType} tpe=$tpe") + descriptor: ChainStateDescriptor +) { + require( + descriptor.descriptorType == tpe, + s"descriptorTpe=${descriptor.descriptorType} tpe=$tpe" + ) } case class ChainStateDescriptorDAO()(implicit override val ec: ExecutionContext, - override val appConfig: ChainAppConfig) - extends CRUD[ChainStateDescriptorDb, ChainStateDescriptorType] + override val appConfig: ChainAppConfig +) extends CRUD[ChainStateDescriptorDb, ChainStateDescriptorType] with SlickUtil[ChainStateDescriptorDb, ChainStateDescriptorType] { import profile.api._ - implicit val chainStateDescriptorTypeMapper: BaseColumnType[ - ChainStateDescriptorType] = + implicit val chainStateDescriptorTypeMapper + : BaseColumnType[ChainStateDescriptorType] = MappedColumnType.base[ChainStateDescriptorType, String]( _.toString, - ChainStateDescriptorType.fromString) + ChainStateDescriptorType.fromString + ) - implicit val chainStateDescriptorMapper: BaseColumnType[ - ChainStateDescriptor] = + implicit val chainStateDescriptorMapper + : BaseColumnType[ChainStateDescriptor] = MappedColumnType.base[ChainStateDescriptor, String]( _.toString, - ChainStateDescriptor.fromString) + ChainStateDescriptor.fromString + ) override val table: profile.api.TableQuery[ChainStateDescriptorTable] = TableQuery[ChainStateDescriptorTable] - override def createAll(ts: Vector[ChainStateDescriptorDb]): Future[ - Vector[ChainStateDescriptorDb]] = + override def createAll( + ts: Vector[ChainStateDescriptorDb] + ): Future[Vector[ChainStateDescriptorDb]] = createAllNoAutoInc(ts, safeDatabase) - override def findByPrimaryKeys(ids: Vector[ChainStateDescriptorType]): Query[ - ChainStateDescriptorTable, - ChainStateDescriptorDb, - Seq] = { + override def findByPrimaryKeys( + ids: Vector[ChainStateDescriptorType] + ): Query[ChainStateDescriptorTable, ChainStateDescriptorDb, Seq] = { table.filter(_.tpe.inSet(ids)) } - override def findByPrimaryKey(id: ChainStateDescriptorType): Query[ - Table[ChainStateDescriptorDb], - ChainStateDescriptorDb, - Seq] = { + override def findByPrimaryKey( + id: ChainStateDescriptorType + ): Query[Table[ChainStateDescriptorDb], ChainStateDescriptorDb, Seq] = { table.filter(_.tpe === id) } - override def findAll(ts: Vector[ChainStateDescriptorDb]): Query[ - Table[ChainStateDescriptorDb], - ChainStateDescriptorDb, - Seq] = + override def findAll( + ts: Vector[ChainStateDescriptorDb] + ): Query[Table[ChainStateDescriptorDb], ChainStateDescriptorDb, Seq] = findByPrimaryKeys(ts.map(_.tpe)) def getSync(): Future[Option[SyncDescriptor]] = { @@ -132,17 +135,21 @@ case class ChainStateDescriptorDAO()(implicit } class ChainStateDescriptorTable(t: Tag) - extends Table[ChainStateDescriptorDb](t, - schemaName, - "state_descriptors") { + extends Table[ChainStateDescriptorDb]( + t, + schemaName, + "state_descriptors" + ) { def tpe: Rep[ChainStateDescriptorType] = column("type", O.PrimaryKey) def descriptor: Rep[ChainStateDescriptor] = column("descriptor") override def * : ProvenShape[ChainStateDescriptorDb] = - (tpe, descriptor).<>(ChainStateDescriptorDb.tupled, - ChainStateDescriptorDb.unapply) + (tpe, descriptor).<>( + ChainStateDescriptorDb.tupled, + ChainStateDescriptorDb.unapply + ) } } diff --git a/chain/src/main/scala/org/bitcoins/chain/models/CompactFilterDAO.scala b/chain/src/main/scala/org/bitcoins/chain/models/CompactFilterDAO.scala index 0d553d00b5..f5a7a0af89 100644 --- a/chain/src/main/scala/org/bitcoins/chain/models/CompactFilterDAO.scala +++ b/chain/src/main/scala/org/bitcoins/chain/models/CompactFilterDAO.scala @@ -12,8 +12,8 @@ import scala.concurrent.{ExecutionContext, Future} case class CompactFilterDAO()(implicit ec: ExecutionContext, - override val appConfig: ChainAppConfig) - extends CRUD[CompactFilterDb, DoubleSha256DigestBE] + override val appConfig: ChainAppConfig +) extends CRUD[CompactFilterDb, DoubleSha256DigestBE] with SlickUtil[CompactFilterDb, DoubleSha256DigestBE] { val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) import mappers.{ @@ -47,8 +47,10 @@ case class CompactFilterDAO()(implicit def hashIndex = index("cfilters_hash_index", hash) override def * = { - (hash, filterType, bytes, height, blockHash).<>(CompactFilterDb.tupled, - CompactFilterDb.unapply) + (hash, filterType, bytes, height, blockHash).<>( + CompactFilterDb.tupled, + CompactFilterDb.unapply + ) } } @@ -56,39 +58,39 @@ case class CompactFilterDAO()(implicit TableQuery[CompactFilterTable] } - private lazy val blockHeaderTable: profile.api.TableQuery[ - BlockHeaderDAO#BlockHeaderTable] = { + private lazy val blockHeaderTable + : profile.api.TableQuery[BlockHeaderDAO#BlockHeaderTable] = { BlockHeaderDAO().table } override def createAll( - filters: Vector[CompactFilterDb]): Future[Vector[CompactFilterDb]] = { + filters: Vector[CompactFilterDb] + ): Future[Vector[CompactFilterDb]] = { createAllNoAutoInc(ts = filters, database = safeDatabase) } /** Finds the rows that correlate to the given primary keys */ override protected def findByPrimaryKeys( - ids: Vector[DoubleSha256DigestBE]): Query[ - Table[CompactFilterDb], - CompactFilterDb, - Seq] = { + ids: Vector[DoubleSha256DigestBE] + ): Query[Table[CompactFilterDb], CompactFilterDb, Seq] = { table.filter(_.blockHash.inSet(ids)) } - override protected def findAll(ts: Vector[CompactFilterDb]): Query[ - Table[CompactFilterDb], - CompactFilterDb, - Seq] = { + override protected def findAll( + ts: Vector[CompactFilterDb] + ): Query[Table[CompactFilterDb], CompactFilterDb, Seq] = { findByPrimaryKeys(ts.map(_.blockHashBE)) } def findByBlockHash( - hash: DoubleSha256DigestBE): Future[Option[CompactFilterDb]] = { + hash: DoubleSha256DigestBE + ): Future[Option[CompactFilterDb]] = { read(hash) } def findByBlockHashes( - hashes: Vector[DoubleSha256DigestBE]): Future[Vector[CompactFilterDb]] = { + hashes: Vector[DoubleSha256DigestBE] + ): Future[Vector[CompactFilterDb]] = { val action = findByPrimaryKeys(hashes).result safeDatabase.runVec(action) } @@ -99,10 +101,12 @@ case class CompactFilterDAO()(implicit safeDatabase.runVec(query) } - private def getAtHeightQuery(height: Int): profile.StreamingProfileAction[ - Seq[CompactFilterDb], - CompactFilterDb, - Effect.Read] = { + private def getAtHeightQuery( + height: Int): profile.StreamingProfileAction[Seq[ + CompactFilterDb + ], + CompactFilterDb, + Effect.Read] = { table.filter(_.height === height).result } @@ -113,10 +117,8 @@ case class CompactFilterDAO()(implicit result } - private val maxHeightQuery: profile.ProfileAction[ - Int, - NoStream, - Effect.Read] = { + private val maxHeightQuery + : profile.ProfileAction[Int, NoStream, Effect.Read] = { val query = table.map(_.height).max.getOrElse(0).result query } @@ -129,10 +131,12 @@ case class CompactFilterDAO()(implicit private def getBetweenHeightsQuery( from: Int, - to: Int): profile.StreamingProfileAction[ - Seq[CompactFilterDb], - CompactFilterDb, - Effect.Read] = { + to: Int + ): profile.StreamingProfileAction[Seq[ + CompactFilterDb + ], + CompactFilterDb, + Effect.Read] = { table .filter(header => header.height >= from && header.height <= to) .sortBy(_.height) @@ -144,8 +148,8 @@ case class CompactFilterDAO()(implicit .join(blockHeaderTable) .on(_.blockHash === _.hash) .sortBy(_._1.height.desc) - //just take the last 2016 headers, if we have a reorg larger than - //this we will not be able to retrieve that header + // just take the last 2016 headers, if we have a reorg larger than + // this we will not be able to retrieve that header .take(appConfig.chain.difficultyChangeInterval) val maxQuery = join.map(_._2.chainWork).max @@ -162,10 +166,8 @@ case class CompactFilterDAO()(implicit safeDatabase.run(bestFilterQuery).map(_.headOption) } - private val bestFilterHeightQuery: DBIOAction[ - Option[Int], - NoStream, - Effect.Read] = { + private val bestFilterHeightQuery + : DBIOAction[Option[Int], NoStream, Effect.Read] = { table.map(_.height).max.result } diff --git a/chain/src/main/scala/org/bitcoins/chain/models/CompactFilterHeaderDAO.scala b/chain/src/main/scala/org/bitcoins/chain/models/CompactFilterHeaderDAO.scala index 3165c07831..24b56bd90a 100644 --- a/chain/src/main/scala/org/bitcoins/chain/models/CompactFilterHeaderDAO.scala +++ b/chain/src/main/scala/org/bitcoins/chain/models/CompactFilterHeaderDAO.scala @@ -10,8 +10,8 @@ import scala.concurrent.{ExecutionContext, Future} case class CompactFilterHeaderDAO()(implicit ec: ExecutionContext, - override val appConfig: ChainAppConfig) - extends CRUD[CompactFilterHeaderDb, DoubleSha256DigestBE] + override val appConfig: ChainAppConfig +) extends CRUD[CompactFilterHeaderDb, DoubleSha256DigestBE] with SlickUtil[CompactFilterHeaderDb, DoubleSha256DigestBE] { import profile.api._ val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -44,7 +44,8 @@ case class CompactFilterHeaderDAO()(implicit override def * = { (hash, filterHash, previousFilterHeader, blockHash, height).<>( CompactFilterHeaderDb.tupled, - CompactFilterHeaderDb.unapply) + CompactFilterHeaderDb.unapply + ) } } @@ -52,49 +53,51 @@ case class CompactFilterHeaderDAO()(implicit TableQuery[CompactFilterHeaderTable] } - private lazy val blockHeaderTable: profile.api.TableQuery[ - BlockHeaderDAO#BlockHeaderTable] = { + private lazy val blockHeaderTable + : profile.api.TableQuery[BlockHeaderDAO#BlockHeaderTable] = { BlockHeaderDAO().table } - override def createAll(filterHeaders: Vector[CompactFilterHeaderDb]): Future[ - Vector[CompactFilterHeaderDb]] = { + override def createAll( + filterHeaders: Vector[CompactFilterHeaderDb] + ): Future[Vector[CompactFilterHeaderDb]] = { createAllNoAutoInc(ts = filterHeaders, database = safeDatabase) } /** Finds the rows that correlate to the given primary keys */ override protected def findByPrimaryKeys( - ids: Vector[DoubleSha256DigestBE]): Query[ - Table[CompactFilterHeaderDb], - CompactFilterHeaderDb, - Seq] = + ids: Vector[DoubleSha256DigestBE] + ): Query[Table[CompactFilterHeaderDb], CompactFilterHeaderDb, Seq] = table.filter(_.hash.inSet(ids)) - override protected def findAll(ts: Vector[CompactFilterHeaderDb]): Query[ - Table[CompactFilterHeaderDb], - CompactFilterHeaderDb, - Seq] = + override protected def findAll( + ts: Vector[CompactFilterHeaderDb] + ): Query[Table[CompactFilterHeaderDb], CompactFilterHeaderDb, Seq] = findByPrimaryKeys(ts.map(_.hashBE)) def findByHash( - hash: DoubleSha256DigestBE): Future[Option[CompactFilterHeaderDb]] = { + hash: DoubleSha256DigestBE + ): Future[Option[CompactFilterHeaderDb]] = { read(hash) } - def findByHashes(hashes: Vector[DoubleSha256DigestBE]): Future[ - Vector[CompactFilterHeaderDb]] = { + def findByHashes( + hashes: Vector[DoubleSha256DigestBE] + ): Future[Vector[CompactFilterHeaderDb]] = { val query = findByPrimaryKeys(hashes).result safeDatabase.runVec(query) } def findByBlockHash( - hash: DoubleSha256DigestBE): Future[Option[CompactFilterHeaderDb]] = { + hash: DoubleSha256DigestBE + ): Future[Option[CompactFilterHeaderDb]] = { val query = table.filter(_.blockHash === hash).take(1) safeDatabase.runVec(query.result).map(_.headOption) } - def findAllByBlockHashes(hashes: Vector[DoubleSha256DigestBE]): Future[ - Vector[CompactFilterHeaderDb]] = { + def findAllByBlockHashes( + hashes: Vector[DoubleSha256DigestBE] + ): Future[Vector[CompactFilterHeaderDb]] = { val query = table .filter(_.blockHash.inSet(hashes)) .sortBy(_.height) @@ -107,10 +110,13 @@ case class CompactFilterHeaderDAO()(implicit safeDatabase.runVec(query) } - private def getAtHeightQuery(height: Int): slick.sql.FixedSqlStreamingAction[ - Seq[CompactFilterHeaderDb], - CompactFilterHeaderDb, - Effect.Read] = { + private def getAtHeightQuery( + height: Int + ): slick.sql.FixedSqlStreamingAction[Seq[ + CompactFilterHeaderDb + ], + CompactFilterHeaderDb, + Effect.Read] = { table.filter(_.height === height).result } @@ -121,10 +127,8 @@ case class CompactFilterHeaderDAO()(implicit result } - private val maxHeightQuery: profile.ProfileAction[ - Int, - NoStream, - Effect.Read] = { + private val maxHeightQuery + : profile.ProfileAction[Int, NoStream, Effect.Read] = { val query = table.map(_.height).max.getOrElse(0).result query } @@ -134,8 +138,8 @@ case class CompactFilterHeaderDAO()(implicit .join(blockHeaderTable) .on(_.blockHash === _.hash) .sortBy(_._1.height.desc) - //just take the last 2016 headers, if we have a reorg larger than - //this we will not be able to retrieve that header + // just take the last 2016 headers, if we have a reorg larger than + // this we will not be able to retrieve that header .take(appConfig.chain.difficultyChangeInterval) val maxQuery = join.map(_._2.chainWork).max @@ -147,10 +151,11 @@ case class CompactFilterHeaderDAO()(implicit .result } - /** Fetches the best filter header from the database _without_ context - * that it's actually in our best blockchain. For instance, this filter header could be - * reorged out for whatever reason. - * @see https://github.com/bitcoin-s/bitcoin-s/issues/1919#issuecomment-682041737 + /** Fetches the best filter header from the database _without_ context that + * it's actually in our best blockchain. For instance, this filter header + * could be reorged out for whatever reason. + * @see + * https://github.com/bitcoin-s/bitcoin-s/issues/1919#issuecomment-682041737 */ def getBestFilterHeader: Future[Option[CompactFilterHeaderDb]] = { safeDatabase.run(bestFilterHeaderQuery).map(_.headOption) @@ -167,11 +172,13 @@ case class CompactFilterHeaderDAO()(implicit } } - /** This looks for best filter headers whose [[CompactFilterHeaderDb.blockHashBE]] are associated with the given + /** This looks for best filter headers whose + * [[CompactFilterHeaderDb.blockHashBE]] are associated with the given * [[BlockHeaderDb.hashBE]] given as a parameter. */ def getBestFilterHeaderForHeaders( - headers: Vector[BlockHeaderDb]): Future[Option[CompactFilterHeaderDb]] = { + headers: Vector[BlockHeaderDb] + ): Future[Option[CompactFilterHeaderDb]] = { val hashes = headers.map(_.hashBE) val join = table .join(blockHeaderTable) @@ -197,17 +204,20 @@ case class CompactFilterHeaderDAO()(implicit def getBetweenHeights( from: Int, - to: Int): Future[Vector[CompactFilterHeaderDb]] = { + to: Int + ): Future[Vector[CompactFilterHeaderDb]] = { val query = getBetweenHeightsQuery(from, to) safeDatabase.runVec(query) } def getBetweenHeightsQuery( from: Int, - to: Int): profile.StreamingProfileAction[ - Seq[CompactFilterHeaderDb], - CompactFilterHeaderDb, - Effect.Read] = { + to: Int + ): profile.StreamingProfileAction[Seq[ + CompactFilterHeaderDb + ], + CompactFilterHeaderDb, + Effect.Read] = { table.filter(header => header.height >= from && header.height <= to).result } diff --git a/chain/src/main/scala/org/bitcoins/chain/pow/Pow.scala b/chain/src/main/scala/org/bitcoins/chain/pow/Pow.scala index d16db68995..9405f0eccd 100644 --- a/chain/src/main/scala/org/bitcoins/chain/pow/Pow.scala +++ b/chain/src/main/scala/org/bitcoins/chain/pow/Pow.scala @@ -8,16 +8,19 @@ import org.bitcoins.core.protocol.blockchain._ import org.bitcoins.core.util.NumberUtil /** Implements functions found inside of bitcoin core's - * @see [[https://github.com/bitcoin/bitcoin/blob/35477e9e4e3f0f207ac6fa5764886b15bf9af8d0/src/pow.cpp pow.cpp]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/35477e9e4e3f0f207ac6fa5764886b15bf9af8d0/src/pow.cpp pow.cpp]] */ sealed abstract class Pow { /** Gets the next proof of work requirement for a block - * @see [[https://github.com/bitcoin/bitcoin/blob/35477e9e4e3f0f207ac6fa5764886b15bf9af8d0/src/pow.cpp#L13 Mimics bitcoin core implementation]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/35477e9e4e3f0f207ac6fa5764886b15bf9af8d0/src/pow.cpp#L13 Mimics bitcoin core implementation]] */ def getNetworkWorkRequired( newPotentialTip: BlockHeader, - blockchain: Blockchain)(implicit config: ChainAppConfig): UInt32 = { + blockchain: Blockchain + )(implicit config: ChainAppConfig): UInt32 = { val chainParams = config.chain val tip = blockchain.tip val currentHeight = tip.height @@ -34,7 +37,7 @@ sealed abstract class Pow { chainParams.compressedPowLimit } else { // Return the last non-special-min-difficulty-rules-block - //while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit) + // while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit) // pindex = pindex->pprev; val nonMinDiffF = blockchain.find { h => h.nBits != chainParams.compressedPowLimit || h.height % chainParams.difficultyChangeInterval == 0 @@ -48,9 +51,10 @@ sealed abstract class Pow { RegTestNetChainParams.compressedPowLimit case TestNetChainParams | MainNetChainParams | SigNetChainParams(_) => - //if we can't find a non min difficulty block, let's just fail + // if we can't find a non min difficulty block, let's just fail throw new RuntimeException( - s"Could not find non mindifficulty block in chain of size=${blockchain.length}! hash=${tip.hashBE.hex} height=${currentHeight}") + s"Could not find non mindifficulty block in chain of size=${blockchain.length}! hash=${tip.hashBE.hex} height=${currentHeight}" + ) } } @@ -64,19 +68,23 @@ sealed abstract class Pow { require( firstHeight >= 0, - s"We must have our first height be positive, got=${firstHeight}") + s"We must have our first height be positive, got=${firstHeight}" + ) val firstBlockAtIntervalOpt: Option[BlockHeaderDb] = blockchain.findAtHeight(firstHeight) firstBlockAtIntervalOpt match { case Some(firstBlockAtInterval) => - calculateNextWorkRequired(currentTip = tip, - firstBlockAtInterval, - chainParams) + calculateNextWorkRequired( + currentTip = tip, + firstBlockAtInterval, + chainParams + ) case None => throw new RuntimeException( - s"Could not find block at height=$firstHeight out of ${blockchain.length} headers to calculate pow difficulty change") + s"Could not find block at height=$firstHeight out of ${blockchain.length} headers to calculate pow difficulty change" + ) } } @@ -85,7 +93,8 @@ sealed abstract class Pow { } /** Calculate the next proof of work requirement for our blockchain - * @see [[https://github.com/bitcoin/bitcoin/blob/35477e9e4e3f0f207ac6fa5764886b15bf9af8d0/src/pow.cpp#L49 bitcoin core implementation]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/35477e9e4e3f0f207ac6fa5764886b15bf9af8d0/src/pow.cpp#L49 bitcoin core implementation]] * @param currentTip * @param firstBlock * @param chainParams @@ -94,7 +103,8 @@ sealed abstract class Pow { def calculateNextWorkRequired( currentTip: BlockHeaderDb, firstBlock: BlockHeaderDb, - chainParams: ChainParams): UInt32 = { + chainParams: ChainParams + ): UInt32 = { if (chainParams.noRetargeting) { currentTip.nBits } else { diff --git a/chain/src/main/scala/org/bitcoins/chain/validation/TipUpdateResult.scala b/chain/src/main/scala/org/bitcoins/chain/validation/TipUpdateResult.scala index 540b12761d..e5b5e2e9c7 100644 --- a/chain/src/main/scala/org/bitcoins/chain/validation/TipUpdateResult.scala +++ b/chain/src/main/scala/org/bitcoins/chain/validation/TipUpdateResult.scala @@ -3,8 +3,7 @@ package org.bitcoins.chain.validation import org.bitcoins.core.api.chain.db.BlockHeaderDb import org.bitcoins.core.protocol.blockchain.BlockHeader -/** Represents the result of updating the chain with - * the given header +/** Represents the result of updating the chain with the given header */ sealed abstract class TipUpdateResult { def header: BlockHeader @@ -19,7 +18,10 @@ object TipUpdateResult { sealed abstract class Failure extends TipUpdateResult - /** Means that [[org.bitcoins.core.protocol.blockchain.BlockHeader.previousBlockHashBE previousBlockHashBE]] was incorrect */ + /** Means that + * [[org.bitcoins.core.protocol.blockchain.BlockHeader.previousBlockHashBE previousBlockHashBE]] + * was incorrect + */ case class BadPreviousBlockHash(override val header: BlockHeader) extends Failure { @@ -27,9 +29,15 @@ object TipUpdateResult { s"BadPreviousBlockHash(hash=${header.hashBE}, previous=${header.previousBlockHashBE})" } - /** Means that [[org.bitcoins.core.protocol.blockchain.BlockHeader.nBits nBits]] was invalid */ + /** Means that + * [[org.bitcoins.core.protocol.blockchain.BlockHeader.nBits nBits]] was + * invalid + */ case class BadPOW(override val header: BlockHeader) extends Failure - /** Means that [[org.bitcoins.core.protocol.blockchain.BlockHeader.nonce nonce]] was invalid */ + /** Means that + * [[org.bitcoins.core.protocol.blockchain.BlockHeader.nonce nonce]] was + * invalid + */ case class BadNonce(override val header: BlockHeader) extends Failure } diff --git a/chain/src/main/scala/org/bitcoins/chain/validation/TipValidation.scala b/chain/src/main/scala/org/bitcoins/chain/validation/TipValidation.scala index 90d6f064eb..d8a8a19de2 100644 --- a/chain/src/main/scala/org/bitcoins/chain/validation/TipValidation.scala +++ b/chain/src/main/scala/org/bitcoins/chain/validation/TipValidation.scala @@ -9,25 +9,29 @@ import org.bitcoins.core.number.UInt32 import org.bitcoins.core.protocol.blockchain.BlockHeader import org.bitcoins.core.util.NumberUtil -/** Responsible for checking if we can connect two - * block headers together on the blockchain. The checks - * things like proof of work difficulty, if it +/** Responsible for checking if we can connect two block headers together on the + * blockchain. The checks things like proof of work difficulty, if it * references the previous block header correctly etc. */ sealed abstract class TipValidation extends ChainVerificationLogger { - /** Checks if the given header can be connected to the current tip - * This is the method where a [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] is transformed into a - * [[org.bitcoins.chain.models.BlockHeaderDb BlockHeaderDb]]. What this really means is that a height is - * assigned to a [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] after all these - * validation checks occur + /** Checks if the given header can be connected to the current tip This is the + * method where a + * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] is + * transformed into a + * [[org.bitcoins.chain.models.BlockHeaderDb BlockHeaderDb]]. What this + * really means is that a height is assigned to a + * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] after + * all these validation checks occur */ def checkNewTip(newPotentialTip: BlockHeader, blockchain: Blockchain)(implicit - conf: ChainAppConfig): TipUpdateResult = { + conf: ChainAppConfig + ): TipUpdateResult = { val header = newPotentialTip val currentTip = blockchain.tip logger.trace( - s"Checking header=${header.hashBE.hex} to try to connect to currentTip=${currentTip.hashBE.hex} with height=${currentTip.height}") + s"Checking header=${header.hashBE.hex} to try to connect to currentTip=${currentTip.hashBE.hex} with height=${currentTip.height}" + ) val expectedWork: UInt32 = isBadPow(newPotentialTip = newPotentialTip, blockchain = blockchain)(conf) @@ -35,10 +39,11 @@ sealed abstract class TipValidation extends ChainVerificationLogger { val connectTipResult: TipUpdateResult = { if (header.previousBlockHashBE != currentTip.hashBE) { logger.warn( - s"Failed to connect tip=${header.hashBE.hex} to current chain") + s"Failed to connect tip=${header.hashBE.hex} to current chain" + ) TipUpdateResult.BadPreviousBlockHash(newPotentialTip) } else if (header.nBits != expectedWork) { - //https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/pow.cpp#L19 + // https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/pow.cpp#L19 TipUpdateResult.BadPOW(newPotentialTip) } else if (isBadNonce(newPotentialTip)) { TipUpdateResult.BadNonce(newPotentialTip) @@ -56,31 +61,37 @@ sealed abstract class TipValidation extends ChainVerificationLogger { connectTipResult } - /** Logs the result of [[org.bitcoins.chain.validation.TipValidation.checkNewTip() checkNewTip]] */ + /** Logs the result of + * [[org.bitcoins.chain.validation.TipValidation.checkNewTip() checkNewTip]] + */ private def logTipResult( connectTipResult: TipUpdateResult, - currentTip: BlockHeaderDb): Unit = { + currentTip: BlockHeaderDb + ): Unit = { connectTipResult match { case TipUpdateResult.Success(tipDb) => logger.trace( - s"Successfully connected ${tipDb.hashBE.hex} with height=${tipDb.height} to block=${currentTip.hashBE.hex} with height=${currentTip.height}") + s"Successfully connected ${tipDb.hashBE.hex} with height=${tipDb.height} to block=${currentTip.hashBE.hex} with height=${currentTip.height}" + ) case bad: TipUpdateResult.Failure => logger.warn( - s"Failed to connect ${bad.header.hashBE.hex} to ${currentTip.hashBE.hex} with height=${currentTip.height}, reason=${bad}") + s"Failed to connect ${bad.header.hashBE.hex} to ${currentTip.hashBE.hex} with height=${currentTip.height}, reason=${bad}" + ) } () } - /** Checks if the given header hashes to meet the POW requirements for - * this block (determined by lookinng at the `nBits` field). + /** Checks if the given header hashes to meet the POW requirements for this + * block (determined by lookinng at the `nBits` field). * - * @see [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/pow.cpp#L74 pow.cpp]] - * in Bitcoin Core + * @see + * [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/pow.cpp#L74 pow.cpp]] + * in Bitcoin Core */ def isBadNonce(header: BlockHeader): Boolean = { - //convert hash into a big integer + // convert hash into a big integer val headerWork = BigInt(1, header.hashBE.bytes.toArray) if (headerWork <= 0 || NumberUtil.isNBitsOverflow(nBits = header.nBits)) { true @@ -90,9 +101,12 @@ sealed abstract class TipValidation extends ChainVerificationLogger { } private def isBadPow(newPotentialTip: BlockHeader, blockchain: Blockchain)( - config: ChainAppConfig): UInt32 = { - Pow.getNetworkWorkRequired(newPotentialTip = newPotentialTip, - blockchain = blockchain)(config) + config: ChainAppConfig + ): UInt32 = { + Pow.getNetworkWorkRequired( + newPotentialTip = newPotentialTip, + blockchain = blockchain + )(config) } } diff --git a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningChannelOpenerTest.scala b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningChannelOpenerTest.scala index 56e52f9b95..958ec48a26 100644 --- a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningChannelOpenerTest.scala +++ b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningChannelOpenerTest.scala @@ -18,13 +18,16 @@ class CLightningChannelOpenerTest extends CLightningChannelOpenerFixture { for { _ <- CLightningRpcTestUtil.connectLNNodes(clightningA, clightningB) nodeId <- clightningB.nodeId - fundDetails <- clightningA.initChannelOpen(nodeId = nodeId, - amount = amount, - privateChannel = false) + fundDetails <- clightningA.initChannelOpen( + nodeId = nodeId, + amount = amount, + privateChannel = false + ) } yield { assert( fundDetails.funding_address.scriptPubKey - .isInstanceOf[P2WSHWitnessSPKV0]) + .isInstanceOf[P2WSHWitnessSPKV0] + ) } } @@ -40,14 +43,18 @@ class CLightningChannelOpenerTest extends CLightningChannelOpenerFixture { _ = assert(preChannelsB.isEmpty) nodeId <- clightningB.nodeId - fundDetails <- clightningA.initChannelOpen(nodeId = nodeId, - amount = amount, - privateChannel = false) + fundDetails <- clightningA.initChannelOpen( + nodeId = nodeId, + amount = amount, + privateChannel = false + ) // construct psbt psbt <- bitcoind - .walletCreateFundedPsbt(Vector.empty, - Map(fundDetails.funding_address -> amount)) + .walletCreateFundedPsbt( + Vector.empty, + Map(fundDetails.funding_address -> amount) + ) .map(_.psbt) // fund channel with psbt _ <- clightningA.completeChannelOpen(nodeId, psbt) @@ -66,11 +73,13 @@ class CLightningChannelOpenerTest extends CLightningChannelOpenerFixture { _ <- TestAsyncUtil.awaitConditionF( () => clightningA.listChannels().map(_.nonEmpty), interval = 1.second, - maxTries = 500) + maxTries = 500 + ) _ <- TestAsyncUtil.awaitConditionF( () => clightningB.listChannels().map(_.nonEmpty), interval = 1.second, - maxTries = 500) + maxTries = 500 + ) } yield succeed } @@ -86,14 +95,18 @@ class CLightningChannelOpenerTest extends CLightningChannelOpenerFixture { _ = assert(preChannelsB.isEmpty) nodeId <- clightningB.nodeId - fundDetails <- clightningA.initChannelOpen(nodeId = nodeId, - amount = amount, - privateChannel = false) + fundDetails <- clightningA.initChannelOpen( + nodeId = nodeId, + amount = amount, + privateChannel = false + ) // construct psbt psbt <- bitcoind - .walletCreateFundedPsbt(Vector.empty, - Map(fundDetails.funding_address -> amount)) + .walletCreateFundedPsbt( + Vector.empty, + Map(fundDetails.funding_address -> amount) + ) .map(_.psbt) // fund channel with psbt _ <- clightningA.completeChannelOpen(nodeId, psbt) @@ -115,11 +128,13 @@ class CLightningChannelOpenerTest extends CLightningChannelOpenerFixture { _ <- TestAsyncUtil.awaitConditionF( () => clightningA.listChannels().map(_.isEmpty), interval = 1.second, - maxTries = 500) + maxTries = 500 + ) _ <- TestAsyncUtil.awaitConditionF( () => clightningB.listChannels().map(_.isEmpty), interval = 1.second, - maxTries = 500) + maxTries = 500 + ) } yield succeed } } diff --git a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningClientPairTest.scala b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningClientPairTest.scala index 53ad559407..51cbe94f52 100644 --- a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningClientPairTest.scala +++ b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningClientPairTest.scala @@ -65,15 +65,19 @@ class CLightningClientPairTest extends DualCLightningFixture { utxo <- clightning.listFunds.map(_.outputs.head) prevOut = TransactionOutput(utxo.value, utxo.scriptpubkey) - input = TransactionInput(utxo.outPoint, - EmptyScriptSignature, - TransactionConstants.sequence) + input = TransactionInput( + utxo.outPoint, + EmptyScriptSignature, + TransactionConstants.sequence + ) output = TransactionOutput(Bitcoins(0.5), bitcoindAddr.scriptPubKey) - tx = BaseTransaction(Int32.two, - Vector(input), - Vector(output), - UInt32.zero) + tx = BaseTransaction( + Int32.two, + Vector(input), + Vector(output), + UInt32.zero + ) unsigned = PSBT .fromUnsignedTx(tx) @@ -98,10 +102,12 @@ class CLightningClientPairTest extends DualCLightningFixture { val amount = Satoshis(100) for { - invoiceResult <- clightningA.createInvoice(amount = amount, - label = "label", - description = "description", - expirySeconds = 500) + invoiceResult <- clightningA.createInvoice( + amount = amount, + label = "label", + description = "description", + expirySeconds = 500 + ) payment <- clightningB.payInvoice(invoiceResult.bolt11) _ = assert(payment.payment_hash == invoiceResult.payment_hash) _ = assert(payment.msatoshi.toSatoshis == amount) @@ -120,10 +126,12 @@ class CLightningClientPairTest extends DualCLightningFixture { val label = "testLabel" for { - invoiceResult <- clightningA.createInvoice(amount = amount, - label = label, - description = "description", - expirySeconds = 500) + invoiceResult <- clightningA.createInvoice( + amount = amount, + label = label, + description = "description", + expirySeconds = 500 + ) _ = system.scheduler.scheduleOnce(3.seconds) { clightningB.payInvoice(invoiceResult.bolt11) @@ -171,7 +179,8 @@ class CLightningClientPairTest extends DualCLightningFixture { result <- clightningA.sendCustomMessage( nodeId, BigSizeUInt(48001), - hex"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") + hex"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" + ) } yield { assert(result.status.nonEmpty) } diff --git a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningJsonModelParsingTest.scala b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningJsonModelParsingTest.scala index 7d4d2a79ec..8e8aeabf0a 100644 --- a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningJsonModelParsingTest.scala +++ b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningJsonModelParsingTest.scala @@ -17,7 +17,8 @@ class CLightningJsonModelParsingTest extends BitcoinSUnitTest { assert(result.error.isDefined) case JsError(errors) => fail( - s"Failed to parse ListFundsResult, errors: ${errors.mkString("\n")}") + s"Failed to parse ListFundsResult, errors: ${errors.mkString("\n")}" + ) } } @@ -32,7 +33,8 @@ class CLightningJsonModelParsingTest extends BitcoinSUnitTest { assert(result.channels.size == 1) case JsError(errors) => fail( - s"Failed to parse ListFundsResult, errors: ${errors.mkString("\n")}") + s"Failed to parse ListFundsResult, errors: ${errors.mkString("\n")}" + ) } } } diff --git a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningRpcClientTest.scala b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningRpcClientTest.scala index 58985954cf..80d80b3acf 100644 --- a/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningRpcClientTest.scala +++ b/clightning-rpc-test/src/test/scala/com/bitcoins/clightning/rpc/CLightningRpcClientTest.scala @@ -33,7 +33,8 @@ class CLightningRpcClientTest extends CLightningFixture { addr2 <- client.getNewAddress(AddressType.SegWit) addr3 <- client.getNewAddress(AddressType.NestedSegWit) _ <- recoverToSucceededIf[IllegalArgumentException]( - client.getNewAddress(AddressType.Legacy)) + client.getNewAddress(AddressType.Legacy) + ) } yield { assert(addr1.isInstanceOf[Bech32Address]) assert(addr2.isInstanceOf[Bech32Address]) diff --git a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningRpcClient.scala b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningRpcClient.scala index 84a161cd1d..67c98fb26d 100644 --- a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningRpcClient.scala +++ b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningRpcClient.scala @@ -25,8 +25,8 @@ import java.net.InetSocketAddress import scala.concurrent.{ExecutionContext, Future} class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( - implicit val executionContext: ExecutionContext) - extends CLightningUnixSocketHandler + implicit val executionContext: ExecutionContext +) extends CLightningUnixSocketHandler with NativeProcessFactory with StartStopAsync[CLightningRpcClient] with BitcoinSLogger { @@ -49,7 +49,9 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( case AddressType.Legacy => Future.failed( new IllegalArgumentException( - "clightning cannot generate legacy addresses")) + "clightning cannot generate legacy addresses" + ) + ) } for { @@ -62,8 +64,10 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( def listFunds: Future[ListFundsResult] = listFunds(false) def listFunds(spent: Boolean): Future[ListFundsResult] = - clightningCall[ListFundsResult]("listfunds", - JsArray(Vector(JsBoolean(spent)))) + clightningCall[ListFundsResult]( + "listfunds", + JsArray(Vector(JsBoolean(spent))) + ) def walletBalance(): Future[WalletBalances] = { listFunds.map { funds => @@ -75,8 +79,10 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( case OutputStatus.Spent => balances case OutputStatus.Unconfirmed => val newUnconfirmed = balances.unconfirmedBalance + amt - balances.copy(balance = newTotal, - unconfirmedBalance = newUnconfirmed) + balances.copy( + balance = newTotal, + unconfirmedBalance = newUnconfirmed + ) case OutputStatus.Confirmed => val newConfirmed = balances.confirmedBalance + amt balances.copy(balance = newTotal, confirmedBalance = newConfirmed) @@ -91,16 +97,20 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( def connect( nodeId: NodeId, host: String, - port: Int): Future[ConnectResult] = { + port: Int + ): Future[ConnectResult] = { val uri = NodeUri(nodeId, host, port) connect(uri) } def connect(uri: NodeUri): Future[ConnectResult] = { val params = JsArray( - Vector(JsString(uri.nodeId.toString), - JsString(uri.host), - JsNumber(uri.port))) + Vector( + JsString(uri.nodeId.toString), + JsString(uri.host), + JsNumber(uri.port) + ) + ) clightningCall[ConnectResult]("connect", params) } @@ -128,7 +138,8 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( fundingAmount: CurrencyUnit, pushAmt: CurrencyUnit, feeRate: FeeUnit, - privateChannel: Boolean): Future[FundChannelResult] = { + privateChannel: Boolean + ): Future[FundChannelResult] = { val params = JsObject( Vector( @@ -137,7 +148,8 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( "feerate" -> feeRateToJson(feeRate), "announce" -> JsBoolean(privateChannel), "push_msat" -> JsNumber(MilliSatoshis(pushAmt).toLong) - )) + ) + ) clightningCall[FundChannelResult]("fundchannel", params) } @@ -172,14 +184,16 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( amount: CurrencyUnit, label: String, description: String, - expirySeconds: Long): Future[CLightningInvoiceResult] = { + expirySeconds: Long + ): Future[CLightningInvoiceResult] = { val params = JsObject( Vector( "msatoshi" -> JsNumber(MilliSatoshis(amount).toLong), "label" -> JsString(label), "description" -> JsString(description), "expiry" -> JsNumber(expirySeconds) - )) + ) + ) clightningCall[CLightningInvoiceResult]("invoice", params) } @@ -187,24 +201,28 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( def payInvoice(invoice: LnInvoice): Future[CLightningPayResult] = { clightningCall[CLightningPayResult]( "pay", - JsArray(Vector(JsString(invoice.toString)))) + JsArray(Vector(JsString(invoice.toString))) + ) } def payInvoice( invoice: LnInvoice, - amount: CurrencyUnit): Future[CLightningPayResult] = { + amount: CurrencyUnit + ): Future[CLightningPayResult] = { val params = JsArray( - Vector(JsString(invoice.toString), - JsNumber(MilliSatoshis(amount).toLong))) + Vector(JsString(invoice.toString), JsNumber(MilliSatoshis(amount).toLong)) + ) clightningCall[CLightningPayResult]("pay", params) } - def lookupInvoice(paymentHash: Sha256Digest): Future[ - Option[CLightningLookupInvoiceResult]] = { + def lookupInvoice( + paymentHash: Sha256Digest + ): Future[Option[CLightningLookupInvoiceResult]] = { val params = JsObject(Vector("payment_hash" -> JsString(paymentHash.hex))) clightningCall[CLightningListInvoicesResult]("listinvoices", params).map( - _.invoices.headOption) + _.invoices.headOption + ) } def listInvoices: Future[Vector[CLightningLookupInvoiceResult]] = { @@ -214,37 +232,45 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( def waitInvoice(label: String): Future[CLightningLookupInvoiceResult] = { clightningCall[CLightningLookupInvoiceResult]( "waitinvoice", - JsArray(Vector(JsString(label)))) + JsArray(Vector(JsString(label))) + ) } def reserveInputs(psbt: PSBT): Future[Vector[InputReservation]] = { val param = JsArray(Vector(JsString(psbt.base64))) clightningCall[InputReservations]("reserveinputs", param).map( - _.reservations) + _.reservations + ) } def reserveInputs( psbt: PSBT, - exclusive: Boolean): Future[Vector[InputReservation]] = { + exclusive: Boolean + ): Future[Vector[InputReservation]] = { val param = JsArray(Vector(JsString(psbt.base64), JsBoolean(exclusive))) clightningCall[InputReservations]("reserveinputs", param).map( - _.reservations) + _.reservations + ) } def reserveInputs( psbt: PSBT, exclusive: Boolean, - reserve: Int): Future[Vector[InputReservation]] = { + reserve: Int + ): Future[Vector[InputReservation]] = { val param = JsArray( - Vector(JsString(psbt.base64), JsBoolean(exclusive), JsNumber(reserve))) + Vector(JsString(psbt.base64), JsBoolean(exclusive), JsNumber(reserve)) + ) clightningCall[InputReservations]("reserveinputs", param).map( - _.reservations) + _.reservations + ) } def signPSBT(psbt: PSBT): Future[PSBT] = { clightningCall[CLightningPsbtResult]( "signpsbt", - JsArray(Vector(JsString(psbt.base64)))).map(_.signed_psbt) + JsArray(Vector(JsString(psbt.base64))) + ).map(_.signed_psbt) } def signPSBT(psbt: PSBT, indexesToSign: Vector[Int]): Future[PSBT] = { @@ -252,34 +278,40 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( Vector( "psbt" -> JsString(psbt.base64), "signonly" -> JsArray(indexesToSign.map(JsNumber(_))) - )) + ) + ) clightningCall[CLightningPsbtResult]("signpsbt", params).map(_.signed_psbt) } def listTransactions(): Future[Vector[CLightningTransaction]] = clightningCall[ListTransactionsResults]("listtransactions").map( - _.transactions) + _.transactions + ) def withdraw( address: BitcoinAddress, - amount: Satoshis): Future[WithdrawResult] = + amount: Satoshis + ): Future[WithdrawResult] = sendToAddress(address, amount) def withdraw( address: BitcoinAddress, amount: Satoshis, - feeRate: FeeUnit): Future[WithdrawResult] = + feeRate: FeeUnit + ): Future[WithdrawResult] = sendToAddress(address, amount, feeRate) def sendToAddress( address: BitcoinAddress, - amount: Satoshis): Future[WithdrawResult] = { + amount: Satoshis + ): Future[WithdrawResult] = { val params = JsObject( Vector( "destination" -> JsString(address.toString), "satoshi" -> JsNumber(amount.toLong) - )) + ) + ) clightningCall[WithdrawResult]("withdraw", params) } @@ -287,13 +319,15 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( def sendToAddress( address: BitcoinAddress, amount: Satoshis, - feeRate: FeeUnit): Future[WithdrawResult] = { + feeRate: FeeUnit + ): Future[WithdrawResult] = { val params = JsObject( Vector( "destination" -> JsString(address.toString), "satoshi" -> JsNumber(amount.toLong), "feerate" -> feeRateToJson(feeRate) - )) + ) + ) clightningCall[WithdrawResult]("withdraw", params) } @@ -301,22 +335,26 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( def initChannelOpen( nodeId: NodeId, amount: CurrencyUnit, - privateChannel: Boolean): Future[FundChannelStartResult] = { + privateChannel: Boolean + ): Future[FundChannelStartResult] = { val params = JsObject( Vector( "id" -> JsString(nodeId.toString), "amount" -> JsNumber(amount.satoshis.toLong), "announce" -> JsBoolean(privateChannel) - )) + ) + ) clightningCall[FundChannelStartResult]("fundchannel_start", params) } def completeChannelOpen( nodeId: NodeId, - psbt: PSBT): Future[FundChannelCompleteResult] = { + psbt: PSBT + ): Future[FundChannelCompleteResult] = { val params = JsArray( - Vector(JsString(nodeId.toString), JsString(psbt.base64))) + Vector(JsString(nodeId.toString), JsString(psbt.base64)) + ) clightningCall[FundChannelCompleteResult]("fundchannel_complete", params) } @@ -330,26 +368,30 @@ class CLightningRpcClient(val instance: CLightningInstanceLocal, binary: File)( def sendCustomMessage( peer: NodeId, tpe: BigSizeUInt, - data: ByteVector): Future[SendCustomMessageResult] = { + data: ByteVector + ): Future[SendCustomMessageResult] = { val tlv = TLV.fromTypeAndValue(tpe, data) sendCustomMessage(peer, tlv) } def sendCustomMessage( peer: NodeId, - tlv: TLV): Future[SendCustomMessageResult] = { + tlv: TLV + ): Future[SendCustomMessageResult] = { val lnMessage = LnMessage[TLV](tlv) sendCustomMessage(peer, lnMessage) } def sendCustomMessage( peer: NodeId, - lnMessage: LnMessage[TLV]): Future[SendCustomMessageResult] = { + lnMessage: LnMessage[TLV] + ): Future[SendCustomMessageResult] = { val params = JsObject( Vector( "node_id" -> JsString(peer.toString), "msg" -> JsString(lnMessage.hex) - )) + ) + ) clightningCall[SendCustomMessageResult]("sendcustommsg", params) } diff --git a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningUnixSocketHandler.scala b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningUnixSocketHandler.scala index 09bb8f1851..dc4ec69913 100644 --- a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningUnixSocketHandler.scala +++ b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/CLightningUnixSocketHandler.scala @@ -13,7 +13,8 @@ import scala.util._ abstract class CLightningUnixSocketHandler { self: CLightningRpcClient => def clightningCall[T](command: String, parameters: JsValue = JsArray.empty)( - implicit reader: Reads[T]): Future[T] = { + implicit reader: Reads[T] + ): Future[T] = { logger.trace(s"clightning rpc call $command") val responseF = sendRequest(command, parameters) @@ -23,7 +24,8 @@ abstract class CLightningUnixSocketHandler { self: CLightningRpcClient => } private def parseResult[T](payload: RpcResult, commandName: String)(implicit - reader: Reads[T]): T = { + reader: Reads[T] + ): T = { payload.result match { case Some(result) => result.validate[T] match { @@ -46,11 +48,13 @@ abstract class CLightningUnixSocketHandler { self: CLightningRpcClient => throw new RuntimeException(err.message) case JsError(_) => throw new RuntimeException( - s"Could not parse error for command: $commandName, json: $errJs") + s"Could not parse error for command: $commandName, json: $errJs" + ) } case None => throw new RuntimeException( - s"Did not get result or error for command: $commandName") + s"Did not get result or error for command: $commandName" + ) } } } @@ -69,12 +73,15 @@ abstract class CLightningUnixSocketHandler { self: CLightningRpcClient => private def sendRequest( methodName: String, - params: JsValue): Future[RpcResult] = { + params: JsValue + ): Future[RpcResult] = { val uuid = UUID.randomUUID().toString - val map: Map[String, JsValue] = Map("jsonrpc" -> JsString("2.0"), - "id" -> JsString(uuid), - "method" -> JsString(methodName), - "params" -> params) + val map: Map[String, JsValue] = Map( + "jsonrpc" -> JsString("2.0"), + "id" -> JsString(uuid), + "method" -> JsString(methodName), + "params" -> params + ) val request: ByteString = HttpEntity(ContentTypes.`application/json`, JsObject(map).toString()).data @@ -133,7 +140,8 @@ private[clightning] case class RpcResult( jsonrpc: String, id: String, result: Option[JsValue], - error: Option[JsValue]) + error: Option[JsValue] +) private[clightning] case class RpcError(code: Long, message: String) diff --git a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningConfig.scala b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningConfig.scala index 0b07a47ca9..8ea51fc672 100644 --- a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningConfig.scala +++ b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningConfig.scala @@ -10,56 +10,57 @@ import java.net.URI import java.nio.file.{Files, Path, Paths} import scala.util.Properties -/** This class represents a parsed `lightning.conf` file. It - * respects the different ways of writing options in - * `lightning.conf`: Raw options, network-prefixed options - * and options within network sections. It also tries to - * conform to the way clightning gives precedence to the - * different properties. +/** This class represents a parsed `lightning.conf` file. It respects the + * different ways of writing options in `lightning.conf`: Raw options, + * network-prefixed options and options within network sections. It also tries + * to conform to the way clightning gives precedence to the different + * properties. * - * Not all options are exposed from this class. We only - * expose those that are of relevance when making RPC - * requests. + * Not all options are exposed from this class. We only expose those that are + * of relevance when making RPC requests. */ case class CLightningConfig( private[bitcoins] val lines: Seq[String], - datadir: File) - extends BitcoinSLogger { + datadir: File +) extends BitcoinSLogger { - //create datadir and config if it DNE on disk + // create datadir and config if it DNE on disk if (!datadir.exists()) { logger.debug( - s"datadir=${datadir.getAbsolutePath} does not exist, creating now") + s"datadir=${datadir.getAbsolutePath} does not exist, creating now" + ) datadir.mkdirs() CLightningConfig.writeConfigToFile(this, datadir) } private val confFile = datadir.toPath.resolve("config") - //create config file in datadir if it does not exist + // create config file in datadir if it does not exist if (!Files.exists(confFile)) { logger.debug( - s"config in datadir=${datadir.getAbsolutePath} does not exist, creating now") + s"config in datadir=${datadir.getAbsolutePath} does not exist, creating now" + ) CLightningConfig.writeConfigToFile(this, datadir) } - /** Converts the config back to a string that can be written - * to file, and passed to `lightning` + /** Converts the config back to a string that can be written to file, and + * passed to `lightning` */ lazy val toWriteableString: String = lines.mkString("\n") - /** Splits the provided lines into pairs of keys/values - * based on `=`, and then applies the provided - * `collect` function on those pairs + /** Splits the provided lines into pairs of keys/values based on `=`, and then + * applies the provided `collect` function on those pairs */ - private def collectFrom(lines: Seq[String])( - collect: PartialFunction[(String, String), String]): Seq[String] = { + private def collectFrom( + lines: Seq[String] + )(collect: PartialFunction[(String, String), String]): Seq[String] = { val splittedPairs = { val splitLines = lines.map( _.split("=") .map(_.trim) - .toList) + .toList + ) splitLines.collect { case h :: t :: _ => h -> t @@ -121,7 +122,8 @@ case class CLightningConfig( val lines = newLine +: ourLines val newConfig = CLightningConfig(lines, datadir) logger.debug( - s"Appending new config with $key=$value to datadir=${datadir.getAbsolutePath}") + s"Appending new config with $key=$value to datadir=${datadir.getAbsolutePath}" + ) CLightningConfig.writeConfigToFile(newConfig, datadir) newConfig @@ -150,8 +152,8 @@ object CLightningConfig override lazy val empty: CLightningConfig = CLightningConfig("", DEFAULT_DATADIR) - /** Constructs a `lightning` config from the given string, - * by splitting it on newlines + /** Constructs a `lightning` config from the given string, by splitting it on + * newlines */ override def apply(config: String, datadir: File): CLightningConfig = apply(config.split("\n").toList, datadir) @@ -163,7 +165,8 @@ object CLightningConfig /** Reads the given file and construct a `lightning` config from it */ override def apply( config: File, - datadir: File = DEFAULT_DATADIR): CLightningConfig = { + datadir: File = DEFAULT_DATADIR + ): CLightningConfig = { import org.bitcoins.core.compat.JavaConverters._ val lines = Files .readAllLines(config.toPath) @@ -182,9 +185,8 @@ object CLightningConfig apply(dir.toPath.resolve("config")) } - /** If there is a `config` in the default - * data directory, this is read. Otherwise, the - * default configuration is returned. + /** If there is a `config` in the default data directory, this is read. + * Otherwise, the default configuration is returned. */ override def fromDefaultDatadir: CLightningConfig = { if (DEFAULT_CONF_FILE.isFile) { @@ -196,17 +198,21 @@ object CLightningConfig override val DEFAULT_DATADIR: File = { val path = if (Properties.isMac) { - Paths.get(Properties.userHome, - "Library", - "Application Support", - "lightning") + Paths.get( + Properties.userHome, + "Library", + "Application Support", + "lightning" + ) } else if (Properties.isWin) { - Paths.get("C:", - "Users", - Properties.userName, - "Appdata", - "Local", - "lightning") + Paths.get( + "C:", + "Users", + Properties.userName, + "Appdata", + "Local", + "lightning" + ) } else { Paths.get(Properties.userHome, ".lightning") } @@ -223,12 +229,13 @@ object CLightningConfig .resolve("lightning-rpc") .toFile - /** Writes the config to the data directory within it, if it doesn't - * exist. Returns the written file. + /** Writes the config to the data directory within it, if it doesn't exist. + * Returns the written file. */ override def writeConfigToFile( config: CLightningConfig, - datadir: File): Path = { + datadir: File + ): Path = { val confStr = config.lines.mkString("\n") @@ -237,7 +244,8 @@ object CLightningConfig if (datadir == DEFAULT_DATADIR && confFile == DEFAULT_CONF_FILE.toPath) { logger.warn( - s"We will not overwrite the existing config in default datadir") + s"We will not overwrite the existing config in default datadir" + ) } else { Files.write(confFile, confStr.getBytes) } diff --git a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningInstanceLocal.scala b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningInstanceLocal.scala index 28dc88607b..9877ec19dc 100644 --- a/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningInstanceLocal.scala +++ b/clightning-rpc/src/main/scala/com/bitcoins/clightning/rpc/config/CLightningInstanceLocal.scala @@ -17,7 +17,8 @@ case class CLightningInstanceLocal( listenBinding: URI, logFileOpt: Option[File], bitcoindAuthCredentials: PasswordBased, - bitcoindRpcUri: URI) + bitcoindRpcUri: URI +) object CLightningInstanceLocal extends InstanceFactoryLocal[CLightningInstanceLocal, ActorSystem] { @@ -36,8 +37,9 @@ object CLightningInstanceLocal } } - override def fromConfigFile(file: File = DEFAULT_CONF_FILE.toFile)(implicit - system: ActorSystem): CLightningInstanceLocal = { + override def fromConfigFile( + file: File = DEFAULT_CONF_FILE.toFile + )(implicit system: ActorSystem): CLightningInstanceLocal = { require(file.exists, s"${file.getPath} does not exist!") require(file.isFile, s"${file.getPath} is not a file!") @@ -46,8 +48,9 @@ object CLightningInstanceLocal fromConfig(config) } - override def fromDataDir(dir: File = DEFAULT_DATADIR.toFile)(implicit - system: ActorSystem): CLightningInstanceLocal = { + override def fromDataDir( + dir: File = DEFAULT_DATADIR.toFile + )(implicit system: ActorSystem): CLightningInstanceLocal = { require(dir.exists, s"${dir.getPath} does not exist!") require(dir.isDirectory, s"${dir.getPath} is not a directory!") diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/api/CallbackTest.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/api/CallbackTest.scala index e119e56216..cbd56cde65 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/api/CallbackTest.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/api/CallbackTest.scala @@ -21,12 +21,15 @@ class CallbackTest extends BitcoinSJvmTest { val runnable: Runnable = () => { if (!promise.isCompleted) { promise.failure( - new RuntimeException("2nd callback did not start before timeout")) + new RuntimeException("2nd callback did not start before timeout") + ) } } - AsyncUtil.scheduler.scheduleOnce(testTimeout.toMillis, - TimeUnit.MILLISECONDS, - runnable) + AsyncUtil.scheduler.scheduleOnce( + testTimeout.toMillis, + TimeUnit.MILLISECONDS, + runnable + ) promise.future.map(_ => ()) } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/ConstRandAdaptorSign.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/ConstRandAdaptorSign.scala index 8bfb7bf295..05f789ff68 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/ConstRandAdaptorSign.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/ConstRandAdaptorSign.scala @@ -10,7 +10,8 @@ case class ConstRandAdaptorSign(privKey: ECPrivateKey) extends AdaptorSign { override def adaptorSign( adaptorPoint: ECPublicKey, - msg: ByteVector): ECAdaptorSignature = { + msg: ByteVector + ): ECAdaptorSignature = { adaptorSign(adaptorPoint, msg, ConstRandAdaptorSign.constRand) } @@ -24,14 +25,16 @@ case class ConstRandAdaptorSign(privKey: ECPrivateKey) extends AdaptorSign { override def signWithEntropy( bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature = { + entropy: ByteVector + ): ECDigitalSignature = { privKey.signWithEntropy(bytes, entropy) } override def adaptorSign( adaptorPoint: ECPublicKey, msg: ByteVector, - auxRand: ByteVector): ECAdaptorSignature = { + auxRand: ByteVector + ): ECAdaptorSignature = { privKey.adaptorSign(adaptorPoint, msg, auxRand) } } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCFeeTestVector.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCFeeTestVector.scala index cc3d03af63..a984094e71 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCFeeTestVector.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCFeeTestVector.scala @@ -16,8 +16,8 @@ case class DLCFeeTestVector( offerFundingFee: Satoshis, offerClosingFee: Satoshis, acceptFundingFee: Satoshis, - acceptClosingFee: Satoshis) - extends TestVector { + acceptClosingFee: Satoshis +) extends TestVector { override def toJson: JsValue = { Json.toJson(this)(DLCFeeTestVector.dlcFeeTestVectorFormat) @@ -49,7 +49,8 @@ case class DLCFeeTestVectorInput( acceptInputs: Vector[FundingFeeInfo], acceptPayoutSPKLen: Int, acceptChangeSPKLen: Int, - feeRate: SatoshisPerVirtualByte) { + feeRate: SatoshisPerVirtualByte +) { lazy val mockDualFundingTxFinalizer: DualFundingTxFinalizer = { def mockSPK(len: Int): ScriptPubKey = { @@ -107,7 +108,8 @@ object DLCFeeTestVector extends TestVectorParser[DLCFeeTestVector] { acceptInputs: Vector[FundingFeeInfo], acceptPayoutSPKLen: Int, acceptChangeSPKLen: Int, - feeRate: SatoshisPerVirtualByte): DLCFeeTestVector = { + feeRate: SatoshisPerVirtualByte + ): DLCFeeTestVector = { DLCFeeTestVector( DLCFeeTestVectorInput( offerInputs, diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCFeeTestVectorGen.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCFeeTestVectorGen.scala index 2d665a3011..57ea8430de 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCFeeTestVectorGen.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCFeeTestVectorGen.scala @@ -12,7 +12,8 @@ object DLCFeeTestVectorGen extends TestVectorGen[DLCFeeTestVector, DLCFeeTestVectorInput] { override val defaultTestFile: File = new File( - "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_fee_test.json") + "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_fee_test.json" + ) override val testVectorParser: DLCFeeTestVector.type = DLCFeeTestVector @@ -22,8 +23,8 @@ object DLCFeeTestVectorGen override val inputStr: String = "inputs" - override def generateFromInput: DLCFeeTestVectorInput => Future[ - DLCFeeTestVector] = { input => + override def generateFromInput + : DLCFeeTestVectorInput => Future[DLCFeeTestVector] = { input => Future.successful(DLCFeeTestVector(input)) } @@ -55,7 +56,8 @@ object DLCFeeTestVectorGen def allTests( offerInputs: Vector[FundingFeeInfo], - acceptInputs: Vector[FundingFeeInfo]): Vector[DLCFeeTestVector] = { + acceptInputs: Vector[FundingFeeInfo] + ): Vector[DLCFeeTestVector] = { for { offerPayoutSPKLen <- payoutSPKLens offerChangeSPKLen <- changeSPKLens @@ -77,7 +79,8 @@ object DLCFeeTestVectorGen def someTests( offerInputs: Vector[FundingFeeInfo], - acceptInputs: Vector[FundingFeeInfo]): Vector[DLCFeeTestVector] = { + acceptInputs: Vector[FundingFeeInfo] + ): Vector[DLCFeeTestVector] = { allTests(offerInputs, acceptInputs) .sortBy(_ => scala.util.Random.nextDouble()) .take(10) diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCParsingTestVector.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCParsingTestVector.scala index a44ebdc30e..f469cfe0c6 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCParsingTestVector.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCParsingTestVector.scala @@ -25,7 +25,8 @@ sealed trait DLCParsingTestVector extends TestVector { "tpeName" -> JsString(tpeName), "input" -> JsString(input.hex), "fields" -> JsObject(jsonFields) - )) + ) + ) } } @@ -84,8 +85,8 @@ object ByteVectorWrapper { override def toString: String = { s"NamedMultiElement(${elements - .map { case (name, bytes) => s"$name -> $bytes" } - .mkString(",")})" + .map { case (name, bytes) => s"$name -> $bytes" } + .mkString(",")})" } override def toJson: JsValue = { @@ -128,14 +129,14 @@ object ByteVectorWrapper { case class DLCTLVTestVector( input: TLV, tpeName: String, - fields: Vector[(String, ByteVectorWrapper)]) - extends DLCParsingTestVector + fields: Vector[(String, ByteVectorWrapper)] +) extends DLCParsingTestVector case class DLCMessageTestVector( input: LnMessage[TLV], tpeName: String, - fields: Vector[(String, ByteVectorWrapper)]) - extends DLCParsingTestVector + fields: Vector[(String, ByteVectorWrapper)] +) extends DLCParsingTestVector object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { @@ -163,7 +164,8 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { "extraPrecision" -> Element(UInt16(point.extraPrecision)) ) case piece => Element(piece) - }) + } + ) ) DLCTLVTestVector(tlv, "payout_function_v0", fields) case PolynomialPayoutCurvePieceTLV(midpoints) => @@ -180,13 +182,15 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { }) ) DLCTLVTestVector(tlv, "polynomial_payout_curve_piece", fields) - case HyperbolaPayoutCurvePieceTLV(usePositivePiece, - translateOutcome, - translatePayout, - a, - b, - c, - d) => + case HyperbolaPayoutCurvePieceTLV( + usePositivePiece, + translateOutcome, + translatePayout, + a, + b, + c, + d + ) => def boolToElement(bool: Boolean): Element = { Element(ByteVector(if (bool) 1.toByte else 0.toByte)) } @@ -197,14 +201,18 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { "usePositivePiece" -> boolToElement(usePositivePiece), "translateOutcomeSign" -> boolToElement(translateOutcome.sign), "translateOutcome" -> Element( - BigSizeUInt(translateOutcome.withoutPrecision)), + BigSizeUInt(translateOutcome.withoutPrecision) + ), "translateOutcomeExtraPrecision" -> Element( - UInt16(translateOutcome.extraPrecision)), + UInt16(translateOutcome.extraPrecision) + ), "translatePayoutSign" -> boolToElement(translatePayout.sign), "translatePayout" -> Element( - BigSizeUInt(translatePayout.withoutPrecision)), + BigSizeUInt(translatePayout.withoutPrecision) + ), "translatePayoutExtraPrecision" -> Element( - UInt16(translatePayout.extraPrecision)), + UInt16(translatePayout.extraPrecision) + ), "aSign" -> boolToElement(a.sign), "a" -> Element(BigSizeUInt(a.withoutPrecision)), "aExtraPrecision" -> Element(UInt16(a.extraPrecision)), @@ -238,14 +246,18 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { "tpe" -> Element(ContractDescriptorV0TLV.tpe), "length" -> Element(tlv.length), "outcomes" -> MultiElement(outcomes.map { case (outcome, amt) => - NamedMultiElement("outcome" -> CryptoUtil.sha256(outcome).bytes, - "localPayout" -> amt.toUInt64.bytes) + NamedMultiElement( + "outcome" -> CryptoUtil.sha256(outcome).bytes, + "localPayout" -> amt.toUInt64.bytes + ) }) ) DLCTLVTestVector(tlv, "contract_descriptor_v0", fields) - case ContractDescriptorV1TLV(numDigits, - payoutFunction, - roundingIntervals) => + case ContractDescriptorV1TLV( + numDigits, + payoutFunction, + roundingIntervals + ) => val fields = Vector( "tpe" -> Element(ContractDescriptorV1TLV.tpe), "length" -> Element(tlv.length), @@ -263,7 +275,8 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { DLCTLVTestVector(tlv, "oracle_info_v0", fields) case OracleParamsV0TLV(maxErrorExp, minFailExp, maximizeCoverage) => val maximizeCoverageBytes = ByteVector( - if (maximizeCoverage) TLV.TRUE_BYTE else TLV.FALSE_BYTE) + if (maximizeCoverage) TLV.TRUE_BYTE else TLV.FALSE_BYTE + ) val fields = Vector( "tpe" -> Element(OracleParamsV0TLV.tpe), @@ -279,7 +292,8 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { "length" -> Element(tlv.length), "threshold" -> Element(UInt16(threshold)), "announcements" -> MultiElement( - announcements.toVector.map(Element(_))) + announcements.toVector.map(Element(_)) + ) ) DLCTLVTestVector(tlv, "oracle_info_v1", fields) case OracleInfoV2TLV(threshold, oracles, params) => @@ -312,16 +326,19 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { Vector( "contractDescriptor" -> Element(descriptor), "oracleInfo" -> Element(oracleInfo) - )) + ) + ) }) ) DLCTLVTestVector(tlv, "contract_info_v1", fields) - case FundingInputV0TLV(inputSerialId, - prevTx, - prevTxVout, - sequence, - maxWitnessLen, - redeemScriptOpt) => + case FundingInputV0TLV( + inputSerialId, + prevTx, + prevTxVout, + sequence, + maxWitnessLen, + redeemScriptOpt + ) => val redeemScript = redeemScriptOpt.getOrElse(EmptyScriptPubKey) @@ -344,8 +361,11 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { "length" -> Element(tlv.length), "sigs" -> MultiElement( sigs.map(sig => - NamedMultiElement("encryptedSig" -> sig.adaptedSig, - "dleqProof" -> sig.dleqProof))) + NamedMultiElement( + "encryptedSig" -> sig.adaptedSig, + "dleqProof" -> sig.dleqProof + )) + ) ) DLCTLVTestVector(tlv, "cet_adaptor_signatures_v0", fields) case FundingSignaturesV0TLV(witnesses) => @@ -360,27 +380,30 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { stackElem => NamedMultiElement( "stackElementLen" -> Element(UInt16(stackElem.length)), - "stackElement" -> stackElem) + "stackElement" -> stackElem + ) }) ) }) ) DLCTLVTestVector(tlv, "funding_signatures_v0", fields) - case DLCOfferTLV(versionOpt, - contractFlags, - chainHash, - contractInfo, - fundingPubKey, - payoutSPK, - payoutSerialId, - totalCollateralSatoshis, - fundingInputs, - changeSPK, - changeSerialId, - fundOutputSerialId, - feeRate, - contractMaturityBound, - contractTimeout) => + case DLCOfferTLV( + versionOpt, + contractFlags, + chainHash, + contractInfo, + fundingPubKey, + payoutSPK, + payoutSerialId, + totalCollateralSatoshis, + fundingInputs, + changeSPK, + changeSerialId, + fundOutputSerialId, + feeRate, + contractMaturityBound, + contractTimeout + ) => val version = versionOpt match { case Some(version) => Vector(PicklerKeys.protocolVersionKey -> Element(UInt16(version))) @@ -397,10 +420,12 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { "payoutSPK" -> Element(payoutSPK.asmBytes), "payoutSerialId" -> Element(payoutSerialId), "totalCollateralSatoshis" -> Element( - totalCollateralSatoshis.toUInt64), + totalCollateralSatoshis.toUInt64 + ), "fundingInputsLen" -> Element(UInt16(fundingInputs.length)), "fundingInputs" -> new MultiElement( - fundingInputs.map(input => Element(input.bytes))), + fundingInputs.map(input => Element(input.bytes)) + ), "changeSPKLen" -> Element(UInt16(changeSPK.asmBytes.length)), "changeSPK" -> Element(changeSPK.asmBytes), "changeSerialId" -> Element(changeSerialId), @@ -428,32 +453,37 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { "tpe" -> Element(NegotiationFieldsV2TLV.tpe), "length" -> Element(tlv.length), "nested_negotiation_fields" -> MultiElement( - nestedNegotiationFields.map(Element(_))) + nestedNegotiationFields.map(Element(_)) + ) ) DLCTLVTestVector(tlv, "negotiation_fields_v2", fields) - case DLCAcceptTLV(tempContractId, - totalCollateralSatoshis, - fundingPubKey, - payoutSPK, - payoutSerialId, - fundingInputs, - changeSPK, - changeSerialId, - cetSignatures, - refundSignature, - negotiationFields) => + case DLCAcceptTLV( + tempContractId, + totalCollateralSatoshis, + fundingPubKey, + payoutSPK, + payoutSerialId, + fundingInputs, + changeSPK, + changeSerialId, + cetSignatures, + refundSignature, + negotiationFields + ) => val fields = Vector( "tpe" -> Element(UInt16(DLCAcceptTLV.tpe.toInt)), "tempContractId" -> Element(tempContractId), "totalCollateralSatoshis" -> Element( - totalCollateralSatoshis.toUInt64), + totalCollateralSatoshis.toUInt64 + ), "fundingPubKey" -> Element(fundingPubKey), "payoutSPKLen" -> Element(UInt16(payoutSPK.asmBytes.length)), "payoutSPK" -> Element(payoutSPK.asmBytes), "payoutSerialId" -> Element(payoutSerialId), "fundingInputsLen" -> Element(UInt16(fundingInputs.length)), "fundingInputs" -> new MultiElement( - fundingInputs.map(input => Element(input.bytes))), + fundingInputs.map(input => Element(input.bytes)) + ), "changeSPKLen" -> Element(UInt16(changeSPK.asmBytes.length)), "changeSPK" -> Element(changeSPK.asmBytes), "changeSerialId" -> Element(changeSerialId), @@ -462,10 +492,12 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { "negotiationFields" -> Element(negotiationFields) ) DLCMessageTestVector(LnMessage(tlv), "accept_dlc_v0", fields) - case DLCSignTLV(contractId, - cetSignatures, - refundSignature, - fundingSignatures) => + case DLCSignTLV( + contractId, + cetSignatures, + refundSignature, + fundingSignatures + ) => val fields = Vector( "tpe" -> Element(UInt16(DLCSignTLV.tpe.toInt)), "contractId" -> Element(contractId), @@ -483,15 +515,18 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { val outcomeBytes = CryptoUtil.serializeForHash(outcome) NamedMultiElement( "outcomeLen" -> Element(UInt16(outcomeBytes.length)), - "outcome" -> Element(outcomeBytes)) + "outcome" -> Element(outcomeBytes) + ) }) ) DLCTLVTestVector(tlv, "enum_event_descriptor_v0", fields) - case SignedDigitDecompositionEventDescriptor(base, - numDigits, - units, - precision) => + case SignedDigitDecompositionEventDescriptor( + base, + numDigits, + units, + precision + ) => val fields = Vector( "tpe" -> Element(DigitDecompositionEventDescriptorV0TLV.tpe), "length" -> Element(tlv.length), @@ -503,10 +538,12 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { ) DLCTLVTestVector(tlv, "digit_decomp_event_descriptor_v0", fields) - case UnsignedDigitDecompositionEventDescriptor(base, - numDigits, - units, - precision) => + case UnsignedDigitDecompositionEventDescriptor( + base, + numDigits, + units, + precision + ) => val fields = Vector( "tpe" -> Element(DigitDecompositionEventDescriptorV0TLV.tpe), "length" -> Element(tlv.length), @@ -554,7 +591,8 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] { _: SendOfferTLV | _: AmtToForwardTLV | _: OutgoingCLTVValueTLV | _: PaymentDataTLV | _: ShortChannelIdTLV => throw new IllegalArgumentException( - s"DLCParsingTestVector is only defined for DLC messages and TLVs, got $tlv") + s"DLCParsingTestVector is only defined for DLC messages and TLVs, got $tlv" + ) } } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCParsingTestVectorGen.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCParsingTestVectorGen.scala index 92276c3bd5..5330b4bd02 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCParsingTestVectorGen.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCParsingTestVectorGen.scala @@ -11,7 +11,8 @@ object DLCParsingTestVectorGen extends TestVectorGen[DLCParsingTestVector, TLV] { override val defaultTestFile: File = new File( - "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_message_test.json") + "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_message_test.json" + ) override val testVectorParser: DLCParsingTestVector.type = DLCParsingTestVector diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTLVGen.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTLVGen.scala index 8b3d8a876f..c7b7206788 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTLVGen.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTLVGen.scala @@ -31,33 +31,38 @@ object DLCTLVGen { def genContractDescriptor( outcomes: Vector[String] = DLCTestUtil.genOutcomes(3), - totalInput: CurrencyUnit = defaultAmt * 2): EnumContractDescriptor = { + totalInput: CurrencyUnit = defaultAmt * 2 + ): EnumContractDescriptor = { DLCTestUtil.genContractDescriptors(outcomes, totalInput)._1 } def contractDescriptorParsingTestVector( outcomes: Vector[String] = DLCTestUtil.genOutcomes(3), - totalInput: CurrencyUnit = defaultAmt * 2): DLCParsingTestVector = { + totalInput: CurrencyUnit = defaultAmt * 2 + ): DLCParsingTestVector = { DLCParsingTestVector(genContractDescriptor(outcomes, totalInput).toTLV) } def genOracleInfo( oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey, oracleRValue: SchnorrNonce = ECPublicKey.freshPublicKey.schnorrNonce, - events: Vector[String] = - Vector("dummy1", "dummy2")): EnumSingleOracleInfo = { + events: Vector[String] = Vector("dummy1", "dummy2") + ): EnumSingleOracleInfo = { EnumSingleOracleInfo( OracleAnnouncementV0TLV.dummyForEventsAndKeys( oraclePrivKey, oracleRValue, - events.map(EnumOutcome.apply))) + events.map(EnumOutcome.apply) + ) + ) } def genEnumContractOraclePair( oraclePrivKey: ECPrivateKey, oracleRValue: SchnorrNonce, outcomes: Vector[String], - totalInput: CurrencyUnit): ContractOraclePair.EnumPair = { + totalInput: CurrencyUnit + ): ContractOraclePair.EnumPair = { val contract = genContractDescriptor(outcomes, totalInput) val oracleInfo = genOracleInfo(oraclePrivKey, oracleRValue, outcomes) @@ -68,11 +73,14 @@ object DLCTLVGen { oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey, oracleRValue: SchnorrNonce = ECPublicKey.freshPublicKey.schnorrNonce, outcomes: Vector[String] = DLCTestUtil.genOutcomes(3), - totalInput: CurrencyUnit = defaultAmt * 2): ContractInfo = { - val pair = genEnumContractOraclePair(oraclePrivKey, - oracleRValue, - outcomes, - totalInput) + totalInput: CurrencyUnit = defaultAmt * 2 + ): ContractInfo = { + val pair = genEnumContractOraclePair( + oraclePrivKey, + oracleRValue, + outcomes, + totalInput + ) SingleContractInfo(totalInput.satoshis, pair) } @@ -81,28 +89,33 @@ object DLCTLVGen { oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey, oracleRValue: SchnorrNonce = ECPublicKey.freshPublicKey.schnorrNonce, outcomes: Vector[String] = DLCTestUtil.genOutcomes(3), - totalInput: CurrencyUnit = defaultAmt * 2): DLCParsingTestVector = { + totalInput: CurrencyUnit = defaultAmt * 2 + ): DLCParsingTestVector = { DLCParsingTestVector( - genContractInfo(oraclePrivKey, oracleRValue, outcomes, totalInput).toTLV) + genContractInfo(oraclePrivKey, oracleRValue, outcomes, totalInput).toTLV + ) } def oracleInfoParsingTestVector( oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey, oracleRValue: SchnorrNonce = ECPublicKey.freshPublicKey.schnorrNonce, - events: Vector[String] = - Vector("dummy1", "dummy2")): DLCParsingTestVector = { + events: Vector[String] = Vector("dummy1", "dummy2") + ): DLCParsingTestVector = { DLCParsingTestVector( - genOracleInfo(oraclePrivKey, oracleRValue, events).toTLV) + genOracleInfo(oraclePrivKey, oracleRValue, events).toTLV + ) } def p2wpkh( - pubKey: ECPublicKey = ECPublicKey.freshPublicKey): P2WPKHWitnessSPKV0 = { + pubKey: ECPublicKey = ECPublicKey.freshPublicKey + ): P2WPKHWitnessSPKV0 = { P2WPKHWitnessSPKV0(pubKey) } def address( spk: ScriptPubKey = p2wpkh(), - network: NetworkParameters = RegTest): BitcoinAddress = { + network: NetworkParameters = RegTest + ): BitcoinAddress = { spk match { case wspk: WitnessScriptPubKey => Bech32Address(wspk, network) case p2sh: P2SHScriptPubKey => P2SHAddress(p2sh, network) @@ -114,7 +127,8 @@ object DLCTLVGen { def inputTransaction( input: CurrencyUnit = defaultAmt, - spk: ScriptPubKey = p2wpkh()): Transaction = { + spk: ScriptPubKey = p2wpkh() + ): Transaction = { BaseTransaction( TransactionConstants.validLockVersion, Vector.empty, @@ -125,11 +139,13 @@ object DLCTLVGen { def outputReference( input: CurrencyUnit = defaultAmt, - spk: ScriptPubKey = - P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey)): OutputReference = { + spk: ScriptPubKey = P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey) + ): OutputReference = { val tx = inputTransaction(input, spk) - OutputReference(TransactionOutPoint(tx.txIdBE, UInt32.zero), - tx.outputs.head) + OutputReference( + TransactionOutPoint(tx.txIdBE, UInt32.zero), + tx.outputs.head + ) } def fundingInput( @@ -138,13 +154,16 @@ object DLCTLVGen { prevTxVout: UInt32 = UInt32.zero, sequence: UInt32 = TransactionConstants.enableRBFSequence, maxWitnessLen: UInt16 = UInt16(107), - redeemScriptOpt: Option[WitnessScriptPubKey] = None): DLCFundingInput = { - DLCFundingInput(inputSerialId, - prevTx, - prevTxVout, - sequence, - maxWitnessLen, - redeemScriptOpt) + redeemScriptOpt: Option[WitnessScriptPubKey] = None + ): DLCFundingInput = { + DLCFundingInput( + inputSerialId, + prevTx, + prevTxVout, + sequence, + maxWitnessLen, + redeemScriptOpt + ) } def fundingInputParsingTestVector( @@ -153,15 +172,18 @@ object DLCTLVGen { prevTxVout: UInt32 = UInt32.zero, sequence: UInt32 = TransactionConstants.enableRBFSequence, maxWitnessLen: UInt16 = UInt16(107), - redeemScriptOpt: Option[WitnessScriptPubKey] = - None): DLCParsingTestVector = { + redeemScriptOpt: Option[WitnessScriptPubKey] = None + ): DLCParsingTestVector = { DLCParsingTestVector( - fundingInput(inputSerialId, - prevTx, - prevTxVout, - sequence, - maxWitnessLen, - redeemScriptOpt).toTLV) + fundingInput( + inputSerialId, + prevTx, + prevTxVout, + sequence, + maxWitnessLen, + redeemScriptOpt + ).toTLV + ) } def adaptorSig: ECAdaptorSignature = { @@ -177,7 +199,8 @@ object DLCTLVGen { def ecdsaSig(sigHashByte: Boolean = true): ECDigitalSignature = { val sigWithoutSigHash = ECDigitalSignature.fromRS( ECPrivateKey.freshPrivateKey.fieldElement.toBigInteger, - ECPrivateKey.freshPrivateKey.fieldElement.toBigInteger) + ECPrivateKey.freshPrivateKey.fieldElement.toBigInteger + ) if (sigHashByte) { ECDigitalSignature(sigWithoutSigHash.bytes :+ 0x01) @@ -188,20 +211,23 @@ object DLCTLVGen { def partialSig( pubKey: ECPublicKey = ECPublicKey.freshPublicKey, - sigHashByte: Boolean = true): PartialSignature = { + sigHashByte: Boolean = true + ): PartialSignature = { PartialSignature(pubKey, ecdsaSig(sigHashByte)) } def p2wpkhWitnessV0( pubKey: ECPublicKey = ECPublicKey.freshPublicKey, - sigHashByte: Boolean = true): P2WPKHWitnessV0 = { + sigHashByte: Boolean = true + ): P2WPKHWitnessV0 = { P2WPKHWitnessV0(pubKey, ecdsaSig(sigHashByte)) } def cetSigs( outcomes: Vector[EnumOutcome] = DLCTestUtil.genOutcomes(3).map(EnumOutcome.apply), - oracleInfo: EnumSingleOracleInfo = genOracleInfo()): CETSignatures = { + oracleInfo: EnumSingleOracleInfo = genOracleInfo() + ): CETSignatures = { CETSignatures( outcomes.map(outcome => EnumOracleOutcome(Vector(oracleInfo), outcome).sigPoint -> adaptorSig) @@ -209,25 +235,30 @@ object DLCTLVGen { } def refundSigs( - fundingPubKey: ECPublicKey = - ECPublicKey.freshPublicKey): PartialSignature = { + fundingPubKey: ECPublicKey = ECPublicKey.freshPublicKey + ): PartialSignature = { partialSig(fundingPubKey, sigHashByte = false) } def cetSigsParsingTestVector(numOutcomes: Int = 3): DLCParsingTestVector = { DLCParsingTestVector( - CETSignaturesV0TLV((0 until numOutcomes).toVector.map(_ => adaptorSig))) + CETSignaturesV0TLV((0 until numOutcomes).toVector.map(_ => adaptorSig)) + ) } def fundingSigs( outPoints: Vector[TransactionOutPoint] = Vector( - outputReference().outPoint)): FundingSignatures = { + outputReference().outPoint + ) + ): FundingSignatures = { FundingSignatures(outPoints.map(outpoint => outpoint -> p2wpkhWitnessV0())) } def fundingSigsParsingTestVector( outPoints: Vector[TransactionOutPoint] = Vector( - outputReference().outPoint)): DLCParsingTestVector = { + outputReference().outPoint + ) + ): DLCParsingTestVector = { DLCParsingTestVector(fundingSigs(outPoints).toTLV) } @@ -244,7 +275,8 @@ object DLCTLVGen { fundOutputSerialId: UInt64 = DLCMessage.genSerialId(), feeRate: SatoshisPerVirtualByte = SatoshisPerVirtualByte.one, contractMaturityBound: BlockTimeStamp = BlockTimeStamp(100), - contractTimeout: BlockTimeStamp = BlockTimeStamp(200)): DLCOffer = { + contractTimeout: BlockTimeStamp = BlockTimeStamp(200) + ): DLCOffer = { DLCOffer( protocolVersionOpt, contractInfo, @@ -273,7 +305,8 @@ object DLCTLVGen { fundOutputSerialId: UInt64 = DLCMessage.genSerialId(), feeRate: SatoshisPerVirtualByte = SatoshisPerVirtualByte.one, contractMaturityBound: BlockTimeStamp = BlockTimeStamp(100), - contractTimeout: BlockTimeStamp = BlockTimeStamp(200)): DLCOfferTLV = { + contractTimeout: BlockTimeStamp = BlockTimeStamp(200) + ): DLCOfferTLV = { dlcOffer( protocolVersionOpt, contractInfo, @@ -304,8 +337,8 @@ object DLCTLVGen { fundOutputSerialId: UInt64 = DLCMessage.genSerialId(), feeRate: SatoshisPerVirtualByte = SatoshisPerVirtualByte.one, contractMaturityBound: BlockTimeStamp = BlockTimeStamp(100), - contractTimeout: BlockTimeStamp = - BlockTimeStamp(200)): DLCParsingTestVector = { + contractTimeout: BlockTimeStamp = BlockTimeStamp(200) + ): DLCParsingTestVector = { DLCParsingTestVector( dlcOfferTLV( protocolVersionOpt, @@ -321,7 +354,8 @@ object DLCTLVGen { feeRate, contractMaturityBound, contractTimeout - )) + ) + ) } def dlcAccept( @@ -334,7 +368,8 @@ object DLCTLVGen { changeSerialId: UInt64 = DLCMessage.genSerialId(), cetSignatures: CETSignatures = cetSigs(), refundSignatures: PartialSignature = refundSigs(), - tempContractId: Sha256Digest = hash()): DLCAccept = { + tempContractId: Sha256Digest = hash() + ): DLCAccept = { DLCAccept( totalCollateral, DLCPublicKeys(fundingPubKey, payoutAddress), @@ -359,17 +394,20 @@ object DLCTLVGen { changeSerialId: UInt64 = DLCMessage.genSerialId(), cetSignatures: CETSignatures = cetSigs(), refundSignatures: PartialSignature = refundSigs(), - tempContractId: Sha256Digest = hash()): DLCAcceptTLV = { - dlcAccept(totalCollateral, - fundingPubKey, - payoutAddress, - payoutSerialId, - fundingInputs, - changeAddress, - changeSerialId, - cetSignatures, - refundSignatures, - tempContractId).toTLV + tempContractId: Sha256Digest = hash() + ): DLCAcceptTLV = { + dlcAccept( + totalCollateral, + fundingPubKey, + payoutAddress, + payoutSerialId, + fundingInputs, + changeAddress, + changeSerialId, + cetSignatures, + refundSignatures, + tempContractId + ).toTLV } def dlcAcceptParsingTestVector( @@ -381,18 +419,22 @@ object DLCTLVGen { changeAddress: BitcoinAddress = address(), changeSerialId: UInt64 = DLCMessage.genSerialId(), cetSignatures: CETSignatures = cetSigs(), - tempContractId: Sha256Digest = hash()): DLCParsingTestVector = { + tempContractId: Sha256Digest = hash() + ): DLCParsingTestVector = { DLCParsingTestVector( - dlcAcceptTLV(totalCollateral, - fundingPubKey, - payoutAddress, - payoutSerialId, - fundingInputs, - changeAddress, - changeSerialId, - cetSignatures, - refundSigs(), - tempContractId)) + dlcAcceptTLV( + totalCollateral, + fundingPubKey, + payoutAddress, + payoutSerialId, + fundingInputs, + changeAddress, + changeSerialId, + cetSignatures, + refundSigs(), + tempContractId + ) + ) } def dlcAcceptFromOffer( @@ -403,14 +445,15 @@ object DLCTLVGen { payoutSerialId: UInt64 = DLCMessage.genSerialId(), fundingInputs: Vector[DLCFundingInput] = Vector(fundingInput()), changeAddress: BitcoinAddress = address(), - changeSerialId: UInt64 = DLCMessage.genSerialId()): DLCAccept = { + changeSerialId: UInt64 = DLCMessage.genSerialId() + ): DLCAccept = { val totalCollateral = offer.contractInfo.maxOffererPayout - offer.collateral + overCollateral val cetSignatures = cetSigs( - offer.contractInfo.allOutcomes.map( - _.asInstanceOf[EnumOracleOutcome].outcome), + offer.contractInfo.allOutcomes + .map(_.asInstanceOf[EnumOracleOutcome].outcome), offer.contractInfo.oracleInfos.head.asInstanceOf[EnumSingleOracleInfo] ) @@ -440,22 +483,26 @@ object DLCTLVGen { payoutSerialId: UInt64 = DLCMessage.genSerialId(), fundingInputs: Vector[DLCFundingInput] = Vector(fundingInput()), changeAddress: BitcoinAddress = address(), - changeSerialId: UInt64 = DLCMessage.genSerialId()): DLCAcceptTLV = { - dlcAcceptFromOffer(offer, - overCollateral, - fundingPubKey, - payoutAddress, - payoutSerialId, - fundingInputs, - changeAddress, - changeSerialId).toTLV + changeSerialId: UInt64 = DLCMessage.genSerialId() + ): DLCAcceptTLV = { + dlcAcceptFromOffer( + offer, + overCollateral, + fundingPubKey, + payoutAddress, + payoutSerialId, + fundingInputs, + changeAddress, + changeSerialId + ).toTLV } def dlcSign( cetSignatures: CETSignatures = cetSigs(), refundSignatures: PartialSignature = refundSigs(), fundingSignatures: FundingSignatures = fundingSigs(), - contractId: ByteVector = hash().bytes): DLCSign = { + contractId: ByteVector = hash().bytes + ): DLCSign = { DLCSign(cetSignatures, refundSignatures, fundingSignatures, contractId) } @@ -463,32 +510,35 @@ object DLCTLVGen { cetSignatures: CETSignatures = cetSigs(), refundSignatures: PartialSignature = refundSigs(), fundingSignatures: FundingSignatures = fundingSigs(), - contractId: ByteVector = hash().bytes): DLCSignTLV = { - dlcSign(cetSignatures, - refundSignatures, - fundingSignatures, - contractId).toTLV + contractId: ByteVector = hash().bytes + ): DLCSignTLV = { + dlcSign( + cetSignatures, + refundSignatures, + fundingSignatures, + contractId + ).toTLV } def dlcSignParsingTestVector( cetSignatures: CETSignatures = cetSigs(), refundSignatures: PartialSignature = refundSigs(), fundingSignatures: FundingSignatures = fundingSigs(), - contractId: ByteVector = hash().bytes): DLCParsingTestVector = { + contractId: ByteVector = hash().bytes + ): DLCParsingTestVector = { DLCParsingTestVector( - dlcSignTLV(cetSignatures, - refundSignatures, - fundingSignatures, - contractId)) + dlcSignTLV(cetSignatures, refundSignatures, fundingSignatures, contractId) + ) } def dlcSignFromOffer( offer: DLCOffer, - contractId: ByteVector = hash().bytes): DLCSign = { + contractId: ByteVector = hash().bytes + ): DLCSign = { val cetSignatures = { cetSigs( - offer.contractInfo.allOutcomes.map( - _.asInstanceOf[EnumOracleOutcome].outcome), + offer.contractInfo.allOutcomes + .map(_.asInstanceOf[EnumOracleOutcome].outcome), offer.oracleInfos.head.asInstanceOf[EnumSingleOracleInfo] ) } @@ -499,7 +549,8 @@ object DLCTLVGen { def dlcSignTLVFromOffer( offer: DLCOffer, - contractId: ByteVector = hash().bytes): DLCSignTLV = { + contractId: ByteVector = hash().bytes + ): DLCSignTLV = { dlcSignFromOffer(offer, contractId).toTLV } @@ -513,7 +564,8 @@ object DLCTLVGen { def dlcSignTLVFromOfferAndAccept( offer: DLCOffer, - accept: DLCAccept): DLCSignTLV = { + accept: DLCAccept + ): DLCSignTLV = { dlcSignFromOfferAndAccept(offer, accept).toTLV } } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTestVector.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTestVector.scala index 17c7af43ef..e50b429457 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTestVector.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTestVector.scala @@ -47,18 +47,21 @@ case class FundingInputTx( idx: Int, inputKeys: Vector[ECPrivateKey], redeemScript: Option[WitnessScriptPubKey], - scriptWitness: ScriptWitnessV0) { + scriptWitness: ScriptWitnessV0 +) { val outputRef: OutputReference = OutputReference(TransactionOutPoint(tx.txId, UInt32(idx)), tx.outputs(idx)) lazy val scriptSignatureParams: ScriptSignatureParams[InputInfo] = { ScriptSignatureParams( - InputInfo(TransactionOutPoint(tx.txId, UInt32(idx)), - tx.outputs(idx), - redeemScript, - Some(scriptWitness), - ConditionalPath.NoCondition), + InputInfo( + TransactionOutPoint(tx.txId, UInt32(idx)), + tx.outputs(idx), + redeemScript, + Some(scriptWitness), + ConditionalPath.NoCondition + ), tx, inputKeys, HashType.sigHashAll @@ -66,19 +69,23 @@ case class FundingInputTx( } def toFundingInput: DLCFundingInput = { - DLCFundingInput.fromInputSigningInfo(scriptSignatureParams, - serialId, - tx.inputs(idx).sequence) + DLCFundingInput.fromInputSigningInfo( + scriptSignatureParams, + serialId, + tx.inputs(idx).sequence + ) } def toSerializedFundingInputTx: SerializedFundingInputTx = { - SerializedFundingInputTx(serialId, - tx, - idx, - inputKeys, - redeemScript, - scriptWitness, - scriptSignatureParams.maxWitnessLen) + SerializedFundingInputTx( + serialId, + tx, + idx, + inputKeys, + redeemScript, + scriptWitness, + scriptSignatureParams.maxWitnessLen + ) } } @@ -89,7 +96,8 @@ case class SerializedFundingInputTx( inputKeys: Vector[ECPrivateKey], redeemScript: Option[WitnessScriptPubKey], scriptWitness: ScriptWitnessV0, - maxWitnessLen: Int) { + maxWitnessLen: Int +) { def toFundingInputTx: FundingInputTx = { FundingInputTx(serialId, tx, idx, inputKeys, redeemScript, scriptWitness) @@ -105,7 +113,8 @@ case class DLCPartyParams( fundingPrivKey: ECPrivateKey, payoutAddress: BitcoinAddress, payoutSerialId: UInt64, - fundOutputSerialId: UInt64) { + fundOutputSerialId: UInt64 +) { def fundingInputs: Vector[DLCFundingInput] = fundingInputTxs.map(_.toFundingInput) @@ -119,7 +128,8 @@ case class DLCPartyParams( DLCOfferTLV.currentVersionOpt, SingleContractInfo( EnumContractDescriptor(params.contractInfo.map(_.toMapEntry)), - params.oracleInfo), + params.oracleInfo + ), DLCPublicKeys(fundingPrivKey.publicKey, payoutAddress), collateral.satoshis, fundingInputs, @@ -136,7 +146,8 @@ case class DLCPartyParams( case class SerializedContractInfoEntry( preImage: String, outcome: Sha256Digest, - localPayout: CurrencyUnit) { + localPayout: CurrencyUnit +) { def toMapEntry: (EnumOutcome, Satoshis) = { EnumOutcome(preImage) -> localPayout.satoshis @@ -145,12 +156,15 @@ case class SerializedContractInfoEntry( object SerializedContractInfoEntry { - def fromContractDescriptor(contractInfo: EnumContractDescriptor): Vector[ - SerializedContractInfoEntry] = { + def fromContractDescriptor( + contractInfo: EnumContractDescriptor + ): Vector[SerializedContractInfoEntry] = { contractInfo.map { case (EnumOutcome(str), amt) => - SerializedContractInfoEntry(str, - CryptoUtil.sha256DLCAttestation(str), - amt) + SerializedContractInfoEntry( + str, + CryptoUtil.sha256DLCAttestation(str), + amt + ) }.toVector } } @@ -162,20 +176,24 @@ case class DLCParams( contractTimeout: BlockTimeStamp, feeRate: SatoshisPerVirtualByte, realOutcome: Sha256Digest, - oracleSignature: SchnorrDigitalSignature) + oracleSignature: SchnorrDigitalSignature +) case class ValidTestInputs( params: DLCParams, offerParams: DLCPartyParams, - acceptParams: DLCPartyParams) { + acceptParams: DLCPartyParams +) { def offer: DLCOffer = offerParams.toOffer(params) def accept: DLCAcceptWithoutSigs = DLCAcceptWithoutSigs( acceptParams.collateral.satoshis, - DLCPublicKeys(acceptParams.fundingPrivKey.publicKey, - acceptParams.payoutAddress), + DLCPublicKeys( + acceptParams.fundingPrivKey.publicKey, + acceptParams.payoutAddress + ), acceptParams.fundingInputs, acceptParams.changeAddress, acceptParams.payoutSerialId, @@ -212,7 +230,8 @@ object ValidTestInputs { case class DLCTransactions( fundingTx: Transaction, cets: Vector[Transaction], - refundTx: Transaction) + refundTx: Transaction +) case class SuccessTestVector( testInputs: ValidTestInputs, @@ -220,8 +239,8 @@ case class SuccessTestVector( accept: LnMessage[DLCAcceptTLV], sign: LnMessage[DLCSignTLV], unsignedTxs: DLCTransactions, - signedTxs: DLCTransactions) - extends DLCTestVector { + signedTxs: DLCTransactions +) extends DLCTestVector { override def toJson: JsValue = { Json.toJson(this)(SuccessTestVector.successTestVectorFormat) @@ -239,7 +258,8 @@ object SuccessTestVector extends TestVectorParser[SuccessTestVector] { implicit val u64Format: Format[UInt64] = hexFormat(UInt64) implicit val oracleInfoFormat: Format[EnumSingleOracleInfo] = hexFormat( - EnumSingleOracleInfo) + EnumSingleOracleInfo + ) implicit val blockTimeStampFormat: Format[BlockTimeStamp] = Format[BlockTimeStamp]( @@ -256,7 +276,8 @@ object SuccessTestVector extends TestVectorParser[SuccessTestVector] { ) implicit val sha256DigestFormat: Format[Sha256Digest] = hexFormat( - Sha256Digest) + Sha256Digest + ) implicit val schnorrDigitalSignatureFormat: Format[SchnorrDigitalSignature] = hexFormat(SchnorrDigitalSignature) @@ -312,13 +333,16 @@ object SuccessTestVector extends TestVectorParser[SuccessTestVector] { Json.format[DLCPartyParams] implicit val offerMsgFormat: Format[LnMessage[DLCOfferTLV]] = hexFormat( - LnMessageFactory(DLCOfferTLV)) + LnMessageFactory(DLCOfferTLV) + ) implicit val acceptMsgFormat: Format[LnMessage[DLCAcceptTLV]] = hexFormat( - LnMessageFactory(DLCAcceptTLV)) + LnMessageFactory(DLCAcceptTLV) + ) implicit val signMsgFormat: Format[LnMessage[DLCSignTLV]] = hexFormat( - LnMessageFactory(DLCSignTLV)) + LnMessageFactory(DLCSignTLV) + ) implicit val validTestInputsFormat: Format[ValidTestInputs] = Json.format[ValidTestInputs] diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTestVectorGen.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTestVectorGen.scala index 5e5c5097eb..b89d737e57 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTestVectorGen.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTestVectorGen.scala @@ -9,7 +9,8 @@ import scala.concurrent.Future object DLCTestVectorGen extends TestVectorGen[DLCTestVector, ValidTestInputs] { override val defaultTestFile: File = new File( - "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_test.json") + "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_test.json" + ) override val testVectorParser: DLCTestVector.type = DLCTestVector @@ -37,6 +38,8 @@ object DLCTestVectorGen extends TestVectorGen[DLCTestVector, ValidTestInputs] { Future.sequence( (numOutcomesTests ++ nonP2WPKHInputTests ++ multiInputTests).map( - Future.fromTry)) + Future.fromTry + ) + ) } } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTxGen.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTxGen.scala index 0c94c02601..d1b5148cbb 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTxGen.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTxGen.scala @@ -23,21 +23,26 @@ object DLCTxGen { contractDescriptor: EnumContractDescriptor = genContractDescriptor(), contractMaturityBound: BlockTimeStamp = BlockTimeStamp(100), contractTimeout: BlockTimeStamp = BlockTimeStamp(200), - feeRate: SatoshisPerVirtualByte = - SatoshisPerVirtualByte(Satoshis(5))): DLCParams = { + feeRate: SatoshisPerVirtualByte = SatoshisPerVirtualByte(Satoshis(5)) + ): DLCParams = { val privKey = ECPrivateKey.freshPrivateKey val kVal = ECPrivateKey.freshPrivateKey val oracleInfo = EnumSingleOracleInfo( OracleAnnouncementV0TLV - .dummyForEventsAndKeys(privKey, - kVal.schnorrNonce, - contractDescriptor.keys)) + .dummyForEventsAndKeys( + privKey, + kVal.schnorrNonce, + contractDescriptor.keys + ) + ) val realOutcome = contractDescriptor.keys(contractDescriptor.size / 2) val sig = - privKey.schnorrSignWithNonce(CryptoUtil - .sha256DLCAttestation(realOutcome.outcome) - .bytes, - kVal) + privKey.schnorrSignWithNonce( + CryptoUtil + .sha256DLCAttestation(realOutcome.outcome) + .bytes, + kVal + ) DLCParams( oracleInfo, SerializedContractInfoEntry.fromContractDescriptor(contractDescriptor), @@ -50,10 +55,13 @@ object DLCTxGen { } private val dummyTransactionInput = TransactionInput( - TransactionOutPoint(CryptoUtil.doubleSHA256(ByteVector("DLC".getBytes)), - UInt32.zero), + TransactionOutPoint( + CryptoUtil.doubleSHA256(ByteVector("DLC".getBytes)), + UInt32.zero + ), EmptyScriptSignature, - UInt32.zero) + UInt32.zero + ) def fundingInputTx( inputs: Vector[TransactionInput] = Vector(dummyTransactionInput), @@ -61,10 +69,12 @@ object DLCTxGen { privKeys: Vector[ECPrivateKey] = Vector(ECPrivateKey.freshPrivateKey), redeemScriptOpt: Option[WitnessScriptPubKeyV0] = None, scriptWitness: ScriptWitnessV0 = P2WPKHWitnessV0( - ECPublicKey.freshPublicKey), + ECPublicKey.freshPublicKey + ), amt: CurrencyUnit = defaultAmt * 2, lockTime: UInt32 = UInt32.zero, - serialId: UInt64 = DLCMessage.genSerialId()): FundingInputTx = { + serialId: UInt64 = DLCMessage.genSerialId() + ): FundingInputTx = { val (spk, scriptWit) = redeemScriptOpt match { case Some(wspk) => (P2SHScriptPubKey(wspk), scriptWitness) case None => @@ -85,10 +95,12 @@ object DLCTxGen { Vector .fill(idx)(TransactionOutput(defaultAmt, EmptyScriptPubKey)) :+ TransactionOutput(amt, spk) - val tx = BaseTransaction(TransactionConstants.validLockVersion, - inputs, - outputs, - lockTime) + val tx = BaseTransaction( + TransactionConstants.validLockVersion, + inputs, + outputs, + lockTime + ) FundingInputTx(serialId, tx, idx, privKeys, redeemScriptOpt, scriptWit) } @@ -100,7 +112,8 @@ object DLCTxGen { p2shNested: Boolean = false, idx: Int = 0, amt: CurrencyUnit = defaultAmt * 2, - lockTime: UInt32 = UInt32.zero): FundingInputTx = { + lockTime: UInt32 = UInt32.zero + ): FundingInputTx = { val multiSig = MultiSignatureScriptPubKey(requiredSigs, privKeys.map(_.publicKey)) @@ -110,12 +123,14 @@ object DLCTxGen { val scriptWitness = P2WSHWitnessV0(multiSig) - fundingInputTx(idx = idx, - privKeys = privKeys, - redeemScriptOpt = redeemScriptOpt, - scriptWitness = scriptWitness, - amt = amt, - lockTime = lockTime) + fundingInputTx( + idx = idx, + privKeys = privKeys, + redeemScriptOpt = redeemScriptOpt, + scriptWitness = scriptWitness, + amt = amt, + lockTime = lockTime + ) } def dlcPartyParams( @@ -126,28 +141,33 @@ object DLCTxGen { fundingPrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey, payoutAddress: BitcoinAddress = address(), payoutSerialId: UInt64 = DLCMessage.genSerialId(), - fundOutputSerialId: UInt64 = DLCMessage.genSerialId()): DLCPartyParams = { - DLCPartyParams(collateral, - fundingInputTxs, - changeAddress, - changeSerialId, - fundingPrivKey, - payoutAddress, - payoutSerialId, - fundOutputSerialId) + fundOutputSerialId: UInt64 = DLCMessage.genSerialId() + ): DLCPartyParams = { + DLCPartyParams( + collateral, + fundingInputTxs, + changeAddress, + changeSerialId, + fundingPrivKey, + payoutAddress, + payoutSerialId, + fundOutputSerialId + ) } def validTestInputs( params: DLCParams = dlcParams(), offerParams: DLCPartyParams = dlcPartyParams(), - acceptParams: DLCPartyParams = dlcPartyParams()): ValidTestInputs = { + acceptParams: DLCPartyParams = dlcPartyParams() + ): ValidTestInputs = { ValidTestInputs(params, offerParams, acceptParams) } def validTestInputsForInputs( offerInputs: Vector[FundingInputTx], acceptInputs: Vector[FundingInputTx], - numOutcomes: Int = 3): ValidTestInputs = { + numOutcomes: Int = 3 + ): ValidTestInputs = { val outcomes = DLCTestUtil.genOutcomes(numOutcomes) val contractDescriptor = genContractDescriptor(outcomes) @@ -197,16 +217,19 @@ object DLCTxGen { } def dlcTxTestVector( - inputs: ValidTestInputs = validTestInputs()): DLCTxTestVector = { + inputs: ValidTestInputs = validTestInputs() + ): DLCTxTestVector = { DLCTxTestVector.fromInputs(inputs) } def dlcTxTestVectorWithTxInputs( offerInputs: Vector[FundingInputTx], acceptInputs: Vector[FundingInputTx], - numOutcomes: Int = 3): DLCTxTestVector = { + numOutcomes: Int = 3 + ): DLCTxTestVector = { dlcTxTestVector( - validTestInputsForInputs(offerInputs, acceptInputs, numOutcomes)) + validTestInputsForInputs(offerInputs, acceptInputs, numOutcomes) + ) } def randomTxTestVector(numOutcomes: Int): DLCTxTestVector = { @@ -214,11 +237,13 @@ object DLCTxGen { val contractDescriptor = genContractDescriptor(outcomes) dlcTxTestVector( - validTestInputs(dlcParams(contractDescriptor = contractDescriptor))) + validTestInputs(dlcParams(contractDescriptor = contractDescriptor)) + ) } def successTestVector( - inputs: ValidTestInputs = validTestInputs()): Try[SuccessTestVector] = { + inputs: ValidTestInputs = validTestInputs() + ): Try[SuccessTestVector] = { val offer = inputs.offer val acceptWithoutSigs = inputs.accept @@ -243,8 +268,10 @@ object DLCTxGen { .map(_.preImage) .get val outcome = - EnumOracleOutcome(Vector(inputs.params.oracleInfo), - EnumOutcome(outcomeStr)) + EnumOracleOutcome( + Vector(inputs.params.oracleInfo), + EnumOutcome(outcomeStr) + ) val acceptCETSigs = acceptSigner.createCETSigs() val offerCETSigs = offerSigner.createCETSigs() @@ -264,15 +291,23 @@ object DLCTxGen { outcome, acceptCETSigs(outcome.sigPoint), Vector( - EnumOracleSignature(inputs.params.oracleInfo, - inputs.params.oracleSignature))) + EnumOracleSignature( + inputs.params.oracleInfo, + inputs.params.oracleSignature + ) + ) + ) val acceptSignedCET = acceptSigner.completeCET( outcome, offerCETSigs(outcome.sigPoint), Vector( - EnumOracleSignature(inputs.params.oracleInfo, - inputs.params.oracleSignature))) + EnumOracleSignature( + inputs.params.oracleInfo, + inputs.params.oracleSignature + ) + ) + ) val accept = acceptWithoutSigs.withSigs(acceptCETSigs, acceptRefundSig) @@ -286,9 +321,11 @@ object DLCTxGen { accept.toMessage, sign.toMessage, DLCTransactions(fundingTx, cets, refundTx), - DLCTransactions(signedFundingTx, - Vector(offerSignedCET, acceptSignedCET), - signedRefundTx) + DLCTransactions( + signedFundingTx, + Vector(offerSignedCET, acceptSignedCET), + signedRefundTx + ) ) } } @@ -298,6 +335,7 @@ object DLCTxGen { val contractDescriptor = genContractDescriptor(outcomes) successTestVector( - validTestInputs(dlcParams(contractDescriptor = contractDescriptor))) + validTestInputs(dlcParams(contractDescriptor = contractDescriptor)) + ) } } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTxTestVectorGen.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTxTestVectorGen.scala index 3bb1ca5358..1210300e4c 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTxTestVectorGen.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/DLCTxTestVectorGen.scala @@ -10,7 +10,8 @@ object DLCTxTestVectorGen extends TestVectorGen[DLCTxTestVector, ValidTestInputs] { override val defaultTestFile: File = new File( - "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_tx_test.json") + "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_tx_test.json" + ) override val testVectorParser: DLCTxTestVector.type = DLCTxTestVector @@ -36,6 +37,7 @@ object DLCTxTestVectorGen DLCTxGen.multiInputTests(numInputs).map(DLCTxGen.dlcTxTestVector) Future.successful( - numOutcomesTests ++ nonP2WPKHInputTests ++ multiInputTests) + numOutcomesTests ++ nonP2WPKHInputTests ++ multiInputTests + ) } } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/SchnorrSigPointTestVector.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/SchnorrSigPointTestVector.scala index 4c7f279b68..8264763bdd 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/SchnorrSigPointTestVector.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/SchnorrSigPointTestVector.scala @@ -8,10 +8,12 @@ case class SchnorrSigPointTestVector( pubKey: SchnorrPublicKey, pubNonce: SchnorrNonce, signature: SchnorrDigitalSignature, - sigPoint: ECPublicKey) - extends TestVector { - require(signature.sig.getPublicKey == sigPoint, - s"Signature ($signature) does not match Signature Point ($sigPoint)") + sigPoint: ECPublicKey +) extends TestVector { + require( + signature.sig.getPublicKey == sigPoint, + s"Signature ($signature) does not match Signature Point ($sigPoint)" + ) def privKey: ECPrivateKey = inputs.privKey def privNonce: ECPrivateKey = inputs.privNonce @@ -25,13 +27,15 @@ case class SchnorrSigPointTestVector( case class SchnorrSigPointTestVectorInput( privKey: ECPrivateKey, privNonce: ECPrivateKey, - msgHash: Sha256Digest) + msgHash: Sha256Digest +) object SchnorrSigPointTestVectorInput { def fromJson(json: JsValue): JsResult[SchnorrSigPointTestVectorInput] = { json.validate[SchnorrSigPointTestVectorInput]( - SchnorrSigPointTestVector.schnorrSigPointTestVectorInputFormat) + SchnorrSigPointTestVector.schnorrSigPointTestVectorInputFormat + ) } } @@ -39,14 +43,16 @@ object SchnorrSigPointTestVector extends TestVectorParser[SchnorrSigPointTestVector] { def apply( - input: SchnorrSigPointTestVectorInput): SchnorrSigPointTestVector = { + input: SchnorrSigPointTestVectorInput + ): SchnorrSigPointTestVector = { SchnorrSigPointTestVector(input.privKey, input.privNonce, input.msgHash) } def apply( privKey: ECPrivateKey, privNonce: ECPrivateKey, - msgHash: Sha256Digest): SchnorrSigPointTestVector = { + msgHash: Sha256Digest + ): SchnorrSigPointTestVector = { val signature = privKey.schnorrSignWithNonce(msgHash.bytes, privNonce) val signaturePoint = signature.sig.getPublicKey @@ -55,43 +61,52 @@ object SchnorrSigPointTestVector privKey.schnorrPublicKey, privNonce.schnorrNonce, signature, - signaturePoint) + signaturePoint + ) } def networkElementFormat[T <: NetworkElement]( - factory: Factory[T]): Format[T] = { - Format[T]({ json => - json.validate[String].map(factory.fromHex) - }, - { element => - JsString(element.hex) - }) + factory: Factory[T] + ): Format[T] = { + Format[T]( + { json => + json.validate[String].map(factory.fromHex) + }, + { element => + JsString(element.hex) + } + ) } implicit val privKeyFormat: Format[ECPrivateKey] = networkElementFormat( - ECPrivateKey) + ECPrivateKey + ) implicit val schnorrPubKeyFormat: Format[SchnorrPublicKey] = networkElementFormat(SchnorrPublicKey) implicit val schnorrNonceFormat: Format[SchnorrNonce] = networkElementFormat( - SchnorrNonce) + SchnorrNonce + ) implicit val hashFormat: Format[Sha256Digest] = networkElementFormat( - Sha256Digest) + Sha256Digest + ) implicit val signatureFormat: Format[SchnorrDigitalSignature] = networkElementFormat(SchnorrDigitalSignature) implicit val pubKeyFromat: Format[ECPublicKey] = networkElementFormat( - ECPublicKey) + ECPublicKey + ) - implicit val schnorrSigPointTestVectorInputFormat: Format[ - SchnorrSigPointTestVectorInput] = + implicit val schnorrSigPointTestVectorInputFormat + : Format[SchnorrSigPointTestVectorInput] = Json.format[SchnorrSigPointTestVectorInput] - implicit val schnorrSigPointTestVectorFormat: Format[ - SchnorrSigPointTestVector] = Json.format[SchnorrSigPointTestVector] + implicit val schnorrSigPointTestVectorFormat + : Format[SchnorrSigPointTestVector] = + Json.format[SchnorrSigPointTestVector] override def fromJson(json: JsValue): JsResult[SchnorrSigPointTestVector] = { json.validate[SchnorrSigPointTestVector] diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/SchnorrSigPointTestVectorGen.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/SchnorrSigPointTestVectorGen.scala index b6152cb5fb..3fdc7e3ffb 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/SchnorrSigPointTestVectorGen.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/SchnorrSigPointTestVectorGen.scala @@ -10,27 +10,30 @@ import scala.concurrent.Future object SchnorrSigPointTestVectorGen extends TestVectorGen[ SchnorrSigPointTestVector, - SchnorrSigPointTestVectorInput] { + SchnorrSigPointTestVectorInput + ] { override val defaultTestFile: File = new File( - "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_schnorr_test.json") + "core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/dlc_schnorr_test.json" + ) override val testVectorParser: SchnorrSigPointTestVector.type = SchnorrSigPointTestVector - override def inputFromJson: JsValue => JsResult[ - SchnorrSigPointTestVectorInput] = + override def inputFromJson + : JsValue => JsResult[SchnorrSigPointTestVectorInput] = SchnorrSigPointTestVectorInput.fromJson override val inputStr: String = "inputs" - override def generateFromInput: SchnorrSigPointTestVectorInput => Future[ - SchnorrSigPointTestVector] = { inputs => - Future.successful(SchnorrSigPointTestVector(inputs)) + override def generateFromInput + : SchnorrSigPointTestVectorInput => Future[SchnorrSigPointTestVector] = { + inputs => + Future.successful(SchnorrSigPointTestVector(inputs)) } - override def generateTestVectors(): Future[ - Vector[SchnorrSigPointTestVector]] = { + override def generateTestVectors() + : Future[Vector[SchnorrSigPointTestVector]] = { def generateTest: SchnorrSigPointTestVector = { SchnorrSigPointTestVector( ECPrivateKey.freshPrivateKey, diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/TestVectorGen.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/TestVectorGen.scala index edb867cb24..8d9061f8ae 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/TestVectorGen.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/TestVectorGen.scala @@ -30,7 +30,8 @@ trait TestVectorGen[T <: TestVector, Input] { def writeTestVectorsToFile( vecs: Vector[T], - file: File = defaultTestFile): Unit = { + file: File = defaultTestFile + ): Unit = { val arr = JsArray(vecs.map(_.toJson)) writeToFile(arr, file) } @@ -106,20 +107,24 @@ trait TestVectorGen[T <: TestVector, Input] { } else { Future.failed( new RuntimeException( - s"Was unable to delete ${defaultTestFile.getAbsolutePath}")) + s"Was unable to delete ${defaultTestFile.getAbsolutePath}" + ) + ) } } } case JsError(err) => Future.failed( - new IllegalArgumentException(s"Could not read json from file: $err")) + new IllegalArgumentException(s"Could not read json from file: $err") + ) } } def generateTestVectors(): Future[Vector[T]] def generateAndWriteTestVectors( - file: File = defaultTestFile): Future[Unit] = { + file: File = defaultTestFile + ): Future[Unit] = { generateTestVectors().map { testVectors => writeTestVectorsToFile(testVectors, file) } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/DLCFeeTestVectorTest.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/DLCFeeTestVectorTest.scala index 7a877727cd..8b828096e2 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/DLCFeeTestVectorTest.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/DLCFeeTestVectorTest.scala @@ -34,13 +34,15 @@ class DLCFeeTestVectorTest extends BitcoinSJvmTest { acceptChangeSPKLen <- Gen.oneOf(22, 34) feeRate <- FeeUnitGen.satsPerVirtualByte } yield { - DLCFeeTestVector(offerInputs.toVector, - offerPayoutSPKLen, - offerChangeSPKLen, - acceptInputs.toVector, - acceptPayoutSPKLen, - acceptChangeSPKLen, - feeRate) + DLCFeeTestVector( + offerInputs.toVector, + offerPayoutSPKLen, + offerChangeSPKLen, + acceptInputs.toVector, + acceptPayoutSPKLen, + acceptChangeSPKLen, + feeRate + ) } forAll(gen) { feeTest => diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/SchnorrSigPointTestVectorTest.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/SchnorrSigPointTestVectorTest.scala index 3954eb1cc8..d0f3f92fad 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/SchnorrSigPointTestVectorTest.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/SchnorrSigPointTestVectorTest.scala @@ -33,8 +33,11 @@ class SchnorrSigPointTestVectorTest extends BitcoinSUnitTest { vecResult.get.foldLeft(succeed) { case (_, testVec) => assert(SchnorrSigPointTestVector(testVec.inputs) == testVec) assert( - testVec.pubKey.computeSigPoint(testVec.msgHash.bytes, - testVec.pubNonce) == testVec.sigPoint) + testVec.pubKey.computeSigPoint( + testVec.msgHash.bytes, + testVec.pubNonce + ) == testVec.sigPoint + ) } } } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/TestVectorUtil.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/TestVectorUtil.scala index 4c0dbf3561..de98d38751 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/TestVectorUtil.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/dlc/testgen/statictest/TestVectorUtil.scala @@ -24,9 +24,11 @@ object TestVectorUtil { Gen.choose(2, 100).flatMap { numOutcomes => inputsGen.flatMap { offerInputs => inputsGen.flatMap { acceptInputs => - DLCTxGen.validTestInputsForInputs(offerInputs.toVector, - acceptInputs.toVector, - numOutcomes) + DLCTxGen.validTestInputsForInputs( + offerInputs.toVector, + acceptInputs.toVector, + numOutcomes + ) } } } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/p2p/InetAddressJVMTest.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/p2p/InetAddressJVMTest.scala index 7e76eca9ca..f4c33ef6c6 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/p2p/InetAddressJVMTest.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/p2p/InetAddressJVMTest.scala @@ -16,7 +16,9 @@ class InetAddressJVMTest extends BitcoinSUnitTest { forAll(P2PGenerator.inetAddress) { inet => assert( NetworkIpAddress.writeAddress( - JvmAddress.getByAddress(inet.getAddress).getAddress) == inet.bytes) + JvmAddress.getByAddress(inet.getAddress).getAddress + ) == inet.bytes + ) } } @@ -25,7 +27,8 @@ class InetAddressJVMTest extends BitcoinSUnitTest { assert( JvmAddress .getByAddress(inet.ipv4Bytes.toArray) - .getAddress sameElements inet.ipv4Bytes.toArray) + .getAddress sameElements inet.ipv4Bytes.toArray + ) } } } diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/LargeTransactionTest.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/LargeTransactionTest.scala index b05d69ba27..a20bfe76c3 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/LargeTransactionTest.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/LargeTransactionTest.scala @@ -9,7 +9,7 @@ class LargeTransactionTest extends BitcoinSUnitTest { behavior of "LargeTransactionTest" it must "parse a536e7f60a493a258d9adc77d913f7798baf60c808c16898b04579d8c0652681" in { - //from https://mempool.space/testnet/tx/a536e7f60a493a258d9adc77d913f7798baf60c808c16898b04579d8c0652681 + // from https://mempool.space/testnet/tx/a536e7f60a493a258d9adc77d913f7798baf60c808c16898b04579d8c0652681 val fileName = "/a536e7f60a493a258d9adc77d913f7798baf60c808c16898b04579d8c0652681.txt" val lines = diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootTestCase.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootTestCase.scala index 391dcda809..c0a1c46040 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootTestCase.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootTestCase.scala @@ -19,14 +19,15 @@ case class TaprootTestCase( failure: Try[(ScriptSignature, Option[ScriptWitness])], flags: Vector[ScriptFlag], `final`: Option[Boolean], - comment: String) { + comment: String +) { def successTxSigComponent: TxSigComponent = { buildSigComponent(successTx) } - /** Returns the failed tx sig component iff an exception wasn't - * thrown during constructino of the tx sig component + /** Returns the failed tx sig component iff an exception wasn't thrown during + * constructino of the tx sig component */ def failureTxSigComponentsOpt: Option[TxSigComponent] = { failureTxT.map { witTx => @@ -39,31 +40,38 @@ case class TaprootTestCase( val output = prevouts(index) require( prevouts.length == outpoints.length, - s"prevOutputs.length=${prevouts.length} outpoints.length=${outpoints.length}") + s"prevOutputs.length=${prevouts.length} outpoints.length=${outpoints.length}" + ) val outputMap: Map[TransactionOutPoint, TransactionOutput] = outpoints.zip(prevouts).toMap output.scriptPubKey match { case _: TaprootScriptPubKey => tx match { case wtx: WitnessTransaction => - TaprootTxSigComponent(transaction = wtx, - UInt32(index), - PreviousOutputMap(outputMap), - flags) + TaprootTxSigComponent( + transaction = wtx, + UInt32(index), + PreviousOutputMap(outputMap), + flags + ) case nonWitTx: NonWitnessTransaction => - TxSigComponent(transaction = nonWitTx, - UInt32(index), - output, - PreviousOutputMap.empty, - flags) + TxSigComponent( + transaction = nonWitTx, + UInt32(index), + output, + PreviousOutputMap.empty, + flags + ) } case _: ScriptPubKey => - TxSigComponent(transaction = tx, - inputIndex = UInt32(index), - output, - PreviousOutputMap.empty, - flags) + TxSigComponent( + transaction = tx, + inputIndex = UInt32(index), + output, + PreviousOutputMap.empty, + flags + ) } } @@ -96,7 +104,8 @@ case class TaprootTestCase( private def updateTxWithWitness( scriptSig: ScriptSignature, - witnessOpt: Option[ScriptWitness]): Transaction = { + witnessOpt: Option[ScriptWitness] + ): Transaction = { val curInput = tx.inputs(index) val inputWithScriptSig = TransactionInput(curInput.previousOutput, scriptSig, curInput.sequence) @@ -195,18 +204,20 @@ object TaprootTestCase { val flags = ScriptFlagFactory.fromList(obj("flags").str).toVector val finals = obj.value.get("final").map { case b: ujson.Bool => b.bool - case x => sys.error(s"Expected bool for failure object, got=$x") + case x => sys.error(s"Expected bool for failure object, got=$x") } val comment = obj("comment").str - TaprootTestCase(tx = transaction, - prevouts = prevouts, - index = index, - success = success, - failure = failure, - flags = flags, - `final` = finals, - comment = comment) + TaprootTestCase( + tx = transaction, + prevouts = prevouts, + index = index, + success = success, + failure = failure, + flags = flags, + `final` = finals, + comment = comment + ) } catch { case scala.util.control.NonFatal(exn) => println(s"Failed to parse obj=${obj("comment").str}") diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootTxTests.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootTxTests.scala index 4eac918ea1..dca57d8c11 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootTxTests.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootTxTests.scala @@ -17,14 +17,14 @@ class TaprootTxTests extends BitcoinSAsyncTest { behavior of "Taproot test cases" - //these static test vectors take forever + // these static test vectors take forever override lazy val timeLimit: Span = 10.minutes implicit override val executionContext: ExecutionContext = system.dispatchers.lookup("pekko.actor.multi-core-dispatcher") - //these tests are from - //https://raw.githubusercontent.com/bitcoin-core/qa-assets/main/unit_test_data/script_assets_test.json + // these tests are from + // https://raw.githubusercontent.com/bitcoin-core/qa-assets/main/unit_test_data/script_assets_test.json lazy val url = getClass.getResource("/script_assets_test_cp.json") lazy val lines = { @@ -36,8 +36,8 @@ class TaprootTxTests extends BitcoinSAsyncTest { } it must "parse a taproot test case" in { - //https://github.com/bitcoin/bitcoin/blob/v22.0/test/functional/feature_taproot.py#L1112 - //https://github.com/bitcoin/bitcoin/blob/3820090bd619ac85ab35eff376c03136fe4a9f04/src/test/script_tests.cpp#L1673 + // https://github.com/bitcoin/bitcoin/blob/v22.0/test/functional/feature_taproot.py#L1112 + // https://github.com/bitcoin/bitcoin/blob/3820090bd619ac85ab35eff376c03136fe4a9f04/src/test/script_tests.cpp#L1673 val first = testCases.head val expectedTxHex = "f705d6e8019870958e85d1d8f94aa6d74746ba974db0f5ccae49a49b32dcada4e19de4eb5ecb00000000925977cc01f9875c000000000016001431d2b00cd4687ceb34008d9894de84062def14aa05406346" @@ -58,7 +58,7 @@ class TaprootTxTests extends BitcoinSAsyncTest { } it must "run the success test cases through the script interpreter" in { - //execute in parallel as running test cases sequentially takes 17 minutes on CI + // execute in parallel as running test cases sequentially takes 17 minutes on CI val groupedTestCases = testCases.grouped(Runtime.getRuntime.availableProcessors()) @@ -74,7 +74,8 @@ class TaprootTxTests extends BitcoinSAsyncTest { } private def executeSuccessTestCases( - testCases: Vector[TaprootTestCase]): Future[Vector[Assertion]] = { + testCases: Vector[TaprootTestCase] + ): Future[Vector[Assertion]] = { FutureUtil.makeAsync { () => testCases.map { testCase => withClue(testCase.comment) { diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootWalletTestCase.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootWalletTestCase.scala index ee49aa2257..381613d874 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootWalletTestCase.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootWalletTestCase.scala @@ -24,16 +24,19 @@ case class Intermediary( leafHashes: Option[Vector[Sha256Digest]], merkleRootOpt: Option[Sha256Digest], tweak: Sha256Digest, - tweakedPubkey: XOnlyPubKey) + tweakedPubkey: XOnlyPubKey +) case class Expected( scriptPubKey: TaprootScriptPubKey, - bip350Address: Bech32mAddress) + bip350Address: Bech32mAddress +) case class TaprootWalletTestCase( `given`: Given, intermediary: Intermediary, - expected: Expected) + expected: Expected +) case class TaprootWalletTestCases(tests: Vector[TaprootWalletTestCase]) @@ -76,8 +79,10 @@ object TaprootWalletTestCase { Some(leaf) } else { val arr = `given`.arr - require(arr.length == 2, - s"tapscript is a binary tre, not ${arr.length} tree") + require( + arr.length == 2, + s"tapscript is a binary tre, not ${arr.length} tree" + ) val result: Vector[Option[TapscriptTree]] = arr.map(parseScriptTree).toVector val branch = TapBranch(result(0).get, result(1).get) diff --git a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootWalletTestVectors.scala b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootWalletTestVectors.scala index 48c658bcba..a87939e355 100644 --- a/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootWalletTestVectors.scala +++ b/core-test/.jvm/src/test/scala/org/bitcoins/core/protocol/transaction/TaprootWalletTestVectors.scala @@ -9,7 +9,7 @@ import org.scalatest.Assertion class TaprootWalletTestVectors extends BitcoinSUnitTest { behavior of "TaprootWalletTestVectors" - //from: https://github.com/bitcoin/bips/blob/master/bip-0341/wallet-test-vectors.json + // from: https://github.com/bitcoin/bips/blob/master/bip-0341/wallet-test-vectors.json lazy val url = getClass.getResource("/wallet-test-vectors.json") lazy val lines = { @@ -18,7 +18,8 @@ class TaprootWalletTestVectors extends BitcoinSUnitTest { lazy val testCase: TaprootWalletTestCases = { upickle.default.read[TaprootWalletTestCases](lines)( - TaprootWalletTestCase.walletTestVectorReader) + TaprootWalletTestCase.walletTestVectorReader + ) } lazy val tests: Vector[TaprootWalletTestCase] = testCase.tests @@ -32,8 +33,10 @@ class TaprootWalletTestVectors extends BitcoinSUnitTest { } else { val leafHashes = `given`.leafHashes assert(leafHashes == intermediary.leafHashes.get) - assert(`given`.merkleRootOpt == intermediary.merkleRootOpt, - s"test=${test.expected.bip350Address}") + assert( + `given`.merkleRootOpt == intermediary.merkleRootOpt, + s"test=${test.expected.bip350Address}" + ) checkOutput(test) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/bloom/BloomFilterTest.scala b/core-test/src/test/scala/org/bitcoins/core/bloom/BloomFilterTest.scala index b6e85f253c..0f7ce02b60 100644 --- a/core-test/src/test/scala/org/bitcoins/core/bloom/BloomFilterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/bloom/BloomFilterTest.scala @@ -13,14 +13,14 @@ import scala.util.Try class BloomFilterTest extends BitcoinSUnitTest { "BloomFilter" must "create a bloom filter, insert a few elements, then serialize and deserialize it" in { - //test case in bitcoin core - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L28 + // test case in bitcoin core + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L28 val filter = BloomFilter(3, 0.01, UInt32.zero, BloomUpdateAll) - //hex is from bitcoin core + // hex is from bitcoin core filter.hex must be("03000000050000000000000001") val hash = Sha256Hash160Digest("99108ad8ed9bb6274d3980bab5a85c048f0950c8") val newFilter = filter.insert(hash) - //hex from bitcoin core + // hex from bitcoin core newFilter.hex must be("03010098050000000000000001") newFilter.contains(hash) must be(true) @@ -44,16 +44,16 @@ class BloomFilterTest extends BitcoinSUnitTest { } it must "create a bloom filter with a tweak then insert elements and serialize it" in { - //mimics this test case from core https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L59 + // mimics this test case from core https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L59 val filter = BloomFilter(3, 0.01, UInt32(2147483649L), BloomUpdateAll) val hash1 = Sha256Hash160Digest("99108ad8ed9bb6274d3980bab5a85c048f0950c8") val filter1 = filter.insert(hash1) filter1.contains(hash1) must be(true) - //one bit different + // one bit different filter1.contains( - Sha256Hash160Digest("19108ad8ed9bb6274d3980bab5a85c048f0950c8")) must be( - false) + Sha256Hash160Digest("19108ad8ed9bb6274d3980bab5a85c048f0950c8") + ) must be(false) val hash2 = Sha256Hash160Digest("b5a2c786d9ef4658287ced5914b37a1b4aa32eee") val filter2 = filter1.insert(hash2) @@ -69,12 +69,14 @@ class BloomFilterTest extends BitcoinSUnitTest { it must "insert a key & it's address into our bloom filter and the check to make sure it contains them" in { val filter = BloomFilter(2, 0.001, UInt32.zero, BloomUpdateAll) val privKey = ECPrivateKeyUtil.fromWIFToPrivateKey( - "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C") + "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C" + ) assert( - privKey.hex == "f49addfd726a59abde172c86452f5f73038a02f4415878dc14934175e8418aff") + privKey.hex == "f49addfd726a59abde172c86452f5f73038a02f4415878dc14934175e8418aff" + ) val pubKey = privKey.publicKeyBytes val filter1 = filter.insert(pubKey.bytes) - //hex is from bitcoin core + // hex is from bitcoin core filter1.hex must be("0302c12b080000000000000001") val keyId = CryptoUtil.sha256Hash160(pubKey.bytes) val filter2 = filter1.insert(keyId.bytes) @@ -87,10 +89,12 @@ class BloomFilterTest extends BitcoinSUnitTest { // the hashed pubkey, therefore we need 4 elements // for 2 keys val numElements = 4 - val bloom = BloomFilter(numElements = numElements, - falsePositiveRate = 0.000001, - tweak = UInt32(100), - BloomUpdateNone) + val bloom = BloomFilter( + numElements = numElements, + falsePositiveRate = 0.000001, + tweak = UInt32(100), + BloomUpdateNone + ) val firstKey = ECPrivateKey().publicKey val secondKey = ECPrivateKey().publicKey @@ -103,13 +107,15 @@ class BloomFilterTest extends BitcoinSUnitTest { } it must "test the isRelevant part of isRelevantAndUpdate inside of core" in { - //mimics this test case in core - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L114 + // mimics this test case in core + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L114 val creditingTx = Transaction( - "01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000") + "01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffffffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e2754dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d9032a7b9d64fa43188ac00000000" + ) val spendingTx = Transaction( - "01000000016bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4000000008c493046022100da0dc6aecefe1e06efdf05773757deb168820930e3b0d03f46f5fcf150bf990c022100d25b5c87040076e4f253f8262e763e2dd51e7ff0be157727c4bc42807f17bd39014104e6c26ef67dc610d2cd192484789a6cf9aea9930b944b7e2db5342b9d9e5b9ff79aff9a2ee1978dd7fd01dfc522ee02283d3b06a9d03acf8096968d7dbb0f9178ffffffff028ba7940e000000001976a914badeecfdef0507247fc8f74241d73bc039972d7b88ac4094a802000000001976a914c10932483fec93ed51f5fe95e72559f2cc7043f988ac00000000") + "01000000016bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4000000008c493046022100da0dc6aecefe1e06efdf05773757deb168820930e3b0d03f46f5fcf150bf990c022100d25b5c87040076e4f253f8262e763e2dd51e7ff0be157727c4bc42807f17bd39014104e6c26ef67dc610d2cd192484789a6cf9aea9930b944b7e2db5342b9d9e5b9ff79aff9a2ee1978dd7fd01dfc522ee02283d3b06a9d03acf8096968d7dbb0f9178ffffffff028ba7940e000000001976a914badeecfdef0507247fc8f74241d73bc039972d7b88ac4094a802000000001976a914c10932483fec93ed51f5fe95e72559f2cc7043f988ac00000000" + ) val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) @@ -119,38 +125,44 @@ class BloomFilterTest extends BitcoinSUnitTest { val filter2 = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) - //byte reversed tx hash + // byte reversed tx hash val filter3 = filter2.insert( DoubleSha256Digest( - "6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4")) + "6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4" + ) + ) filter3.isRelevant(creditingTx) must be(true) val filter4 = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) - //insert a digital signature in our bloom filter for the spendingTx + // insert a digital signature in our bloom filter for the spendingTx val filter5 = filter4.insert( - hex"30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01") + hex"30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a01" + ) filter5.isRelevant(creditingTx) must be(true) val filter6 = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) - //insert the pubkey of spendingTx in the bloom filter + // insert the pubkey of spendingTx in the bloom filter val pubKey = ECPublicKeyBytes( - "046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339") + "046d11fee51b0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339" + ) val filter7 = filter6.insert(pubKey.bytes) filter7.isRelevant(creditingTx) must be(true) val filter8 = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) val filter9 = filter8.insert( - Sha256Hash160Digest("04943fdd508053c75000106d3bc6e2754dbcff19")) + Sha256Hash160Digest("04943fdd508053c75000106d3bc6e2754dbcff19") + ) filter9.isRelevant(creditingTx) must be(true) - //update the bloom filter to add the outputs inside of the crediting tx - //this is what the core test case really does, but since we separated the isRelevant and update parts, we need - //to call update explicitly + // update the bloom filter to add the outputs inside of the crediting tx + // this is what the core test case really does, but since we separated the isRelevant and update parts, we need + // to call update explicitly val filter10 = filter9.update(creditingTx) filter10.isRelevant(spendingTx) must be(true) val filter11 = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) val filter12 = filter11.insert( - Sha256Hash160Digest("a266436d2965547608b9e15d9032a7b9d64fa431")) + Sha256Hash160Digest("a266436d2965547608b9e15d9032a7b9d64fa431") + ) filter12.isRelevant(creditingTx) must be(true) val filter13 = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) @@ -167,22 +179,27 @@ class BloomFilterTest extends BitcoinSUnitTest { val filter16 = filter15.insert(outPoint) filter16.hex must be( - "230008000000000100000000200040304001000020000000100800050801000400800024130000000000000001") + "230008000000000100000000200040304001000020000000100800050801000400800024130000000000000001" + ) filter16.isRelevant(creditingTx) must be(true) val filter17 = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) - //random tx hash + // random tx hash val filter18 = filter17.insert( DoubleSha256Digest( - "00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436")) + "00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436" + ) + ) filter18.isRelevant(creditingTx) must be(false) val filter19 = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) - //makes sure filter does not match a random outpoint + // makes sure filter does not match a random outpoint val randomOutPoint = TransactionOutPoint( DoubleSha256Digest( - "90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b"), - UInt32.one) + "90c122d70786e899529d71dbeba91ba216982fb6ba58f3bdaab65e73b7e9260b" + ), + UInt32.one + ) val filter20 = filter19.insert(randomOutPoint) filter20.isRelevant(creditingTx) must be(false) @@ -194,18 +211,21 @@ class BloomFilterTest extends BitcoinSUnitTest { } val filter22 = filter21.insert(secondRandomOutPoint) filter22.hex must be( - "230090f00000004000000005040000000004000400000000100101000000008002040000130000000000000001") + "230090f00000004000000005040000000004000400000000100101000000008002040000130000000000000001" + ) filter22.isRelevant(creditingTx) must be(false) } it must "find a transaction is relevant if we have inserted a public key into our bloom filter" in { - //mimics this part of a merkle block test case in core - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L314-L330 + // mimics this part of a merkle block test case in core + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L314-L330 val block = Block( - "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000") + "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000" + ) val txs = block.transactions val pubKey = ECPublicKeyBytes( - "044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af") + "044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af" + ) val filter = BloomFilter(1, 0.00001, UInt32.zero, BloomUpdateNone).insert(pubKey.bytes) @@ -219,10 +239,11 @@ class BloomFilterTest extends BitcoinSUnitTest { } it must "update a bloom filter correctly when the BloomUpdateP2PKOnly flag is set" in { - //follows this test case inside of core - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L423 + // follows this test case inside of core + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L423 val block = Block( - "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000") + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000" + ) // the output for the first transaction in this block is a pay-to-pubkey tx to this pubkey val pubKey = @@ -236,14 +257,14 @@ class BloomFilterTest extends BitcoinSUnitTest { .insert(output) filter.isRelevant(block.transactions.head) must be(true) - //this transaction should be updated in the fitler because the BloomUpdateP2PKOnly flag is set + // this transaction should be updated in the fitler because the BloomUpdateP2PKOnly flag is set val txUpdatedFilter = filter.update(block.transactions.head) - //outpoint of the tx whose scriptPubKey we should match after updating the filter + // outpoint of the tx whose scriptPubKey we should match after updating the filter val outPoint = TransactionOutPoint(block.transactions.head.txId, UInt32.zero) txUpdatedFilter.contains(outPoint) must be(true) - //update the filter with a tx whose output is NOT pay-to-pubkey + // update the filter with a tx whose output is NOT pay-to-pubkey val filterNonP2PKTx = txUpdatedFilter.update(block.transactions(4)) val outPoint2 = TransactionOutPoint(block.transactions(4).txId, UInt32.zero) @@ -255,7 +276,8 @@ class BloomFilterTest extends BitcoinSUnitTest { BloomFlag(1.toByte) must be(BloomUpdateAll) BloomFlag(2.toByte) must be(BloomUpdateP2PKOnly) BloomFlag.fromBytes(ByteVector(BloomUpdateNone.byte)) must be( - BloomUpdateNone) + BloomUpdateNone + ) Try(BloomFlag(Int.MaxValue.toByte)).isFailure must be(true) } diff --git a/core-test/src/test/scala/org/bitcoins/core/config/NetworkParametersTest.scala b/core-test/src/test/scala/org/bitcoins/core/config/NetworkParametersTest.scala index 4f3b4c814b..226c639513 100644 --- a/core-test/src/test/scala/org/bitcoins/core/config/NetworkParametersTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/config/NetworkParametersTest.scala @@ -7,8 +7,8 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest */ class NetworkParametersTest extends BitcoinSUnitTest { - //test case answers are from this link - //https://en.bitcoin.it/wiki/Protocol_documentation#Common_structures + // test case answers are from this link + // https://en.bitcoin.it/wiki/Protocol_documentation#Common_structures "NetworkParameters" must "create the correct magic network bytes for mainnet" in { BytesUtil.encodeHex(MainNet.magicBytes) must be("f9beb4d9") } diff --git a/core-test/src/test/scala/org/bitcoins/core/consensus/MerkleTest.scala b/core-test/src/test/scala/org/bitcoins/core/consensus/MerkleTest.scala index a50bd1a875..870eb99859 100644 --- a/core-test/src/test/scala/org/bitcoins/core/consensus/MerkleTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/consensus/MerkleTest.scala @@ -15,7 +15,8 @@ class MerkleTest extends BitcoinSUnitTest { "Merkle" must "compute the merkle root for the genesis block" in { Merkle.computeBlockMerkleRoot(MainNetChainParams.genesisBlock).hex must be (BytesUtil.flipEndianness( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")) + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + )) } it must "fail to compute the merkle root for a block which has 0 transactions" in { @@ -24,181 +25,260 @@ class MerkleTest extends BitcoinSUnitTest { } it must "correctly compute the merkle root for block 80,000 which has 2 transactions" in { - //this block has 2 transactions in it which makes a nice symmetric merkle tree - //https://blockchain.info/block-height/80000 + // this block has 2 transactions in it which makes a nice symmetric merkle tree + // https://blockchain.info/block-height/80000 val coinbaseTx = Transaction( - "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704e6ed5b1b014effffffff0100f2052a01000000434104b68a50eaa0287eff855189f949c1c6e5f58b37c88231373d8a59809cbae83059cc6469d65c665ccfd1cfeb75c6e8e19413bba7fbff9bc762419a76d87b16086eac00000000") + "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704e6ed5b1b014effffffff0100f2052a01000000434104b68a50eaa0287eff855189f949c1c6e5f58b37c88231373d8a59809cbae83059cc6469d65c665ccfd1cfeb75c6e8e19413bba7fbff9bc762419a76d87b16086eac00000000" + ) require( coinbaseTx.txId.hex == BytesUtil.flipEndianness( - "c06fbab289f723c6261d3030ddb6be121f7d2508d77862bb1e484f5cd7f92b25")) + "c06fbab289f723c6261d3030ddb6be121f7d2508d77862bb1e484f5cd7f92b25" + ) + ) val tx1 = Transaction( - "0100000001a6b97044d03da79c005b20ea9c0e1a6d9dc12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac00000000") + "0100000001a6b97044d03da79c005b20ea9c0e1a6d9dc12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b65d35549d88ac00000000" + ) require( tx1.txId.hex == BytesUtil.flipEndianness( - "5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2")) + "5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2" + ) + ) val transactions = Seq(coinbaseTx, tx1) Merkle.computeMerkleRoot(transactions).hex must be( BytesUtil.flipEndianness( - "8fb300e3fdb6f30a4c67233b997f99fdd518b968b9a3fd65857bfe78b2600719")) + "8fb300e3fdb6f30a4c67233b997f99fdd518b968b9a3fd65857bfe78b2600719" + ) + ) } it must "correctly compute the merkle root for a block with 3 transactions" in { - //https://blockchain.info/block-height/93500 + // https://blockchain.info/block-height/93500 val coinbaseTx = Transaction( - "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08042a8b091b025e3cffffffff0100f2052a01000000434104d77816ded32ccc56fad6f455676c07908da96a37a7b9d2fd510cd4ddd92f3104f3d6e7134bd159fed3741522265a901d44ec2ab428231c0e4986c52a22f13577ac00000000") + "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08042a8b091b025e3cffffffff0100f2052a01000000434104d77816ded32ccc56fad6f455676c07908da96a37a7b9d2fd510cd4ddd92f3104f3d6e7134bd159fed3741522265a901d44ec2ab428231c0e4986c52a22f13577ac00000000" + ) require( coinbaseTx.txId.hex == BytesUtil.flipEndianness( - "a7c2b4a2cc940f9f541905048fe8352bd158dab18d15221fab7ee2187bd3cb5e")) + "a7c2b4a2cc940f9f541905048fe8352bd158dab18d15221fab7ee2187bd3cb5e" + ) + ) val tx1 = Transaction( - "0100000006588e823839ae8e88dede39e38ff01e8c90d05a887425ed55eabecf6020738224000000008b483045022100f6db4e4e90a5760f69c19915483ba6a6315aa2e77d20e82352b695b6451230cd0220359f352a2b7d7a5a8ec5fb71ea58a03addb0340c0293444d553b4ef9c8b0810e0141047247fe4f3927ac892e569e70fd111f3f2ccff9038cbaa161055401713f32e6e2b7179114a2defdd4fbb705d0e2f590fb546386b05b86fe8894b8a6e74f2f5518ffffffff5f35f5725a031d43a50932beeeb863d82e064003ed0e9183afeafe0d5c1d7ffb000000008b48304502202347b11b43964b2e0acecb356a8f9d45d5a0dbbd6a916351bb221e4346fc3287022100a983c5f45e41e9dbe7ddd8490e070c1755205c3909ec7a2cabd8b96bdb8cfa1d0141047e848e792ae7d79b1ec2ce996e2679ae57e3a731db9d8f20c2be48d19c916d1db3e2b063a422e7511f60fe657134698528644935b3d2d75713e07e55f00487e7ffffffff5bf96d93cb82d645369761dc478ff36cf84691ea86c8a68255e7e52799e5aec4010000008a47304402205aa4bf439b85fc6ce12c933e05b387436456269acc4bef40fbce11e850c79f0b022033d425ac44ffb0ffe05708af025b3a4a19fb9e2127d6ede39dce8ff80e78f6270141045dedbe2d352e9327bfefd3dfcd808f87162277ddc4802c600110b736d20a7e6e263634079422a3e4cb00a769657dfa6718feb1cd9bfae1d4b152267fa2040d38ffffffffd9c85951982849492a422d2c918928d21e6c10b07ffaec2e566bea165ce6355d000000008b483045022100ec2eb7afd57c5b281d68708b0a46948221a9b0497736214ca9e5049bb2d764fe02201ddec4c71bdf73b3022b0c3f3e5a340126cefc2076c5d35edb849ee6006ed177014104060c334bdd808dc33008e27b3b01f8f0de9a074038e445fa3252a71a8cbf8b80abee043652b3ebf7cb1f921c2f6dd715858a8cc3c6fdde84f92dbaa9a91c0d51ffffffffba73f0deba362f932bebe223ac478303fd7b4a72dd45ac299882cf720f289eb2010000008b483045022100c0ecc02da03f9bcd1a29db63fd76f18025dd4f2a9de80818077106e093f6da6e0220714835dc93c86b77220564dbd9b9dc67855bfe6bf097670ad9b760b18bb3943c014104ebfe79ce9fe65ca2bca723b692039befba3df71cdd4dab7ad046b864644a5df70a4c90393549243bb475e7b5acdc08fc4b0307ae362861aa19f38e9b0f746c9affffffff056011d7b88b6ca196b0c953063c6c92d6dcb4d7ea31800da227971417ce68ec000000008b483045022100dbe5f0060b87ce7a63a6b46c7fcf19ab516313ff31f33470eecc456a1bb5f01d022027a1c2e0969fe98c458cd7c34e89c26de9ae769758ff5953751653469f94c375014104052cfb55b4a642b3453fbc9797ab7101623789b18f06b0091b03c03af9656a1ce4ac3a7bb65d634d023f9f7dde778a4dad6ae397761cc185de935e2959a0eedaffffffff0200969900020000001976a9141f6630103c210cc5be5c96ce04bac3ed0a9ad22188ac00093d00000000001976a91480d529f416e5fc5d98a8a24622abb45f0a03418888ac00000000") + "0100000006588e823839ae8e88dede39e38ff01e8c90d05a887425ed55eabecf6020738224000000008b483045022100f6db4e4e90a5760f69c19915483ba6a6315aa2e77d20e82352b695b6451230cd0220359f352a2b7d7a5a8ec5fb71ea58a03addb0340c0293444d553b4ef9c8b0810e0141047247fe4f3927ac892e569e70fd111f3f2ccff9038cbaa161055401713f32e6e2b7179114a2defdd4fbb705d0e2f590fb546386b05b86fe8894b8a6e74f2f5518ffffffff5f35f5725a031d43a50932beeeb863d82e064003ed0e9183afeafe0d5c1d7ffb000000008b48304502202347b11b43964b2e0acecb356a8f9d45d5a0dbbd6a916351bb221e4346fc3287022100a983c5f45e41e9dbe7ddd8490e070c1755205c3909ec7a2cabd8b96bdb8cfa1d0141047e848e792ae7d79b1ec2ce996e2679ae57e3a731db9d8f20c2be48d19c916d1db3e2b063a422e7511f60fe657134698528644935b3d2d75713e07e55f00487e7ffffffff5bf96d93cb82d645369761dc478ff36cf84691ea86c8a68255e7e52799e5aec4010000008a47304402205aa4bf439b85fc6ce12c933e05b387436456269acc4bef40fbce11e850c79f0b022033d425ac44ffb0ffe05708af025b3a4a19fb9e2127d6ede39dce8ff80e78f6270141045dedbe2d352e9327bfefd3dfcd808f87162277ddc4802c600110b736d20a7e6e263634079422a3e4cb00a769657dfa6718feb1cd9bfae1d4b152267fa2040d38ffffffffd9c85951982849492a422d2c918928d21e6c10b07ffaec2e566bea165ce6355d000000008b483045022100ec2eb7afd57c5b281d68708b0a46948221a9b0497736214ca9e5049bb2d764fe02201ddec4c71bdf73b3022b0c3f3e5a340126cefc2076c5d35edb849ee6006ed177014104060c334bdd808dc33008e27b3b01f8f0de9a074038e445fa3252a71a8cbf8b80abee043652b3ebf7cb1f921c2f6dd715858a8cc3c6fdde84f92dbaa9a91c0d51ffffffffba73f0deba362f932bebe223ac478303fd7b4a72dd45ac299882cf720f289eb2010000008b483045022100c0ecc02da03f9bcd1a29db63fd76f18025dd4f2a9de80818077106e093f6da6e0220714835dc93c86b77220564dbd9b9dc67855bfe6bf097670ad9b760b18bb3943c014104ebfe79ce9fe65ca2bca723b692039befba3df71cdd4dab7ad046b864644a5df70a4c90393549243bb475e7b5acdc08fc4b0307ae362861aa19f38e9b0f746c9affffffff056011d7b88b6ca196b0c953063c6c92d6dcb4d7ea31800da227971417ce68ec000000008b483045022100dbe5f0060b87ce7a63a6b46c7fcf19ab516313ff31f33470eecc456a1bb5f01d022027a1c2e0969fe98c458cd7c34e89c26de9ae769758ff5953751653469f94c375014104052cfb55b4a642b3453fbc9797ab7101623789b18f06b0091b03c03af9656a1ce4ac3a7bb65d634d023f9f7dde778a4dad6ae397761cc185de935e2959a0eedaffffffff0200969900020000001976a9141f6630103c210cc5be5c96ce04bac3ed0a9ad22188ac00093d00000000001976a91480d529f416e5fc5d98a8a24622abb45f0a03418888ac00000000" + ) require( tx1.txId.hex == BytesUtil.flipEndianness( - "1d74396699ae0effcd67fd5d031b780ff56c336bfc5d2d015d21db687d732764")) + "1d74396699ae0effcd67fd5d031b780ff56c336bfc5d2d015d21db687d732764" + ) + ) val tx2 = Transaction( - "0100000001eba8353ac2e5503f15548975108013246457ed83d331db760f0595b8bd7c54cb000000008c4930460221008c64f29882d9a59cbb070d75b4cdca56c04b523b0af37a0ffecee24e31cb2814022100b183ab317ad217f4a6f4e610c6138e5c2d7681d40f46201f268a5a90c1c07afa0141040b362c040204c13f6e1ec78b60978bdd76d851d4a1612cd9e82ead5177694f8f37fa4e8c78579876bbaf8a561772f320d3125f36cd1f1c5e9eb3f8bc08b626d2ffffffff0280e9fd97000000001976a914f0630fd41ff0722cf29de4db609f06a4c17fad2d88ac002a7515000000001976a9141dea9e37227b8d7a6296849fc76e00e8f5a6674e88ac00000000") + "0100000001eba8353ac2e5503f15548975108013246457ed83d331db760f0595b8bd7c54cb000000008c4930460221008c64f29882d9a59cbb070d75b4cdca56c04b523b0af37a0ffecee24e31cb2814022100b183ab317ad217f4a6f4e610c6138e5c2d7681d40f46201f268a5a90c1c07afa0141040b362c040204c13f6e1ec78b60978bdd76d851d4a1612cd9e82ead5177694f8f37fa4e8c78579876bbaf8a561772f320d3125f36cd1f1c5e9eb3f8bc08b626d2ffffffff0280e9fd97000000001976a914f0630fd41ff0722cf29de4db609f06a4c17fad2d88ac002a7515000000001976a9141dea9e37227b8d7a6296849fc76e00e8f5a6674e88ac00000000" + ) require( tx2.txId.hex == BytesUtil.flipEndianness( - "d8c9d6a13a7fb8236833b1e93d298f4626deeb78b2f1814aa9a779961c08ce39")) + "d8c9d6a13a7fb8236833b1e93d298f4626deeb78b2f1814aa9a779961c08ce39" + ) + ) val transactions = Seq(coinbaseTx, tx1, tx2) Merkle.computeMerkleRoot(transactions).hex must be( BytesUtil.flipEndianness( - "d277b5d20fab7cdb8140ab953323b585445d4920ad7226623d9c7ed0bc6b9a57")) + "d277b5d20fab7cdb8140ab953323b585445d4920ad7226623d9c7ed0bc6b9a57" + ) + ) } it must "correctly compute the merkle root for the 100,000 block which has 4 transactions" in { - //this block has 4 transactions in it which makes a nice symmetric merkle tree - //https://blockchain.info/block-height/100000 + // this block has 4 transactions in it which makes a nice symmetric merkle tree + // https://blockchain.info/block-height/100000 val coinbaseTx = Transaction( - "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020602ffffffff0100f2052a010000004341041b0e8c2567c12536aa13357b79a073dc4444acb83c4ec7a0e2f99dd7457516c5817242da796924ca4e99947d087fedf9ce467cb9f7c6287078f801df276fdf84ac00000000") + "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020602ffffffff0100f2052a010000004341041b0e8c2567c12536aa13357b79a073dc4444acb83c4ec7a0e2f99dd7457516c5817242da796924ca4e99947d087fedf9ce467cb9f7c6287078f801df276fdf84ac00000000" + ) val tx1 = Transaction( - "0100000001032e38e9c0a84c6046d687d10556dcacc41d275ec55fc00779ac88fdf357a187000000008c493046022100c352d3dd993a981beba4a63ad15c209275ca9470abfcd57da93b58e4eb5dce82022100840792bc1f456062819f15d33ee7055cf7b5ee1af1ebcc6028d9cdb1c3af7748014104f46db5e9d61a9dc27b8d64ad23e7383a4e6ca164593c2527c038c0857eb67ee8e825dca65046b82c9331586c82e0fd1f633f25f87c161bc6f8a630121df2b3d3ffffffff0200e32321000000001976a914c398efa9c392ba6013c5e04ee729755ef7f58b3288ac000fe208010000001976a914948c765a6914d43f2a7ac177da2c2f6b52de3d7c88ac00000000") + "0100000001032e38e9c0a84c6046d687d10556dcacc41d275ec55fc00779ac88fdf357a187000000008c493046022100c352d3dd993a981beba4a63ad15c209275ca9470abfcd57da93b58e4eb5dce82022100840792bc1f456062819f15d33ee7055cf7b5ee1af1ebcc6028d9cdb1c3af7748014104f46db5e9d61a9dc27b8d64ad23e7383a4e6ca164593c2527c038c0857eb67ee8e825dca65046b82c9331586c82e0fd1f633f25f87c161bc6f8a630121df2b3d3ffffffff0200e32321000000001976a914c398efa9c392ba6013c5e04ee729755ef7f58b3288ac000fe208010000001976a914948c765a6914d43f2a7ac177da2c2f6b52de3d7c88ac00000000" + ) val tx2 = Transaction( - "0100000001c33ebff2a709f13d9f9a7569ab16a32786af7d7e2de09265e41c61d078294ecf010000008a4730440220032d30df5ee6f57fa46cddb5eb8d0d9fe8de6b342d27942ae90a3231e0ba333e02203deee8060fdc70230a7f5b4ad7d7bc3e628cbe219a886b84269eaeb81e26b4fe014104ae31c31bf91278d99b8377a35bbce5b27d9fff15456839e919453fc7b3f721f0ba403ff96c9deeb680e5fd341c0fc3a7b90da4631ee39560639db462e9cb850fffffffff0240420f00000000001976a914b0dcbf97eabf4404e31d952477ce822dadbe7e1088acc060d211000000001976a9146b1281eec25ab4e1e0793ff4e08ab1abb3409cd988ac00000000") + "0100000001c33ebff2a709f13d9f9a7569ab16a32786af7d7e2de09265e41c61d078294ecf010000008a4730440220032d30df5ee6f57fa46cddb5eb8d0d9fe8de6b342d27942ae90a3231e0ba333e02203deee8060fdc70230a7f5b4ad7d7bc3e628cbe219a886b84269eaeb81e26b4fe014104ae31c31bf91278d99b8377a35bbce5b27d9fff15456839e919453fc7b3f721f0ba403ff96c9deeb680e5fd341c0fc3a7b90da4631ee39560639db462e9cb850fffffffff0240420f00000000001976a914b0dcbf97eabf4404e31d952477ce822dadbe7e1088acc060d211000000001976a9146b1281eec25ab4e1e0793ff4e08ab1abb3409cd988ac00000000" + ) val tx3 = Transaction( - "01000000010b6072b386d4a773235237f64c1126ac3b240c84b917a3909ba1c43ded5f51f4000000008c493046022100bb1ad26df930a51cce110cf44f7a48c3c561fd977500b1ae5d6b6fd13d0b3f4a022100c5b42951acedff14abba2736fd574bdb465f3e6f8da12e2c5303954aca7f78f3014104a7135bfe824c97ecc01ec7d7e336185c81e2aa2c41ab175407c09484ce9694b44953fcb751206564a9c24dd094d42fdbfdd5aad3e063ce6af4cfaaea4ea14fbbffffffff0140420f00000000001976a91439aa3d569e06a1d7926dc4be1193c99bf2eb9ee088ac00000000") + "01000000010b6072b386d4a773235237f64c1126ac3b240c84b917a3909ba1c43ded5f51f4000000008c493046022100bb1ad26df930a51cce110cf44f7a48c3c561fd977500b1ae5d6b6fd13d0b3f4a022100c5b42951acedff14abba2736fd574bdb465f3e6f8da12e2c5303954aca7f78f3014104a7135bfe824c97ecc01ec7d7e336185c81e2aa2c41ab175407c09484ce9694b44953fcb751206564a9c24dd094d42fdbfdd5aad3e063ce6af4cfaaea4ea14fbbffffffff0140420f00000000001976a91439aa3d569e06a1d7926dc4be1193c99bf2eb9ee088ac00000000" + ) val transactions = Seq(coinbaseTx, tx1, tx2, tx3) Merkle.computeMerkleRoot(transactions).hex must be( BytesUtil.flipEndianness( - "f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766")) + "f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766" + ) + ) } it must "correctly compute the merkle root for a block with 5 transactions" in { - //https://blockchain.info/block-height/98500 + // https://blockchain.info/block-height/98500 val coinbaseTx = Transaction( - "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07045359051b0113ffffffff0100f2052a01000000434104bca047b2df9d2e8afcd3000b4769caabd3ff5d668984cd4331fae4aa56b885f536a356252d65577445a1e25b0c9851a99c0ee4b89494c550d136813cbb597910ac00000000") + "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07045359051b0113ffffffff0100f2052a01000000434104bca047b2df9d2e8afcd3000b4769caabd3ff5d668984cd4331fae4aa56b885f536a356252d65577445a1e25b0c9851a99c0ee4b89494c550d136813cbb597910ac00000000" + ) require( coinbaseTx.txId.hex == BytesUtil.flipEndianness( - "bde8a214516cb60a658df9515ba078d094ce416281f1277e83a42db8638e4d33")) + "bde8a214516cb60a658df9515ba078d094ce416281f1277e83a42db8638e4d33" + ) + ) val tx1 = Transaction( - "0100000001007320d46791b00322f9f9158cf480f8b623433776f4bd0a51f34db9281e3083010000008b483045022100c8893bf506b3b679ac384e02e6f7e4f94a5954b99ad4a88ee97b29de504d845b022037f20340a1c45edaefbfe25eb6c4a7b65e3369753fccabe510bbdee3a9064fd70141048d16442ee408075783d1293b515fe1b28ed39abb020c6199ce2f4a5c14d577fadc56cbacf8b5f9f75b900c3c3ba30d34f58b6aed5712bb0c5bd364985de3e26bffffffff0200d27b86080000001976a914e772268c12916cb35d6728f697e05af2ede3b46b88ac404b4c00000000001976a91483a2a9adc7e430b2bbf78864c22979b4cb69204288ac00000000") + "0100000001007320d46791b00322f9f9158cf480f8b623433776f4bd0a51f34db9281e3083010000008b483045022100c8893bf506b3b679ac384e02e6f7e4f94a5954b99ad4a88ee97b29de504d845b022037f20340a1c45edaefbfe25eb6c4a7b65e3369753fccabe510bbdee3a9064fd70141048d16442ee408075783d1293b515fe1b28ed39abb020c6199ce2f4a5c14d577fadc56cbacf8b5f9f75b900c3c3ba30d34f58b6aed5712bb0c5bd364985de3e26bffffffff0200d27b86080000001976a914e772268c12916cb35d6728f697e05af2ede3b46b88ac404b4c00000000001976a91483a2a9adc7e430b2bbf78864c22979b4cb69204288ac00000000" + ) require( tx1.txId.hex == BytesUtil.flipEndianness( - "96a446afdd9e0dbdd4d33cf14be18cb1bf8f46a8fd3f7fcbbad853b47d200c33")) + "96a446afdd9e0dbdd4d33cf14be18cb1bf8f46a8fd3f7fcbbad853b47d200c33" + ) + ) val tx2 = Transaction( - "01000000020fee818ede67485682844b7611bf81abb26dd0aefce430259541761d0e52c74c000000008a473044022038521d9914da4e9c72cfbe0c90ba0adc73b429b84cd89155d3c5479a4e2772e30220172457e0e0796214a8ecd5b246b49d78bd1158e4b16943ae676f196a484c76e70141048431c896f2ad3bf1d32ddbd5116154f4dcd510ed5d27de529e0dd276a24a60e73b1999bb7b46c7edadc60da7cb5945094b5d37a9a83859a47dab5d2c59cd739effffffff7851dd60e5a5ea9bd1252d3128bd3b757ef1a744421799b76db34e0af70d4191010000008a4730440220373cce7182f148eb70ed523f4dd9007bd6f68a86f3284b8ec5588aa11d53455302205393f045b8134aeed54ac9081f9bb295250ca5c9863b7fb252ea8d7bb4cf661b0141041f2d46ae7a8a35bc3e09be573eeeabaae3608dd4f3bb2a75ec8a33ec127757f70230aadaae3ab1570f08e16969d88aee7a2addcf3bcf435b66cdd14b3a25303fffffffff0100e1f505000000001976a914e01f9eff99a725dd3c7548836477529c62c9139e88ac00000000") + "01000000020fee818ede67485682844b7611bf81abb26dd0aefce430259541761d0e52c74c000000008a473044022038521d9914da4e9c72cfbe0c90ba0adc73b429b84cd89155d3c5479a4e2772e30220172457e0e0796214a8ecd5b246b49d78bd1158e4b16943ae676f196a484c76e70141048431c896f2ad3bf1d32ddbd5116154f4dcd510ed5d27de529e0dd276a24a60e73b1999bb7b46c7edadc60da7cb5945094b5d37a9a83859a47dab5d2c59cd739effffffff7851dd60e5a5ea9bd1252d3128bd3b757ef1a744421799b76db34e0af70d4191010000008a4730440220373cce7182f148eb70ed523f4dd9007bd6f68a86f3284b8ec5588aa11d53455302205393f045b8134aeed54ac9081f9bb295250ca5c9863b7fb252ea8d7bb4cf661b0141041f2d46ae7a8a35bc3e09be573eeeabaae3608dd4f3bb2a75ec8a33ec127757f70230aadaae3ab1570f08e16969d88aee7a2addcf3bcf435b66cdd14b3a25303fffffffff0100e1f505000000001976a914e01f9eff99a725dd3c7548836477529c62c9139e88ac00000000" + ) require( tx2.txId.hex == BytesUtil.flipEndianness( - "d3561b5c19b8506f0e5230471ce379feecd5506f4ea4605a1c220652fe8ad0a6")) + "d3561b5c19b8506f0e5230471ce379feecd5506f4ea4605a1c220652fe8ad0a6" + ) + ) val tx3 = Transaction( - "0100000001d7dc7643bf3c9fe8bad464b9447916928d4cc5419d6a6e5d0b32ae25534d7f0a000000008a473044022003fc88222e4d52cd9753887145acf2f2a9f4cfb160eddfb3b27b82b10c1ac9b8022079fc38b0fc74a154aae9df854a3ebc4dc1d43ed6bf9cd2af3617ead8dc86d2f501410454f63db0081744756df83f492c642de26ddf2089ebf7ee3abfdcd7a4908dfb841da3c602302ce2445022ed9c6146c5c784ce2d3cb9b3a393dc9311f5ea84a268ffffffff0180841e00000000001976a91439aa3d569e06a1d7926dc4be1193c99bf2eb9ee088ac00000000") + "0100000001d7dc7643bf3c9fe8bad464b9447916928d4cc5419d6a6e5d0b32ae25534d7f0a000000008a473044022003fc88222e4d52cd9753887145acf2f2a9f4cfb160eddfb3b27b82b10c1ac9b8022079fc38b0fc74a154aae9df854a3ebc4dc1d43ed6bf9cd2af3617ead8dc86d2f501410454f63db0081744756df83f492c642de26ddf2089ebf7ee3abfdcd7a4908dfb841da3c602302ce2445022ed9c6146c5c784ce2d3cb9b3a393dc9311f5ea84a268ffffffff0180841e00000000001976a91439aa3d569e06a1d7926dc4be1193c99bf2eb9ee088ac00000000" + ) require( tx3.txId.hex == BytesUtil.flipEndianness( - "52eedbfd8596f629d61cadb0cddf781d1f64fbb5ea5f015db760a4bf2e603568")) + "52eedbfd8596f629d61cadb0cddf781d1f64fbb5ea5f015db760a4bf2e603568" + ) + ) val tx4 = Transaction( - "0100000001330c207db453d8bacb7f3ffda8468fbfb18ce14bf13cd3d4bd0d9eddaf46a496000000008c493046022100cf5c76c34de0fc8538f1dc8663edac41c05e4fc42fb2f6188c6a044c6906c83b022100a96aca4ebdae7502c0d2241ac4b72bf6e5a56debcc251cfe7380ecabf64a742e014104e919396bf90935fba5f6d58af2f4e844a65a239ff23b695c982345a36bb7dbc23f4a950fc5092ff8c1a64209ad147a82b446defe9480970fb36990e8cceb6da3ffffffff02404b4c00000000001976a914004c7a02611b21082d41d6520042d038a183c51288acc0862f86080000001976a9143aa3e0f999ac63971bd568ae4336cedeba9682b788ac00000000") + "0100000001330c207db453d8bacb7f3ffda8468fbfb18ce14bf13cd3d4bd0d9eddaf46a496000000008c493046022100cf5c76c34de0fc8538f1dc8663edac41c05e4fc42fb2f6188c6a044c6906c83b022100a96aca4ebdae7502c0d2241ac4b72bf6e5a56debcc251cfe7380ecabf64a742e014104e919396bf90935fba5f6d58af2f4e844a65a239ff23b695c982345a36bb7dbc23f4a950fc5092ff8c1a64209ad147a82b446defe9480970fb36990e8cceb6da3ffffffff02404b4c00000000001976a914004c7a02611b21082d41d6520042d038a183c51288acc0862f86080000001976a9143aa3e0f999ac63971bd568ae4336cedeba9682b788ac00000000" + ) require( tx4.txId.hex == BytesUtil.flipEndianness( - "b79606d7377285e1a4f9cb757c9f1a1d36f09c10bc52be49b170c6dd40767669")) + "b79606d7377285e1a4f9cb757c9f1a1d36f09c10bc52be49b170c6dd40767669" + ) + ) val transactions = Seq(coinbaseTx, tx1, tx2, tx3, tx4) Merkle.computeMerkleRoot(transactions).hex must be( BytesUtil.flipEndianness( - "36b38854f9adf76b4646ab2c0f949846408cfab2c045f110d01f84f4122c5add")) + "36b38854f9adf76b4646ab2c0f949846408cfab2c045f110d01f84f4122c5add" + ) + ) } it must "correctly compute the merkle root for a block with 11 transactions" in { - //https://blockchain.info/block-height/101000 + // https://blockchain.info/block-height/101000 val coinbaseTx = Transaction( - "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704cb04041b014affffffff0100f2052a01000000434104204b65fb53be30419ac44ba3a73f128bb9fac510e602de1442ac989a44dcd5a3b9229b594ec437e7ee5d3ffc7e858add6c3f4787b8a8c3d6b4f8b091bf823c3dac00000000") + "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704cb04041b014affffffff0100f2052a01000000434104204b65fb53be30419ac44ba3a73f128bb9fac510e602de1442ac989a44dcd5a3b9229b594ec437e7ee5d3ffc7e858add6c3f4787b8a8c3d6b4f8b091bf823c3dac00000000" + ) require( coinbaseTx.txId.hex == BytesUtil.flipEndianness( - "a2c90afe34f1a9b975d29e8f0d80b04acfa51d775160b11cf2dd7221008fc3c8")) + "a2c90afe34f1a9b975d29e8f0d80b04acfa51d775160b11cf2dd7221008fc3c8" + ) + ) val tx1 = Transaction( - "0100000001a33c65f483575784ca237716c0b9a51a3262c4ee8454ac88352f1bd08e7c71ad0000000049483045022046957e1ad5ddbae7342bbc270cec6f08a5c82211bd06e2b19d140ebfdc708692022100b5289e1d23b48b6975d9b9d1418616f1fa570ac4e10946bc4e7b8baf73bbbca401ffffffff0240147422010000001976a914e2757955eec59afd698d2f3085e48ad98ab1bc8b88acc0dd9107000000001976a914b55dd29fed068ccc1bc17312559953f6583ee7e488ac00000000") + "0100000001a33c65f483575784ca237716c0b9a51a3262c4ee8454ac88352f1bd08e7c71ad0000000049483045022046957e1ad5ddbae7342bbc270cec6f08a5c82211bd06e2b19d140ebfdc708692022100b5289e1d23b48b6975d9b9d1418616f1fa570ac4e10946bc4e7b8baf73bbbca401ffffffff0240147422010000001976a914e2757955eec59afd698d2f3085e48ad98ab1bc8b88acc0dd9107000000001976a914b55dd29fed068ccc1bc17312559953f6583ee7e488ac00000000" + ) require( tx1.txId.hex == BytesUtil.flipEndianness( - "e708cd2450a95173a8af0a7e256010dcbfa3895a467a440f0bb78af4ce69a774")) + "e708cd2450a95173a8af0a7e256010dcbfa3895a467a440f0bb78af4ce69a774" + ) + ) val tx2 = Transaction( - "0100000001844cecc7af8ebbaf190a2c9483b6c13396ba004ec078e6d53c9729826bcb332100000000494830450220757a3bd57a66a9f46a0e7e71a4a8b2aee6d73b39285a16ff70c5e41469942b5b022100b55db0e6c38ed9bdd696a57a5ef1685bf536203eb87e59453b43446c0388a5a201ffffffff0280568322010000001976a914bb0667115ba371dda3abd3c6f6fee2777cb4336188ac809b8207000000001976a91463d4dd1b29d95ed601512b487bfc1c49d84d057988ac00000000") + "0100000001844cecc7af8ebbaf190a2c9483b6c13396ba004ec078e6d53c9729826bcb332100000000494830450220757a3bd57a66a9f46a0e7e71a4a8b2aee6d73b39285a16ff70c5e41469942b5b022100b55db0e6c38ed9bdd696a57a5ef1685bf536203eb87e59453b43446c0388a5a201ffffffff0280568322010000001976a914bb0667115ba371dda3abd3c6f6fee2777cb4336188ac809b8207000000001976a91463d4dd1b29d95ed601512b487bfc1c49d84d057988ac00000000" + ) require( tx2.txId.hex == BytesUtil.flipEndianness( - "7cb7f0c5bad1fc13748e788410f0020db92ba700ad2a668d9c2b6c4aabda2c85")) + "7cb7f0c5bad1fc13748e788410f0020db92ba700ad2a668d9c2b6c4aabda2c85" + ) + ) val tx3 = Transaction( - "0100000001521f1014e1439a4a979b96543eb9fde6fed3033c041777ac888e998a9b5ad687000000008b4830450220042cc7cd451b9d8ac058657b6ea2cce47748a0e4d121fe8959bb12e1d7a33343022100c001bb864c8dd2202c4700a65e91cee7e6b0b75a6075a8e174042e2742c80fe30141046b6331d6d3178e478e88487cf2130365e8c9a099eec187750f98cd6765c0d8f6863ef951072a46bb189985d1406cae2bebe656eeadbc4a0c734a6c462ec35df6ffffffff0280da2d09000000001976a914c22420641cea028c9e06c4d9104c1646f8b1769088ac80a61117010000001976a9142db035e0550aae55ba9275769a487d9fd06da81188ac00000000") + "0100000001521f1014e1439a4a979b96543eb9fde6fed3033c041777ac888e998a9b5ad687000000008b4830450220042cc7cd451b9d8ac058657b6ea2cce47748a0e4d121fe8959bb12e1d7a33343022100c001bb864c8dd2202c4700a65e91cee7e6b0b75a6075a8e174042e2742c80fe30141046b6331d6d3178e478e88487cf2130365e8c9a099eec187750f98cd6765c0d8f6863ef951072a46bb189985d1406cae2bebe656eeadbc4a0c734a6c462ec35df6ffffffff0280da2d09000000001976a914c22420641cea028c9e06c4d9104c1646f8b1769088ac80a61117010000001976a9142db035e0550aae55ba9275769a487d9fd06da81188ac00000000" + ) require( tx3.txId.hex == BytesUtil.flipEndianness( - "5a8b536a80285454839571baf006c9346ef8e5e82dc27d011d307f4c23c26dae")) + "5a8b536a80285454839571baf006c9346ef8e5e82dc27d011d307f4c23c26dae" + ) + ) val tx4 = Transaction( - "010000000123e1398b14f1cba6ddc52214345710c9349e0081afa5ab7a95d6511c2aceec0d010000008c493046022100c2fa6176889034e1f240174808e58302501970424a3dc7ecb127a0362d9716e002210093010e4e06e53efeaa0adf437fc068fcaac3615dd12b0ff6a7eb583c0390ef5f01410434bc0b5bed684ac2baf2c1112531074ae65fe60633514a413eb610862e6e25f562bc75f68e5b3590a2aaed3aa1cb9493ae5a1df448c219c1029f92ea6589dfe1ffffffff02c02f720b010000001976a914e5d802968edc0dab6fc68f91e9b49681854bd10788ac40bc120a000000001976a914c928507652fe7f42e838566153357d81c27b35ff88ac00000000") + "010000000123e1398b14f1cba6ddc52214345710c9349e0081afa5ab7a95d6511c2aceec0d010000008c493046022100c2fa6176889034e1f240174808e58302501970424a3dc7ecb127a0362d9716e002210093010e4e06e53efeaa0adf437fc068fcaac3615dd12b0ff6a7eb583c0390ef5f01410434bc0b5bed684ac2baf2c1112531074ae65fe60633514a413eb610862e6e25f562bc75f68e5b3590a2aaed3aa1cb9493ae5a1df448c219c1029f92ea6589dfe1ffffffff02c02f720b010000001976a914e5d802968edc0dab6fc68f91e9b49681854bd10788ac40bc120a000000001976a914c928507652fe7f42e838566153357d81c27b35ff88ac00000000" + ) require( tx4.txId.hex == BytesUtil.flipEndianness( - "29ae963299c9531fce18750fe64862f032a5a40f15343092b4c432eb231a4084")) + "29ae963299c9531fce18750fe64862f032a5a40f15343092b4c432eb231a4084" + ) + ) val tx5 = Transaction( - "0100000001932c744f53b90a6a4179c4ff98902674fc8b306b476d6e9380b2b370cd79378c010000008b483045022070058478ae92aa03b96f3fcf6498602aa08f14bf467ae306e91515602dd9ae3e022100e7b2946a281f68719f4eb4e46609e4c6f560d0f074dd3df49303fed645afccc3014104b85cded1eb71e8a4ee3b35beff0642d750e0cd9c656679b3b38b61bec3aa785649c742aaa771787a952096ce2b937db0370422ed3d6cfb649616d269b0ca6afaffffffff02008c7d0a000000001976a91439a17a80338f95445d123e8e9bde1ca805e06bfd88ac80be03ef000000001976a914c87ab952fd6e53493215394ec6aea2ae36ed193188ac00000000") + "0100000001932c744f53b90a6a4179c4ff98902674fc8b306b476d6e9380b2b370cd79378c010000008b483045022070058478ae92aa03b96f3fcf6498602aa08f14bf467ae306e91515602dd9ae3e022100e7b2946a281f68719f4eb4e46609e4c6f560d0f074dd3df49303fed645afccc3014104b85cded1eb71e8a4ee3b35beff0642d750e0cd9c656679b3b38b61bec3aa785649c742aaa771787a952096ce2b937db0370422ed3d6cfb649616d269b0ca6afaffffffff02008c7d0a000000001976a91439a17a80338f95445d123e8e9bde1ca805e06bfd88ac80be03ef000000001976a914c87ab952fd6e53493215394ec6aea2ae36ed193188ac00000000" + ) require( tx5.txId.hex == BytesUtil.flipEndianness( - "c55397fa43afe8a75adcf4f0f51a962cc550fa14952528c1dbb11e92bc4cd3fd")) + "c55397fa43afe8a75adcf4f0f51a962cc550fa14952528c1dbb11e92bc4cd3fd" + ) + ) val tx6 = Transaction( - "010000000193e57d0a24ff217fca2ea80192285b9e954f72d916b0f1417cb99638ad3becb0000000008b483045022100e8cb0654d721a3f5ca0bedfd6dce9077f5b827df7b43434f3b94c95d5b06d617022040c99a129fffcb4779b9dbc5d9d8804e10cdbed910d1d1d66c4ccefa74792ec4014104fb3d1c8a73dbc508def81d7cb139d5dd2206d0373d4c37a8c2c6fa02bfc5adf8128c68a776823cc0956e783b7465315237c4382364fb37337561e502c75ae1b4ffffffff020001970d000000001976a914a8772cf424b59eb26e8ab71c37266264ccd9893b88acf1beccc9000000001976a914926fd6a8d607e8be59b19e4f8b2d98a818841bf288ac00000000") + "010000000193e57d0a24ff217fca2ea80192285b9e954f72d916b0f1417cb99638ad3becb0000000008b483045022100e8cb0654d721a3f5ca0bedfd6dce9077f5b827df7b43434f3b94c95d5b06d617022040c99a129fffcb4779b9dbc5d9d8804e10cdbed910d1d1d66c4ccefa74792ec4014104fb3d1c8a73dbc508def81d7cb139d5dd2206d0373d4c37a8c2c6fa02bfc5adf8128c68a776823cc0956e783b7465315237c4382364fb37337561e502c75ae1b4ffffffff020001970d000000001976a914a8772cf424b59eb26e8ab71c37266264ccd9893b88acf1beccc9000000001976a914926fd6a8d607e8be59b19e4f8b2d98a818841bf288ac00000000" + ) require( tx6.txId.hex == BytesUtil.flipEndianness( - "28b8d356e236cc001a2d0e6a8468a290e2b7a8693c246c78c8a30dc0ba16016d")) + "28b8d356e236cc001a2d0e6a8468a290e2b7a8693c246c78c8a30dc0ba16016d" + ) + ) val tx7 = Transaction( - "0100000001c839d2518dde2a3916b4a0bc982a0d2f8b282ce010cf68fc2ff04bfc71a0bbb5010000008b483045022100f3c89528d32017e940ce5081214be1836baab972e0b13bfc486091766cce50020220530507644fa99695d6671fbd26605ea876e2afe73fa8413382348948ba20d60f014104602e552211f29dc5b9eee5b679fb08d21ba14154071d7d8cda23dbdd5c6c8e1656a88a0c2ac4786a4b58def140ea016675e31a09e87d355f18296b658de828ecffffffff02431cff3d000000001976a914d86754c15540fbb0f9d131b041581afe9cc65d6988ac4013b920000000001976a914fcff8f28c7f2dce1edf93e8795cd1d201e2a9c8688ac00000000") + "0100000001c839d2518dde2a3916b4a0bc982a0d2f8b282ce010cf68fc2ff04bfc71a0bbb5010000008b483045022100f3c89528d32017e940ce5081214be1836baab972e0b13bfc486091766cce50020220530507644fa99695d6671fbd26605ea876e2afe73fa8413382348948ba20d60f014104602e552211f29dc5b9eee5b679fb08d21ba14154071d7d8cda23dbdd5c6c8e1656a88a0c2ac4786a4b58def140ea016675e31a09e87d355f18296b658de828ecffffffff02431cff3d000000001976a914d86754c15540fbb0f9d131b041581afe9cc65d6988ac4013b920000000001976a914fcff8f28c7f2dce1edf93e8795cd1d201e2a9c8688ac00000000" + ) require( tx7.txId.hex == BytesUtil.flipEndianness( - "49d72c911b717a7e922ede3241a0bd4f6327dd14cd3a8cba2a11beea3e77238f")) + "49d72c911b717a7e922ede3241a0bd4f6327dd14cd3a8cba2a11beea3e77238f" + ) + ) val tx8 = Transaction( - "0100000001010114fdd45e7b99f6f5caea21645c2693d0609ba580937686ba21f3235978cb000000008a4730440220116bc3143a675d972a78c3d67aa44b58305ecd94bcba286d8275077772a895bd02206c6c8760ffba11147d98517bd4299db0b11b749cb0b2aa992aa9d03a2a41ba5a014104b515bf108c71b23aeae6b3b61fce7d4398e7c117463f2071aeb8f98923058e438c4e2c7a6dfdfcb6bdde622796aa2d78df16d044170802cf26b10938f3bdffe5ffffffff02403cf18a020000001976a914db8c008ab5e1d2cb9bf777eea76f29b7828c6c1388ac404b4c00000000001976a9140c19e5b68422628d748a995a943e751f53da8e9e88ac00000000") + "0100000001010114fdd45e7b99f6f5caea21645c2693d0609ba580937686ba21f3235978cb000000008a4730440220116bc3143a675d972a78c3d67aa44b58305ecd94bcba286d8275077772a895bd02206c6c8760ffba11147d98517bd4299db0b11b749cb0b2aa992aa9d03a2a41ba5a014104b515bf108c71b23aeae6b3b61fce7d4398e7c117463f2071aeb8f98923058e438c4e2c7a6dfdfcb6bdde622796aa2d78df16d044170802cf26b10938f3bdffe5ffffffff02403cf18a020000001976a914db8c008ab5e1d2cb9bf777eea76f29b7828c6c1388ac404b4c00000000001976a9140c19e5b68422628d748a995a943e751f53da8e9e88ac00000000" + ) require( tx8.txId.hex == BytesUtil.flipEndianness( - "cae533bd524a8c0ef25a09ed0608b0f1e6d2233e2128263c2a11400698334626")) + "cae533bd524a8c0ef25a09ed0608b0f1e6d2233e2128263c2a11400698334626" + ) + ) val tx9 = Transaction( - "010000000156c375d64acd0b2c0e5757046c426aa5569e2da805ee3d3b72a136ddbbe770af010000008b483045022037599894a6721378942104ab871c595262fcf61188408609606353129de844e3022100af4104a2695a7ac3c6534ffff54d328ea510a08f2ef331e68e44703a59e9d55c014104953bf42be63bb3b086716bcf04d234cd5a1548ef8dcab6a85277fb163cab71dc98860d807be53dc5aa6094f401508ebb9b60ebe40d898d058f0812f7b84f65f7ffffffff0280841e00000000001976a9149fb2b87cf1dcdd22de8036fa9c449a6b242bb16c88ac80841e00000000001976a914af501f804a4ad6177b77fb64f22e60e2534b0f4488ac00000000") + "010000000156c375d64acd0b2c0e5757046c426aa5569e2da805ee3d3b72a136ddbbe770af010000008b483045022037599894a6721378942104ab871c595262fcf61188408609606353129de844e3022100af4104a2695a7ac3c6534ffff54d328ea510a08f2ef331e68e44703a59e9d55c014104953bf42be63bb3b086716bcf04d234cd5a1548ef8dcab6a85277fb163cab71dc98860d807be53dc5aa6094f401508ebb9b60ebe40d898d058f0812f7b84f65f7ffffffff0280841e00000000001976a9149fb2b87cf1dcdd22de8036fa9c449a6b242bb16c88ac80841e00000000001976a914af501f804a4ad6177b77fb64f22e60e2534b0f4488ac00000000" + ) require( tx9.txId.hex == BytesUtil.flipEndianness( - "9798e1af941e9fc24bfb2af7ae6e00510c2546c95606d9452ac333252940fc79")) + "9798e1af941e9fc24bfb2af7ae6e00510c2546c95606d9452ac333252940fc79" + ) + ) val tx10 = Transaction( - "010000000409427b1f9d55d558f47fb865796ba455a18fb19d8afe7ac802c2df6bb9c4bdea000000008b483045022100d75a7fb24c3b94ed1be19922286ca62aa618291a09e840efcab5f7ac2d71e91f02204578e6c60e69b60179d45359cb29d26a3b8a8148fc658b0a9e1ab28bdf3939ad014104de68dcf94795f2ea428828430381594ad49126b36ffbaf055bfe7125b8d2abfe36bd3f82808f4317033396efdc3b64804f7820636de87f5229552eed8e40ada7ffffffff9e8357c7dec0c0f3c1ef86e79d454ceeefd4c25556b77b66c46e41f23d9f7470000000008a47304402202856dee4c597a9bb786e7a26099375ca3c937f84c9e465cf875ce20ee21710360220575fb1294cf901f35d636f81bfac37b3b285011359a109928227f72388f3d967014104045fbbbd37f38fcdc1d6ba91ec1270b2c4cae9ecafd6fbd7850729a68a1bbde6844e7430c4a7d2a397c1719abf0b66c94abef34381ed435521847cecd8c67b66ffffffff2b2e8b86a0a7d2c68686d95f69d741689502242e3d198257da3e56723ff4a8bd000000008b483045022100cdd5ddedd3204c5f4d8e3eb43e7b3831f60be40fbd989616314159f26e49754b022048aad835a7b11235b59e24fbe70b162d0f5fadf11e800e432b96e0c526c23d5301410426e046799b2fe0c88d8fe6a6edfb147843abead2cb6c0786fd6f1173946df50502708d2e01e24da7f4bc3f65bd0dd7101eece8dbd3e0adbc2be0e96bf52f7c5bffffffff690b213d81673522ade46cce250f446bb1dd9307911a088017d7a81d9b165a86000000008c493046022100d2d55c279bccf504bba239e75901bbeda5556d651ec7753a1ce43f2d74929e5f022100ee8134caac18f3862a5e3c048829dec9323b33bcd86235b115dc909984891db801410488da06bc75b9ea5539f54d5f22568c239a9c0845bf948f156e05096d4584a023bf0504b737f1de61fb4dcbfa58fed558ffed50322ff8578d4b9e3ce05905797effffffff01c0cf6a00000000001976a914ea2ba5d2ecaf296c163fa0eacb35b9d53d8e6aac88ac00000000") + "010000000409427b1f9d55d558f47fb865796ba455a18fb19d8afe7ac802c2df6bb9c4bdea000000008b483045022100d75a7fb24c3b94ed1be19922286ca62aa618291a09e840efcab5f7ac2d71e91f02204578e6c60e69b60179d45359cb29d26a3b8a8148fc658b0a9e1ab28bdf3939ad014104de68dcf94795f2ea428828430381594ad49126b36ffbaf055bfe7125b8d2abfe36bd3f82808f4317033396efdc3b64804f7820636de87f5229552eed8e40ada7ffffffff9e8357c7dec0c0f3c1ef86e79d454ceeefd4c25556b77b66c46e41f23d9f7470000000008a47304402202856dee4c597a9bb786e7a26099375ca3c937f84c9e465cf875ce20ee21710360220575fb1294cf901f35d636f81bfac37b3b285011359a109928227f72388f3d967014104045fbbbd37f38fcdc1d6ba91ec1270b2c4cae9ecafd6fbd7850729a68a1bbde6844e7430c4a7d2a397c1719abf0b66c94abef34381ed435521847cecd8c67b66ffffffff2b2e8b86a0a7d2c68686d95f69d741689502242e3d198257da3e56723ff4a8bd000000008b483045022100cdd5ddedd3204c5f4d8e3eb43e7b3831f60be40fbd989616314159f26e49754b022048aad835a7b11235b59e24fbe70b162d0f5fadf11e800e432b96e0c526c23d5301410426e046799b2fe0c88d8fe6a6edfb147843abead2cb6c0786fd6f1173946df50502708d2e01e24da7f4bc3f65bd0dd7101eece8dbd3e0adbc2be0e96bf52f7c5bffffffff690b213d81673522ade46cce250f446bb1dd9307911a088017d7a81d9b165a86000000008c493046022100d2d55c279bccf504bba239e75901bbeda5556d651ec7753a1ce43f2d74929e5f022100ee8134caac18f3862a5e3c048829dec9323b33bcd86235b115dc909984891db801410488da06bc75b9ea5539f54d5f22568c239a9c0845bf948f156e05096d4584a023bf0504b737f1de61fb4dcbfa58fed558ffed50322ff8578d4b9e3ce05905797effffffff01c0cf6a00000000001976a914ea2ba5d2ecaf296c163fa0eacb35b9d53d8e6aac88ac00000000" + ) require( tx10.txId.hex == BytesUtil.flipEndianness( - "f7a894ce552d9ecb0deb2d8bdd1ee22d5e641aa4c382685a41e9f28c5269a96e")) + "f7a894ce552d9ecb0deb2d8bdd1ee22d5e641aa4c382685a41e9f28c5269a96e" + ) + ) val transactions = Seq(coinbaseTx, tx1, tx2, tx3, tx4, tx5, tx6, tx7, tx8, tx9, tx10) Merkle.computeMerkleRoot(transactions).hex must be( BytesUtil.flipEndianness( - "2c8230dfb6c7ad0949cbdb7d3c3616cc10770db7e832bbf5c9b261388828c6c4")) + "2c8230dfb6c7ad0949cbdb7d3c3616cc10770db7e832bbf5c9b261388828c6c4" + ) + ) } it must "calculate the correct merkle root for wtxids in a block" in { - //from https://www.blocktrail.com/tBTC/block/00000000000002f59cc8b806b2cf6bbe37a367a085de60f9e5e3386081abbb48 + // from https://www.blocktrail.com/tBTC/block/00000000000002f59cc8b806b2cf6bbe37a367a085de60f9e5e3386081abbb48 val blockHex = "00000020e078e9b4bdaff2884ca4b4fcd1e00163c1b744e0b4934757b40500000000000022032fac2d2215dbc56eef51b303b5549de55b0a452bdb98eff828ce5a92d23062d05b58dfce061ac4149d6308010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2003e02e10130e6d696e65642062792062636f696e585bd0620000000006d50200ffffffff03cddf17000000000017a9146859969825bb2787f803a3d0eeb632998ce4f50187848c3b090000000017a9146859969825bb2787f803a3d0eeb632998ce4f501870000000000000000356a24aa21a9ed309cfb38d1015c266667d5b7888c83def872a531b8ac277fe8df623c32b562b50e6d696e65642062792062636f696e0120000000000000000000000000000000000000000000000000000000000000000000000000010000000744e9e8330945e6a42ca9ad027f02e4bacc120495edc029835c6818ddb08edfb200000000fdfd00004730440220025e60deb97943b4bd75d3fb944106072f37d264087a5406d966f1ab8c1c880402202f5243ce39f4bcf119a327de5a34cfa58ea4b9c091f6c096623a0af6e00da9c201483045022100f29fda6ed58a0650a7632a6ee560e7fb5dd6d920e137c1f3685b9564dbca6bdc0220702a7f5ffdf51efe306eaf6e03e6f23f04203e01278899e5e277072f44cb890d014c695221027816ead72a0425676d55ee701575fe75b5362660e8c3b10f6cad7d42c447b7e02103241ce445a4e25e8217be952bec66eea269a4b4e30f3e1bbe4ff43da1f2a43641210359e4817babe8b95f7b3de62479d26dddaa6eb999f8aa8147bcf67a741e0d77e453aeffffffff4b0d544609906638f2f97db62c7d716e6b205265bb034cfeebba2ccf1d497e7900000000fdfd0000473044022054db91af95a46d902d0f4a44c9d22c0bb929d637d498451f86706ee43385bc9d022077ce4389bd319a3fb6357a20400fe5d16e38f14338ddfef2ea26558c9d60c48b01483045022100e50b397b55aa511a8e4c307c9750cb98d23b92c36679d5084afa2cd14c34613d02201c3aac3904add0702cf0abd24f02f666adf5294932bc7b1b18aeb841a1b69304014c695221027816ead72a0425676d55ee701575fe75b5362660e8c3b10f6cad7d42c447b7e02103241ce445a4e25e8217be952bec66eea269a4b4e30f3e1bbe4ff43da1f2a43641210359e4817babe8b95f7b3de62479d26dddaa6eb999f8aa8147bcf67a741e0d77e453aeffffffffeeb8c5b17890de15f078739f80bdddb4516af8294a7131905bb05162934f62c300000000fdfd0000473044022028ad9bfdb65915e637539e968590bc13232a09b4fccbc7bae0520bc59e434bea02203aa718a076cf4af7012db466a041cc944817ff3def577b3ef6f47390be51d16801483045022100dac4f83402e8ac22ed380436f58b8f5fbee57f47c498692038710a06152cb88a02206ac0311ca9e5fafcd341ad185f2fed31081a7a06ad7093b9f7240fb56a30c583014c695221027816ead72a0425676d55ee701575fe75b5362660e8c3b10f6cad7d42c447b7e02103241ce445a4e25e8217be952bec66eea269a4b4e30f3e1bbe4ff43da1f2a43641210359e4817babe8b95f7b3de62479d26dddaa6eb999f8aa8147bcf67a741e0d77e453aefffffffffb6a758c394c9869f3b308aa86c24ebfa0f3aa83753dd54ff3a15e8d12a3eee600000000fdfe0000483045022100d9eaa2732899ae341cde49591450dc96e4dc6698c57dc5f60b406c84340c2d2c02202d16aa3232ce1eeb4b1c9a209b26388110e3a06c10daa8ee5fe6cf1390a1853001483045022100a445ec0db2f552ae54af1afb557c009be07ecb868416dad7a36ace2cfff8364a02205b18dc2841ca4a6e80d7a5454e1f66a05616e31245c98fb8c62cec550d881d6a014c695221027816ead72a0425676d55ee701575fe75b5362660e8c3b10f6cad7d42c447b7e02103241ce445a4e25e8217be952bec66eea269a4b4e30f3e1bbe4ff43da1f2a43641210359e4817babe8b95f7b3de62479d26dddaa6eb999f8aa8147bcf67a741e0d77e453aeffffffff8f3c4f0ac2a46a6f846c25886ece6c6a6e53166ebc6227201ecdb0cbf3a7930802000000fdfd0000473044022059eff6558b8d294b267aa231fed35d05a7448d0831f9caf83f21cb693eae5827022057e2eabcc46b4f7f204c7cd4fe81ba05cfec76d2fc95d4706756bdf0d765673801483045022100aefc168c82c32d4d70a99ff955becd69063be5e4e25559dd5df5e8edc200cc9b02202a46eb13288488141ed92748c7c84965a65f53bf1d8dca5796228b4f175b9b9d014c695221027816ead72a0425676d55ee701575fe75b5362660e8c3b10f6cad7d42c447b7e02103241ce445a4e25e8217be952bec66eea269a4b4e30f3e1bbe4ff43da1f2a43641210359e4817babe8b95f7b3de62479d26dddaa6eb999f8aa8147bcf67a741e0d77e453aeffffffff1bfef6e8450d8c0c4ece4267dceac0ed78a5fb550a46d8bbdfd40238682c4f8001000000fc0047304402207112c760219a819c37977fcd1f25b80051a65ee0d866f032447bb06a59f3176a02206cee9209ebdeb7f466483199d8483d8a734e061e0b9cc9ae9c40d2c76b640aee01473044022076f30b7dc28c8fb6c5e45ac0dfc308549bef36dd896dc3afcaa0909966f833df0220056e21e686a8f13950aa0d415247e6e5ec2a54d64c3ff8f58ae92511263d1afd014c695221020e0a7b420518e1c1e9fb0e7f49a7b1a41561a314d7181750ba157d0b4e4f5bd92102ce21b0ef5427005fb12fabd5f0c4af8bc0c6278380f8ffebbba13df6d5d59c2521037f2cbab534107b423b58d87065c9be4973f327ebb9879678d705693d1ed6260053aeffffffff3bfb021af2c7cbce706f60e3631088e5ca75c4d1deef4c89f4ef5f5551cd539900000000fdfd0000483045022100bcaac04b5f73958ab98905c96b70210f8b767a3e8fe50f8985155dac77a423a402207a8c190d53ebd2646224d2cfc00983aa4f50c807e57ee41fbe6fd971662d0bef0147304402200211a2576ecfc044ff901955838194b829cfaf7015ea8a9119062c4dce1c8ea202202522547086be48e8d05845158147b7e8ac621bff2e1c175534eae4b3d233ba37014c69522102251b9278b4f6b183ad91b36e9d5886ae0e00db52796a7b6a52c285e21d6bd05621024a15dc77d7de50408f826e0578c3860eefb976b184796176dda29d33c92a63ee210277c39cd27f697cd89442be427bb62d853cee716c94fce40b48d33cdd8487e4a553aeffffffff029f4ad2010000000017a914f1c10518b55a8a2a06645991051c3d5175b271ed87002f68590000000017a91425627123694fc0527bf9911e8c9747a0a6e5a113870000000001000000012c57d7340670360580e39d56d298bab34a749c6591e54125bc9f619d38f0653200000000fd5e01004830450221009358d377510748fc449445d2d80b07a4b16a618cef2beb4180705602fd9eecca02203e2d383c21009fe3809947cac90a6aee36286a16c2df42078c41fef327168fb501483045022100b5b6a1852f9fb6486c467d977a840a2260be6e4e07904d3db6aea3fe6abf951702205f049006d75da2f899572073e7b14b687ef80d85fdddf2e6f18e04256e31071f014cc95241048aa0d470b7a9328889c84ef0291ed30346986e22558e80c3ae06199391eae21308a00cdcfb34febc0ea9c80dfd16b01f26c7ec67593cb8ab474aca8fa1d7029d4104cf54956634c4d0bdaf00e6b1871c089b7a892d0fecc077f03b91e8d4d146861b0a4fdd237891a9819c878984d4b123f6fe92d9bbc05873a1bb4fe510145bf369410471843c33b2971e4944c73d4500abd6f61f7edf9ec919c408cbe12a6c9132d2cb8ebed8253322760d5ec6081165e0ab68900683de503f1544f03816d47fec699a53aeffffffff0205cb4c00000000001976a9146efcf883b4b6f9997be9a0600f6c095fe2bd2d9288acd02b0a000000000017a9145629021f7668d4ec310ac5e99701a6d6cf95eb8f87000000000100000001141eb7f92b0f6a93dbe03035bc70a5c2dc1b2438fe73995047f252ef8910b99100000000fdfd000047304402206c4e2835cb23950be6cae4ca3d67111e5e9361de24b416ff4e3adedfaf67013602202f51ca08da2a5338f01da2169f08f25b7efd45d24792f1af2c986172b38218db01483045022100931db2860985a9a61efc8e8ba4d2b7b884defa6350c3dbeed9f8940c0f0495fc02204b88001588bda2b9bed9e813032ad9efcc1f58b0459869c44fb597d921359a01014c6952210241400c20077f858aeb7116ae1306a78a22b10be01fd0a1d4de5ca56d6c161ea221030c33fb0ece93126f51192e6a451216d789afca4aa7378748d1a57a453fb0d1b82103281d2974cced3f577e5eab96ab4e109e426834844deebd886e843415e2722a6a53aeffffffff03d5d911000000000017a914522dbfded5f45dcabc745f130c1c008bec54efab87f79660000000000017a914535e192de149018bd257afcce7256867cb1812b987467500000000000017a914e6969c813bc83e72a581e92bb6911ff5a7eb9b4087000000000100000001315f2523f638b8bf63d8fd9e51b851439cdaf1426613d8dcb554366128f1bfeb00000000fdfd000047304402200151a8f1d21b4a3863ec064115f0dfa48dff8c15cd3bf79bfe82add864e80d0d0220578538a1e69848e48ab301fc62a29ee70941b2a7230b9eeb6b628e0f4ed193730148304502210097d0b01d61d02e5addb471e241b2dca4c8b54f03b309efc36381daa743e04e9e0220518f0e317390007cec89fdec9cd7f60ec3665ec4af8782aaffe129941832b386014c69522103c941da7e416afdf590996932cd0cb1a46a05a443cd518db04fba46838559d5bc2102e2b306e1006491c1aa493045d57f99e093432a148a2edf74e59bcea09f6cdc8c2102d67471eb93a3ff138910fe746fcbcf537a1cbe53c3d9b21edcfb3dd5cfac904153aeffffffff0240420f000000000017a914e4ca7a273e137f85772fe1c53e677cacd92c8fb08739e508000000000017a9147363603c47ed28acda272d1c1a7dd5ae462687c887000000000100000802edf609999a7182acdb830fb5debfca3c3efaf11dc4289d7c7163d16b62abda9c010000006a47304402200b1f6f234e045a826f5e833484da6ec094d6293c0416a5619198eb5374c630d80220466306c4cd2ec7af2680b9845acfe5c31c87c122b34b86fadcfd8962c9a8f078012102fd1c5947a2f3f8aeb4d2ed3bb2fe20feacd7f9cde6e0745d6ab9fe2b1c331128feffffffd81b1a058146d7ce5fcf26a419e6d15857f2406af200e5b4de0a8e3589f1facc000000006b483045022100c07e12ea39aaafdeca657975a1ffdd344b1686dab16fb40784a4ede95c79f4810220320bc054aff57816445c9e05bcb2f3368953c0599c6fd4fd4a4689efe7a6719b01210236890b20648db72415c4e70e3620df9e450a7cc71763da7ce242bbeb1918c22dfeffffff02402305060000000017a9148d6b4327cd87b0766c3139e4053b0ec454d427d287020d4600000000001976a91495565c185a7db3a184b8568dcd19c060b8a8ac1c88ac000000000100000001189082131dea65f9cfd882b89e34db8002db2f7581879d52b04edc04f56ee97e00000000fdfd0000483045022100fba8c9dd55023e0d7eff72082481d61364ddc505af5939a1d4b5d4ae788598ce022053c7ff590af7c1cfa49a00a49da127641f678be290eee90221d1aa073499ab5501473044022024d9b258121d84f30cad93359d371ca3201c3b2b2e49e903b8f9b761cc9e7ded02203801e56ccc6254b1fb8bf9627e27d330138f3120699584b471c36f5d10c08684014c69522103e21147eff3eb4bde79b3b8902c6b957d44b52779df8fc53f912855851ba3addc21022f1ab1d63f0f28a2de7a45f02eb8b86d09dec4319f8070e3df6515394c6da0cd2102c160ee65126efd4488a4b11c9f661fe7e8e0db1683c625b6f1a8b8751c32aac953aeffffffff0108831900000000001976a91460c150da07a41d938832028c1074e986bd3fd50a88ac00000000020000000001208590ad4d34999fb155d0298fd7a8863d7860a305e0310ca28dd64120f30165970a00000000ffffffff8f8db50351b687b890a87d8090ed5d8b143084b0b1f1a8e1ac8431733c7e50330a00000000ffffffff8f7a2b0fde1aaa085ba1faf7dc14f6b07a0bfa47dd2a423cababb9102fe75cf10700000000ffffffff8ed7a0bee4643d25d4cfb159fc5e93d6cf8bd9eae86778232361852fdeaa206d0500000000ffffffff8da0b5161ffeb1f8c6cfbf6efb4d737410dde17944eea0a01b7f30c89c0a4a140400000000ffffffff8c6c53156fe8651b63107b70022dce51dbb58cb64e0f255e0fa770e016fae56f0900000000ffffffff895fba29f123a3513bab3dbc3e95efd6ddb43c6b21eb224a23c74229d39de6110100000000ffffffff8818a95602f7e228dc7cceb07b57e13956b8747d6b8ef1ba607f2208654ca3030000000000ffffffff878a998708c3d3ac11f2d7d4ed5dc534cb5e2b614a6debd322af421485e810720a00000000ffffffff86d61ce44b5b559266636cc24805503deced13a58bdd8750b2fe2584fdefd47a0900000000ffffffff85d067a41bdab156bcf3fae9a44cc29398808d20f7400c1ffb44df463606fce20300000000ffffffffb7b9a8551b47da2844bed2c2464bf3a5292ad119bc59d9ae19b3d9365b6bc8d80400000000ffffffff835377eb8bc94a4d1125daa11695ebf0bb461f764d622a2a06ed1fae9df3d8970200000000ffffffffd5739b854860ceb661cd562ab38ed236aba7627329d733c9abc8dccb8ff4917b0000000000ffffffffd8e0d6ca747cfc6fe170ec4641c8e255a54ac1d00bd7575bc387f1716498de4d0600000000ffffffffc9ac6665cf8603cbc748304e9dff2d84060928b5387a46533e6fccc372d304070000000000ffffffffdfaef7bfbff3d3dc98328586b2c1dff8cba5414536da232dbd6def50546968370200000000ffffffffe339b6d2073b59f4f69aa9dea7476192992185a00d1098d02e9d26510e285aee0200000000ffffffff3aa1039596c676c0d87c2eb02252ccbd9d04292196620170327177bb3024ab9f0900000000ffffffff386cffaf50f7a14af6a2c3b4847010d40e7b0470f2260d22967950145a4cebe10600000000ffffffff1e213b3970a40ee24fa83221e1b7226734d6cd34287f5b411f8de041fbddfd200300000000fffffffff7b21151a5691e943c729912177f4052799e4695abf64e8e8d951231600c3a0b0800000000ffffffff1ab17fe7c58284a8316282c39ab4407a2b3c6cc64a20527f38eacf36fff98bf70a00000000ffffffff0edbc655c8d8cb957f69c5d2fd76a82bf0ac9e5d616c1ef0aa7f0bf5ce9c8d130600000000ffffffff9252c0210242287887e595c86b4cafc758f127bfe05a3d84056e69520cd0fbae0300000000ffffffffcf2b8c3a1bae5146a78b2a4393887fce27f8ecc09f1d784bf12940b3dd0cadc10200000000ffffffffc7d5530cd99be515669d35f64780ea0d6c2792a753321fd739c7524c640cf3700400000000ffffffffa4cf89fb85240885fd2a678d8fdbb138da8af9644f550cf6394b93dbdbf6b8ed0900000000ffffffffc430c6fe1e7734ba7ca9f118298e18de49f21ac205ad880263fce1a4fd097c0d0300000000ffffffffbbe3260b0bfa9b77f135ef2e38f733ada3d144a61e352887a252456ffe41e93d0100000000ffffffff54ef8de7df0b1b9d47af5304ac9f06bc5306ff4fb5c5dc92a04eba90cb2b0b430800000000ffffffffdd181c6bab253dfb922f76b4f24f61cb888291306b3bec51d74ca549de5ab2270400000000ffffffff0ba086010000000000160014f6ca4512a80cd5725e9c2413f4f190045b17bb6fa086010000000000160014c91aa69c4c93a08663ac9e9c42f3c858f731fc38a0860100000000001600140d7a140fc64fee3e2f4f6b4415f5c88e3872acb5a08601000000000016001442c2bd8dd82e14e417ebb9629ae25ec8ce5394f3e02e0000000000001600144101fbd871348e8039f8fe9f99655f07970b2db7a08601000000000016001476ded826319baeef92d6ec0f2829330d31d7c961a08601000000000016001481a3ae5ba2ece8708560fc775d94f68cd658d339a086010000000000160014643ddc2f43dc1866d10b7808c6c99f8fe0e2a6e0a086010000000000160014f94e8618d0acfa64b885a43497d89a7c47a5471ea08601000000000016001496bc607c647c61e9e8e38c8aadd1b6bb500df2ffa0860100000000001600142deb9b8e82d9adbe19b9ae7a8db81c11b95670ff024730440220280303dcc94ee6c5718309ddc5eeafa6994bc3e62e9d3f561d55332e6a6a81ce02202e250e81897467318e0efec45f963a0b7f64828f42dd279553f1ec51021191580121038ba1984243f46c975861d5758e7b2a4b20d334b32b896bb030e8c12972a351a30247304402203b399a0472a72a456505175d4b46a5a6d1e4bf64f18cd6eaa680b7529e4283ea0220108f01af21c1ea46255a33d03229b1a09b2beb496d5c9fa9a1c8ed5ef4ccf397012102dceeafbe426f6468580a42f307bcbf5a7791dffcac07e081ef12261f479cc85a0247304402203d2977af2f65aec78c34c7f810457969e5fbf96abfbdf6c628119b5f3ea39bfa02201aadb1373ba6008388ccb9938777d199cd3b10f6703b941d9745c1a6199ec997012102c7a11ba39740b802a431400eb5977d88c3153c319c0ac60c459fb06c77d03dd002483045022100e901939e715af67960be480986be22ba77cb18eb6fb894cd1a612e9df2a796160220052e195153aa605a62c9293b8aeefbc3082eb81f4cc86b4df240ac8e9912f5cd012103840fab41997e6b51b3d712fc92433e68be14423767615d653745d1403a33cc350248304502210094152c9404efbe6c340e755877356925d84713491ade8f99f50d028e1235708e02206743bcb916c337c82a0c9dacf31702b2d2f71d24c78d0768cd313af064be902b012102dd50e6d81b2b20ff248a44ff1b12b21791803898c7c1e7450ad661df1f246ded02483045022100e2b784903324e89d13cfde5c19a155ff4293d5fd4306cd5721a738d48755b0ae0220364f95a0a306270670c5f0da3deb47ca45ce6f3bd93c678b8b1e4a7eed31a1f5012102d1a9ff47f1808925f4dc8de8677c94fe79180c5863bbfe42410e2e008223e51f02483045022100d31e71ffabaf9246f7e3710e5da27a5b4cf796e408f9a848108933e9450de8a702203369398db7b734ebe9329d3ce3f31c310c8c01fae191878794d5d7594494c663012102b784de5a8e8a3cb77b6809572db28c8657b35a9b5db501c6967a8a6670cdb1c902473044022025edacca4542f87e44e21c1f1d66a844d40603b52b92856af47ef4717599275d022033fea883ee454c68c0b51a8b26cae4b1e9c546c202172ce22df3f009c47f6c54012102121c784428220b388ba20f04be6d913007756ba7992da16ada0477ae6ea5e13802473044022033aeff99cfb661d20f21a7f6cc5f62a7505a2754b2a59e4f17431da6bdb032600220733aa87a3e455e4a4509c8a18a455ccea262beb19088bfc620b75c95c9f3413c0121025e3a2ab59c6f4c6a49f20b7c950cba93d198e588d07112b566cb9eba0f7fe727024730440220259605a5ff50120288417a97853697dd3d1b6b8c79f7d8fd10aebb777399fbb50220350c027ef1e1df4a5e953a6bf88bbf09bb16a32adc187b08999cf0d124e6fb700121025e385cda40960bb1317f2e45b3c4498df7b255be2ffd233772aa2f9cd09242910247304402205782266dccddac241b23d1da239f22149af6313a597b29c01af5c45d9f4f282202205b5dc1ebd988cff630c39aeaddae2d528be78bd15656eb5fb97367712ef332f501210281fe98dc08655e5cfb4d1d12369633876b25b730ee9734b47953471ce1ad589d02473044022019b9749d36b75aae138caa2d0727bb8097831ccff7382b781e30ae82d457ab2f02206407f441c50a2c21dfad8ae964d438f8b4eaacf21a4ab97ee7a1b5052b0c63c30121034527df91a4760d839e83f4d3e3d82ca0e3f507ebc966395d915e5ea7fcd66f7502483045022100db03d616125c5be22d790a421df864ee9d3cb96020090da6daf1ed52a281c93e0220625c0ea02e8a3165512a30122366ce5b116a7e2a5f36f39e0b89b312706faec40121025245aba80e09d564a52c81bb2a0eea46f0fed28fd218471899a5b743950de0e4024730440220611b47026be06cfecf92fcef2a7f1372c104ab76b0b0e50c21b3e2904e30450c02202337a0c0b9ca029fdbfb355264864d31ca5d4860fb95ac3302633bd2494b6c5c0121033e3f5dbfd639ea9b6ce1bebeaa6a018afa927b6728ec44fe31fb78d9cbb1a8c202483045022100ab5b875896d3e8217c281d7ffd3de1b0ca2a6aa0af497b62b5c650df0b49d0cb02205ec8d6a7deaedfbef245b1bc88563de3afdaf4f5c18c1478e85169a4058502dc012102e18566f635adbe17df56d510e6e20429ff7190dd060dd8fc361b735fa9b927bc02483045022100a43c4ccc186b727c376f2a40b97f9732da2317d789a43fc8d815ec2c0cde3f2802201787a86835e4639e83d763303b3111a3bc501f08a18d5b3d18f4a94f9f02270901210274d158e3afcfa28a7ffbcbb9ebc3f10e2dd1635a6722d4a15bac7ed2a9117cac0247304402205bcd9b50df0c4123e7d8849780f32f800cb9a0adab2267002cebea89a641861a02207878ae5cfa3560db734fb8df4107702f159591c01920d7404d50fe6671744ba201210284f5841042b2a50d9dcc8da37bbccb98d276554f8ba8b8401d0eff28ff2b295f0247304402204401abfe05e08149447d79f50bbd141279da2e245f95a3bee5585551fcf4b4d302203680409f918afd5fb6fe8127c60b248ffa6956fe87c74f9f1029669222546fa901210249214a0802b34125c9ea4f781b638b513f29756019f7aac4367ce8e2ee57123c02483045022100e7a6a07e6c6e5b264919f048e061289ccc69f2d2e4c035cfaafcafce76b570160220487cc75548324e5ac60d1703331f42e62d52ebc6ca63b45c85d80c743ae1963a012103d189bc156024d790cb0c901584080f25a6ba83a78d235a8bbf42e7ea985dea26024730440220661deee47c39e9681ce0522cb416605fb4d207c8f91d0b027f448b38bab7b0b8022045e49edfb941b0b1ef4b7e8409b32e80dcad01aaba5e8e4f3844a8a9a0d7da1701210260bfe728fb63c291e857823685e08c41cd30bde103f48bc15c2ece93441f45d0024830450221008f891b5f4674944a57fc6afeba3b400b97dfde0f513da860a0f4d33d5a1b7af702206eabcbe27d588dea77d97db3e06ec94c1ce159baf1b17459c6b30d69b700b81b012103e2303347057593f18f265327b0cf8f999909b9257f0da80d00b522a92961f84f02473044022068210ad1e3f5689a885bbd68e6f01b8c77ea6a65d784c1edaca71c3f731e77aa02203c67eedadff821dfcb9453ffb6cfc3c1a4488f781e09dcffff6833ef1461f212012103a34801ee6ee15c48cbc44daa9f279c50e842f8e3cda3f7937023b01486a17edc0247304402206172b3c35eab825ab127405b7fc6159dcfc3b0baa2f13211e044bdb61244aa9702202938f73cb84f341c0e3eaadb0ea636c94d4dda94c7269cc31170e133f6075a9d01210396b2424b7ff151e3e93308f16c67ca837acfd0dcd5d7a38babd6e616954d835602473044022019b3dbacb067b31ee52631abbc700c7dbf03318cbd6b5868e9ab2b899ba7bcd3022000aeb09b4fa596c37cd0b868af0c9425c32c6947dc0e30ce0ff14bc85a874f2b012103ccf40e0b41d1dad4a65e9cf99e5534a4585498fe8acbbf543debb6109cc40db90247304402206f38e38345c65a6b97d1f0bf53ed1449095e82045a5718e699e2b6fc1da969df0220689313f4e0489f0861c64d8f21bccfd3beba5a616d2aeb8c6cc8dd1af1f08638012102f5cc06357dfd7dbb9ad189620f5fb79b822697196ee532112eb622b202c051220248304502210099444a9aa21dda04625164ae158f019e0e0b7b02cf3c919ede2b5e495641d3b002206f8d02d546e92243a9b50dc67bf1de1ea09906553fcfd8c43b9663021bd6304f012103d2684f4fcc5c66913d1dc0c546b20c5bc99c120b5e5de28f8b734cef9bf7258a0247304402206560e7e66e474b8bfbfcc1f99881a9e5f720b1bdaf7763a30e05baea7636ca6f02206ddd0902e2372fd38a79a91d85e76c01c1e4c1a6c2c478e4453ad86fd365da7e01210321a1d1be4979f8dbacc2a02da4c40c987493adbd7f58f468afe58f64fe60806902483045022100a8e4d728d05691cdd18d073827d0dcac9530c0bde4ce62875cf7768035548e1402200c12e5dd2dde4a64bf6ea95de064fdb8d7ec7b7a6a8d78aae2875c451525ef22012103c7fdaac564e79a423ec97b4f68bd26ec0abecc2f7f6e55b56f0255c5d669019b0247304402201df120353a1de458a347598fc9ac085e44728b857a9a1a6189d8ff2f0f4c99fb02205007a9ea641369beba820e81ff715121535ec5a162579c6bbd0d777f92bb7aea012103f75cd6fe58ede50090acff9f26371ad25ca9e427f74bcf7ad9b47bcf6e77c64e0247304402207bd286743786144feaefbe4d71aeb102ac0b4a56c6a744b5bded4bcdd363ebd302200cebd3fcd34f567418f67f91709fcfab45c5db215e3ba2267f42e4b568c1d74b01210228caaef805404152113f177d1755e15b6b40011aa929b75153db7acc372b289f0247304402200816855663b2a9c74d2760c4b3f4dc0b60016b27f1b71d58dc31336fb88c30830220457225e83b5f9e12813a309b095ce8fc9fc0101d424c0fbc1c8045b7c40937060121022098f135d6af58789e929fb474086de7c7f1ba3b452d4d59bdd163ad5e4cb18a02483045022100b8b9fc8317fd5c7245bc9f086e6993466c3f982d08305fbeb80418a0a01f61d8022033b3172f7bb63eb3c4d7173f620c4d7611b1033c9374ba8d1ebf2be8778f3f840121027120a3863d49b20e8ab2e416d1ed0e2421fc78aa75dc207c3d66a67215c0c3a500000000" val block = Block(blockHex) val coinbase = block.transactions.head.asInstanceOf[WitnessTransaction] val witnessReservedValue = coinbase.witness.witnesses.head val expectedWitnessCommitment = DoubleSha256Digest( - "309cfb38d1015c266667d5b7888c83def872a531b8ac277fe8df623c32b562b5") + "309cfb38d1015c266667d5b7888c83def872a531b8ac277fe8df623c32b562b5" + ) val witnessMerkleRoot = Merkle.computeBlockWitnessMerkleRoot(block) val actualWitnessCommitment = CryptoUtil.doubleSHA256( - witnessMerkleRoot.bytes ++ witnessReservedValue.stack.head) + witnessMerkleRoot.bytes ++ witnessReservedValue.stack.head + ) actualWitnessCommitment must be(expectedWitnessCommitment) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/ExtKeySpec.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/ExtKeySpec.scala index 1ea674d1da..a4fb226f65 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/ExtKeySpec.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/ExtKeySpec.scala @@ -23,12 +23,14 @@ class ExtKeySpec extends BitcoinSUnitTest { } it must "have derivation identity 1" in { - Prop.forAllNoShrink(CryptoGenerators.extPrivateKey, - nonHardened, - nonHardened, - nonHardened) { (m, a, b, c) => - //https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#the-key-tree - //N(m/a/b/c) = N(m/a/b)/c = N(m/a)/b/c = N(m)/a/b/c = M/a/b/c + Prop.forAllNoShrink( + CryptoGenerators.extPrivateKey, + nonHardened, + nonHardened, + nonHardened + ) { (m, a, b, c) => + // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#the-key-tree + // N(m/a/b/c) = N(m/a/b)/c = N(m/a)/b/c = N(m)/a/b/c = M/a/b/c val path1 = m .deriveChildPrivKey(a) .deriveChildPrivKey(b) @@ -59,12 +61,14 @@ class ExtKeySpec extends BitcoinSUnitTest { } it must "derivation identity 2" in { - Prop.forAllNoShrink(CryptoGenerators.extPrivateKey, - hardened, - nonHardened, - nonHardened) { (m, aH, b, c) => - //https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#the-key-tree - //N(m/aH/b/c) = N(m/aH/b)/c = N(m/aH)/b/c + Prop.forAllNoShrink( + CryptoGenerators.extPrivateKey, + hardened, + nonHardened, + nonHardened + ) { (m, aH, b, c) => + // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#the-key-tree + // N(m/aH/b/c) = N(m/aH/b)/c = N(m/aH)/b/c val path1 = m .deriveChildPrivKey(aH) .deriveChildPrivKey(b) diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/ExtKeyTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/ExtKeyTest.scala index 8b896afb9d..1f68d08219 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/ExtKeyTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/ExtKeyTest.scala @@ -89,16 +89,18 @@ class ExtKeyTest extends BitcoinSUnitTest { assertThrows[IllegalArgumentException](hardened.deriveChildPrivKey(0)) assertThrows[IllegalArgumentException]( - hardened.deriveChildPrivKey(UInt32.one)) + hardened.deriveChildPrivKey(UInt32.one) + ) assertThrows[IllegalArgumentException]( - hardened.deriveChildPrivKey(path)) + hardened.deriveChildPrivKey(path) + ) } } - //https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vectors + // https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vectors it must "pass the test vectors in BIP32" in { - //master key + // master key val seedBytes = hex"000102030405060708090a0b0c0d0e0f" val path = BIP32Path.empty @@ -106,58 +108,70 @@ class ExtKeyTest extends BitcoinSUnitTest { val masterPriv = ExtPrivateKey(LegacyMainNetPriv, Some(seedBytes), path) masterPriv.toStringSensitive must be( - "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi") + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" + ) - //master public key + // master public key val masterPub = masterPriv.extPublicKey masterPub.toString must be( - "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8") + "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" + ) - //derive child + // derive child val m0hPath = BIP32Path.fromString("m/0'") val m0h = masterPriv.deriveChildPrivKey(m0hPath) m0h.toStringSensitive must be( - "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7") + "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7" + ) val m0hPub = m0h.extPublicKey m0hPub.toString must be( - "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw") + "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw" + ) val m0h1Path = BIP32Path.fromString("m/0'/1") val m0h1 = masterPriv.deriveChildPrivKey(m0h1Path) m0h1.toStringSensitive must be( - "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs") + "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs" + ) val m0h1Pub = m0h1.extPublicKey m0h1Pub.toString must be( - "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ") + "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ" + ) val m0h1P2hath = BIP32Path.fromString("m/0'/1/2'") val m0h12h = masterPriv.deriveChildPrivKey(m0h1P2hath) m0h12h.toStringSensitive must be( - "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM") + "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM" + ) val m0h12hPub = m0h12h.extPublicKey m0h12hPub.toString must be( - "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5") + "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5" + ) val m0h12h2Path = BIP32Path.fromString("m/0'/1/2'/2") val m0h12h2 = masterPriv.deriveChildPrivKey(m0h12h2Path) m0h12h2.toStringSensitive must be( - "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334") + "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334" + ) val m0h12h2Pub = m0h12h2.extPublicKey m0h12h2Pub.toString must be( - "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV") + "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV" + ) val m0h12h21000000000Path = BIP32Path.fromString("m/0'/1/2'/2/1000000000") val m0h12h21000000000 = masterPriv.deriveChildPrivKey(m0h12h21000000000Path) m0h12h21000000000.toStringSensitive must be( - "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76") + "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76" + ) val m0h12h21000000000Pub = m0h12h21000000000.extPublicKey m0h12h21000000000Pub.toString must be( - "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy") + "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" + ) } it must "pass test vector 2 in BIP32" in { @@ -167,61 +181,73 @@ class ExtKeyTest extends BitcoinSUnitTest { val masterPriv = ExtPrivateKey(LegacyMainNetPriv, Some(seedBytes), BIP32Path.empty) masterPriv.toStringSensitive must be( - "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U") + "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U" + ) val masterPub = masterPriv.extPublicKey masterPub.toString must be( - "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB") + "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB" + ) val m0Path = BIP32Path.fromString("m/0") val m0 = masterPriv.deriveChildPrivKey(m0Path) m0.toStringSensitive must be( - "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt") + "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt" + ) val m0Pub = m0.extPublicKey m0Pub.toString must be( - "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH") + "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH" + ) val m02147483647hPath = BIP32Path.fromString("m/0/2147483647'") val m02147483647h = masterPriv.deriveChildPrivKey(m02147483647hPath) m02147483647h.toStringSensitive must be( - "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9") + "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9" + ) val m02147483647hPub = m02147483647h.extPublicKey m02147483647hPub.toString must be( - "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a") + "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a" + ) val m02147483647h1Path = BIP32Path.fromString("m/0/2147483647'/1") val m02147483647h1 = masterPriv.deriveChildPrivKey(m02147483647h1Path) m02147483647h1.toStringSensitive must be( - "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef") + "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef" + ) val m02147483647h1Pub = m02147483647h1.extPublicKey m02147483647h1Pub.toString must be( - "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon") + "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon" + ) val m02147483647h12147483646hPath = BIP32Path.fromString("m/0/2147483647'/1/2147483646'") val m02147483647h12147483646h = masterPriv.deriveChildPrivKey(m02147483647h12147483646hPath) m02147483647h12147483646h.toStringSensitive must be( - "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc") + "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc" + ) val m02147483647h12147483646hPub = m02147483647h12147483646h.extPublicKey m02147483647h12147483646hPub.toString must be( - "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL") + "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL" + ) val m02147483647h12147483646h2Path = BIP32Path.fromString("m/0/2147483647'/1/2147483646'/2") val m02147483647h12147483646h2 = masterPriv.deriveChildPrivKey(m02147483647h12147483646h2Path) m02147483647h12147483646h2.toStringSensitive must be( - "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j") + "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j" + ) val m02147483647h12147483646h2Pub = m02147483647h12147483646h2.extPublicKey m02147483647h12147483646h2Pub.toString must be( - "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt") + "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt" + ) } it must "pass test vector 3 in BIP32" in { @@ -231,19 +257,23 @@ class ExtKeyTest extends BitcoinSUnitTest { val masterPrivKey = ExtPrivateKey(LegacyMainNetPriv, Some(seedBytes), BIP32Path.empty) masterPrivKey.toStringSensitive must be( - "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6") + "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6" + ) val masterPubKey = masterPrivKey.extPublicKey masterPubKey.toString must be( - "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13") + "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13" + ) val m0h = masterPrivKey.deriveChildPrivKey(BIP32Path.fromString("m/0'")) m0h.toStringSensitive must be( - "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L") + "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L" + ) val m0hPub = m0h.extPublicKey m0hPub.toString must be( - "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y") + "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y" + ) } it must "pass test vector 4 in BIP32" in { @@ -253,28 +283,34 @@ class ExtKeyTest extends BitcoinSUnitTest { val masterPrivKey = ExtPrivateKey(LegacyMainNetPriv, Some(seedBytes), BIP32Path.empty) masterPrivKey.toStringSensitive must be( - "xprv9s21ZrQH143K48vGoLGRPxgo2JNkJ3J3fqkirQC2zVdk5Dgd5w14S7fRDyHH4dWNHUgkvsvNDCkvAwcSHNAQwhwgNMgZhLtQC63zxwhQmRv") + "xprv9s21ZrQH143K48vGoLGRPxgo2JNkJ3J3fqkirQC2zVdk5Dgd5w14S7fRDyHH4dWNHUgkvsvNDCkvAwcSHNAQwhwgNMgZhLtQC63zxwhQmRv" + ) val masterPubKey = masterPrivKey.extPublicKey masterPubKey.toString must be( - "xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuyu5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa") + "xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuyu5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa" + ) val m0h = masterPrivKey.deriveChildPrivKey(BIP32Path.fromString("m/0'")) m0h.toStringSensitive must be( - "xprv9vB7xEWwNp9kh1wQRfCCQMnZUEG21LpbR9NPCNN1dwhiZkjjeGRnaALmPXCX7SgjFTiCTT6bXes17boXtjq3xLpcDjzEuGLQBM5ohqkao9G") + "xprv9vB7xEWwNp9kh1wQRfCCQMnZUEG21LpbR9NPCNN1dwhiZkjjeGRnaALmPXCX7SgjFTiCTT6bXes17boXtjq3xLpcDjzEuGLQBM5ohqkao9G" + ) val m0hPub = m0h.extPublicKey m0hPub.toString must be( - "xpub69AUMk3qDBi3uW1sXgjCmVjJ2G6WQoYSnNHyzkmdCHEhSZ4tBok37xfFEqHd2AddP56Tqp4o56AePAgCjYdvpW2PU2jbUPFKsav5ut6Ch1m") + "xpub69AUMk3qDBi3uW1sXgjCmVjJ2G6WQoYSnNHyzkmdCHEhSZ4tBok37xfFEqHd2AddP56Tqp4o56AePAgCjYdvpW2PU2jbUPFKsav5ut6Ch1m" + ) val m0h1h = masterPrivKey.deriveChildPrivKey(BIP32Path.fromString("m/0'/1'")) m0h1h.toStringSensitive must be( - "xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJeHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1") + "xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJeHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1" + ) val m0h1hPub = m0h1h.extPublicKey m0h1hPub.toString must be( - "xpub6BJA1jSqiukeaesWfxe6sNK9CCGaujFFSJLomWHprUL9DePQ4JDkM5d88n49sMGJxrhpjazuXYWdMf17C9T5XnxkopaeS7jGk1GyyVziaMt") + "xpub6BJA1jSqiukeaesWfxe6sNK9CCGaujFFSJLomWHprUL9DePQ4JDkM5d88n49sMGJxrhpjazuXYWdMf17C9T5XnxkopaeS7jGk1GyyVziaMt" + ) } it must "pass test vector 5 in BIP32" in { @@ -282,118 +318,150 @@ class ExtKeyTest extends BitcoinSUnitTest { assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5fTtTQBm") - .key) + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5fTtTQBm" + ) + .key + ) // prvkey version / pubkey mismatch assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGTQQD3dC4H2D5GBj7vWvSQaaBv5cxi9gafk7NF3pnBju6dwKvH") - .key) + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGTQQD3dC4H2D5GBj7vWvSQaaBv5cxi9gafk7NF3pnBju6dwKvH" + ) + .key + ) // invalid pubkey prefix 04 assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Txnt3siSujt9RCVYsx4qHZGc62TG4McvMGcAUjeuwZdduYEvFn") - .key) + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Txnt3siSujt9RCVYsx4qHZGc62TG4McvMGcAUjeuwZdduYEvFn" + ) + .key + ) // invalid prvkey prefix 04 assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGpWnsj83BHtEy5Zt8CcDr1UiRXuWCmTQLxEK9vbz5gPstX92JQ") - .key) + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGpWnsj83BHtEy5Zt8CcDr1UiRXuWCmTQLxEK9vbz5gPstX92JQ" + ) + .key + ) // invalid pubkey prefix 01 assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6N8ZMMXctdiCjxTNq964yKkwrkBJJwpzZS4HS2fxvyYUA4q2Xe4") - .key) + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6N8ZMMXctdiCjxTNq964yKkwrkBJJwpzZS4HS2fxvyYUA4q2Xe4" + ) + .key + ) // invalid prvkey prefix 01 assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fEQ3Qen6J") - .key) + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fEQ3Qen6J" + ) + .key + ) // zero depth with non-zero parent fingerprint assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv") - .key) + "xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv" + ) + .key + ) // zero depth with non-zero parent fingerprint assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ") - .key) + "xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ" + ) + .key + ) // zero depth with non-zero index assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN") - .key) + "xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN" + ) + .key + ) // zero depth with non-zero index assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8") - .key) + "xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8" + ) + .key + ) // unknown extended key version assertThrows[IllegalArgumentException]( ExtKey .fromString( - "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHGMQzT7ayAmfo4z3gY5KfbrZWZ6St24UVf2Qgo6oujFktLHdHY4") - .key) + "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHGMQzT7ayAmfo4z3gY5KfbrZWZ6St24UVf2Qgo6oujFktLHdHY4" + ) + .key + ) // unknown extended key version assertThrows[IllegalArgumentException]( ExtKey .fromString( - "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHPmHJiEDXkTiJTVV9rHEBUem2mwVbbNfvT2MTcAqj3nesx8uBf9") - .key) + "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHPmHJiEDXkTiJTVV9rHEBUem2mwVbbNfvT2MTcAqj3nesx8uBf9" + ) + .key + ) // private key 0 not in 1..n-1 assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx") - .key) + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx" + ) + .key + ) // private key n not in 1..n-1 assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD5SDKr24z3aiUvKr9bJpdrcLg1y3G") - .key) + "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD5SDKr24z3aiUvKr9bJpdrcLg1y3G" + ) + .key + ) // invalid pubkey 020000000000000000000000000000000000000000000000000000000000000007 assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Q5JXayek4PRsn35jii4veMimro1xefsM58PgBMrvdYre8QyULY") - .key) + "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Q5JXayek4PRsn35jii4veMimro1xefsM58PgBMrvdYre8QyULY" + ) + .key + ) // invalid checksum assertThrows[IllegalArgumentException]( ExtKey .fromString( - "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHL") - .key) + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHL" + ) + .key + ) } it must "have derivation symmetry with (1<<31)-1, last i before hardened keys" in { - //xprv9s21ZrQH143K4QWHDnxmxUbzAQYiDavkg14kQcmZjP2KaSB1PZs5BUsyNGSrWXTzZ9qwyJo5yzvDe3fWybykc8CQPDZMaKupTeVbkfG7osL - //actual priv key 68e5ed2b2c8fc5a6605107d29d074e3d6ccb119c2811007e32f48305176f814c + // xprv9s21ZrQH143K4QWHDnxmxUbzAQYiDavkg14kQcmZjP2KaSB1PZs5BUsyNGSrWXTzZ9qwyJo5yzvDe3fWybykc8CQPDZMaKupTeVbkfG7osL + // actual priv key 68e5ed2b2c8fc5a6605107d29d074e3d6ccb119c2811007e32f48305176f814c val str = "xprv9s21ZrQH143K4LCRq4tUZUt3fiTNZr6QTiep3HGzMxtSwfxKAhBmNJJnsmoyWuYZCPC4DNsiVwToHJbxZtq4iEkozBhMzWNTiCH4tzJNjPi" val masterPriv = ExtPrivateKey.fromString(str) diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/ExtSignTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/ExtSignTest.scala index de4f44af73..017986215d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/ExtSignTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/ExtSignTest.scala @@ -14,9 +14,11 @@ class ExtSignTest extends BitcoinSUnitTest { } it must "be able to sign a specific path of a ext key" in { - forAll(CryptoGenerators.extPrivateKey, - CryptoGenerators.sha256Digest, - HDGenerators.bip32Path) { case (extPrivKey, hash, path) => + forAll( + CryptoGenerators.extPrivateKey, + CryptoGenerators.sha256Digest, + HDGenerators.bip32Path + ) { case (extPrivKey, hash, path) => val sig = extPrivKey.deriveAndSign(hash.bytes, path) val childPubKey = extPrivKey.deriveChildPubKey(path).get assert(childPubKey.key.verify(hash, sig)) diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/MnemonicCodeTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/MnemonicCodeTest.scala index 6a9d9e136e..33b6939f4f 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/MnemonicCodeTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/MnemonicCodeTest.scala @@ -94,7 +94,8 @@ class MnemonicCodeTest extends BitcoinSUnitTest { val attempt = Try { MnemonicCode.fromEntropy( // to provide a bitvector of bad length, but correct entropy multiple - e.take(MnemonicCode.ENTROPY_MULTIPLE)) + e.take(MnemonicCode.ENTROPY_MULTIPLE) + ) } assert(attempt.isFailure) val exc = attempt @@ -126,21 +127,23 @@ class MnemonicCodeTest extends BitcoinSUnitTest { } it must "fail on a seed phrase with bad checksum" in { - val correctSeed = Vector("phone", - "dilemma", - "early", - "never", - "test", - "surge", - "ecology", - "rail", - "medal", - "benefit", - "mystery", - "toward", - "lounge", - "candy", - "syrup") + val correctSeed = Vector( + "phone", + "dilemma", + "early", + "never", + "test", + "surge", + "ecology", + "rail", + "medal", + "benefit", + "mystery", + "toward", + "lounge", + "candy", + "syrup" + ) val newLastWord = "satoshi" val fromWordsT = Try { @@ -184,13 +187,15 @@ class MnemonicCodeTest extends BitcoinSUnitTest { entropy: String, words: String, seed: String, - xpriv: String) + xpriv: String + ) private case class TrezorTestVector( entropy: ByteVector, expectedWords: Vector[String], expectedSeed: BIP39Seed, - expectedXPriv: ExtPrivateKey) + expectedXPriv: ExtPrivateKey + ) private def testTrezorVector( vector: TrezorTestVector @@ -248,21 +253,23 @@ class MnemonicCodeTest extends BitcoinSUnitTest { } it must "not serialize a MnemonicCode toString" in { - val correctSeed = Vector("phone", - "dilemma", - "early", - "never", - "test", - "surge", - "ecology", - "rail", - "medal", - "benefit", - "mystery", - "toward", - "lounge", - "candy", - "syrup") + val correctSeed = Vector( + "phone", + "dilemma", + "early", + "never", + "test", + "surge", + "ecology", + "rail", + "medal", + "benefit", + "mystery", + "toward", + "lounge", + "candy", + "syrup" + ) val mnemonicCode = MnemonicCode.fromWords(correctSeed) diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCheckerTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCheckerTest.scala index e3930a938e..14a02d5a6a 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCheckerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCheckerTest.scala @@ -23,88 +23,113 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { // first tx from satoshi to hal :) // f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16 on mainnet val p2pkTx: Transaction = Transaction( - "0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd37040000000000ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000") + "0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd37040000000000ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000" + ) val p2pkOutput: TransactionOutput = TransactionOutput( - "00f2052a0100000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac") + "00f2052a0100000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac" + ) val p2pkPubKey: ECPublicKeyBytes = ECPublicKeyBytes( - "0311db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c") + "0311db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c" + ) val p2pkSig: ECDigitalSignature = ECDigitalSignature( - "304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901") + "304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901" + ) it must "validate a P2PK sig" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2pkTx, - inputIndex = UInt32.zero, - output = p2pkOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2pkTx, + inputIndex = UInt32.zero, + output = p2pkOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2pkPubKey, - p2pkSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2pkPubKey, + p2pkSig + ) assert(result.isValid, s"result: $result") } // 66f48fa8ef5db20a3b4be6b13f024b6e23480fd83df26ffbe7449110b113a665 on testnet val p2pkhTx: Transaction = Transaction( - "0100000001b8a1278696acfa85f1f576836aa30d335207b69bdaff43d9464cc1db40fe19ae0000000000feffffff02a0860100000000001976a914775bd9c79a9e988c0d6177a9205a611a50b7229188acb6342900000000001976a914f23a46f930320ab3cc7ad8c1660325f4c434d11688ac63b70d00") + "0100000001b8a1278696acfa85f1f576836aa30d335207b69bdaff43d9464cc1db40fe19ae0000000000feffffff02a0860100000000001976a914775bd9c79a9e988c0d6177a9205a611a50b7229188acb6342900000000001976a914f23a46f930320ab3cc7ad8c1660325f4c434d11688ac63b70d00" + ) val p2pkhOutput: TransactionOutput = TransactionOutput( - "00000000000000001976a914cd0385f813ec73f8fc340b7069daf566878a0d6b88ac") + "00000000000000001976a914cd0385f813ec73f8fc340b7069daf566878a0d6b88ac" + ) val p2pkhPubKey: ECPublicKeyBytes = ECPublicKeyBytes( - "02a01aaa27b468ec3fb2ae0c2a9fa1d5dce9b79b35062178f479156d8daa6c0e50") + "02a01aaa27b468ec3fb2ae0c2a9fa1d5dce9b79b35062178f479156d8daa6c0e50" + ) val p2pkhSig: ECDigitalSignature = ECDigitalSignature( - "3044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a201") + "3044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a201" + ) it must "validate a P2PKH sig" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2pkhTx, - inputIndex = UInt32.zero, - output = p2pkhOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2pkhTx, + inputIndex = UInt32.zero, + output = p2pkhOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2pkhPubKey, - p2pkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2pkhPubKey, + p2pkhSig + ) assert(result.isValid, s"result: $result") } // aed79e83630b092dd4888760e322d27cea80b33b877b9ea2563bccfe37c31ff3 on testnet val p2shMultiTx: Transaction = Transaction( - "0100000001d96b47c1dad0f0845529abed89dae027df4bc8d2332125fc2d8e32f173cb17ca01000000da004830450221008c6feca23958570d87e5dfb3c30a4ee3f07ef808bbafb21d0bf99ac62122498d022067c9b99dde72840d070a1a6e8527810d4ff3d6567c0177419f97210d8fa272470147304402201540a3467e3d04f149c23917630784e9ceafdf53c8557123df6fc3738ae9aacb022047fd2ac7ba925914bad08c951cad86b300bc9a49f6a1eca777686ed58be47bb90147522102895a52495c4c370d50e6bef622ff28d87eec2df00c546b8921b6d07e844bfb9c210283fe2cf10b7dba0d635b3e408532183e27cd43adc11e125027107c095a2bfbc552aefcffffff030000000000000000166a146f6d6e69000000000000001f0000015b9dbc1200041d471a0000000017a9146e78f4b07eec1ae32ac26bf449a7dede47f2b5aa8722020000000000001976a91499f8677f2465513d4d7fe77cac7f4c184c3d84dd88ac00000000") + "0100000001d96b47c1dad0f0845529abed89dae027df4bc8d2332125fc2d8e32f173cb17ca01000000da004830450221008c6feca23958570d87e5dfb3c30a4ee3f07ef808bbafb21d0bf99ac62122498d022067c9b99dde72840d070a1a6e8527810d4ff3d6567c0177419f97210d8fa272470147304402201540a3467e3d04f149c23917630784e9ceafdf53c8557123df6fc3738ae9aacb022047fd2ac7ba925914bad08c951cad86b300bc9a49f6a1eca777686ed58be47bb90147522102895a52495c4c370d50e6bef622ff28d87eec2df00c546b8921b6d07e844bfb9c210283fe2cf10b7dba0d635b3e408532183e27cd43adc11e125027107c095a2bfbc552aefcffffff030000000000000000166a146f6d6e69000000000000001f0000015b9dbc1200041d471a0000000017a9146e78f4b07eec1ae32ac26bf449a7dede47f2b5aa8722020000000000001976a91499f8677f2465513d4d7fe77cac7f4c184c3d84dd88ac00000000" + ) val p2shMultiOutput: TransactionOutput = TransactionOutput( - "96b3471a0000000017a9146e78f4b07eec1ae32ac26bf449a7dede47f2b5aa87") + "96b3471a0000000017a9146e78f4b07eec1ae32ac26bf449a7dede47f2b5aa87" + ) val p2shMultiRedeemScript: MultiSignatureScriptPubKey = MultiSignatureScriptPubKey( - "47522102895a52495c4c370d50e6bef622ff28d87eec2df00c546b8921b6d07e844bfb9c210283fe2cf10b7dba0d635b3e408532183e27cd43adc11e125027107c095a2bfbc552ae") + "47522102895a52495c4c370d50e6bef622ff28d87eec2df00c546b8921b6d07e844bfb9c210283fe2cf10b7dba0d635b3e408532183e27cd43adc11e125027107c095a2bfbc552ae" + ) val p2shMultiPubKey1: ECPublicKeyBytes = ECPublicKeyBytes( - "02895a52495c4c370d50e6bef622ff28d87eec2df00c546b8921b6d07e844bfb9c") + "02895a52495c4c370d50e6bef622ff28d87eec2df00c546b8921b6d07e844bfb9c" + ) val p2shMultiPubKey2: ECPublicKeyBytes = ECPublicKeyBytes( - "0283fe2cf10b7dba0d635b3e408532183e27cd43adc11e125027107c095a2bfbc5") + "0283fe2cf10b7dba0d635b3e408532183e27cd43adc11e125027107c095a2bfbc5" + ) val p2shMultiSig1: ECDigitalSignature = ECDigitalSignature( - "30450221008c6feca23958570d87e5dfb3c30a4ee3f07ef808bbafb21d0bf99ac62122498d022067c9b99dde72840d070a1a6e8527810d4ff3d6567c0177419f97210d8fa2724701") + "30450221008c6feca23958570d87e5dfb3c30a4ee3f07ef808bbafb21d0bf99ac62122498d022067c9b99dde72840d070a1a6e8527810d4ff3d6567c0177419f97210d8fa2724701" + ) val p2shMultiSig2: ECDigitalSignature = ECDigitalSignature( - "304402201540a3467e3d04f149c23917630784e9ceafdf53c8557123df6fc3738ae9aacb022047fd2ac7ba925914bad08c951cad86b300bc9a49f6a1eca777686ed58be47bb901") + "304402201540a3467e3d04f149c23917630784e9ceafdf53c8557123df6fc3738ae9aacb022047fd2ac7ba925914bad08c951cad86b300bc9a49f6a1eca777686ed58be47bb901" + ) it must "validate P2SH(Multi) signatures" in { val txSignatureComponent = - P2SHTxSigComponent(transaction = p2shMultiTx, - inputIndex = UInt32.zero, - output = p2shMultiOutput, - Policy.standardFlags) + P2SHTxSigComponent( + transaction = p2shMultiTx, + inputIndex = UInt32.zero, + output = p2shMultiOutput, + Policy.standardFlags + ) val result1 = TransactionSignatureChecker.checkSignature( @@ -112,7 +137,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { p2shMultiRedeemScript.asm.toList, p2shMultiPubKey1, p2shMultiSig1, - Policy.standardFlags) + Policy.standardFlags + ) assert(result1.isValid, s"result: $result1") @@ -122,7 +148,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { p2shMultiRedeemScript.asm.toList, p2shMultiPubKey2, p2shMultiSig2, - Policy.standardFlags) + Policy.standardFlags + ) assert(result2.isValid, s"result: $result2") @@ -141,54 +168,68 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { // de8ed7b2dd4c354ef89ef8aab8f5f19fc6e0a2a2f4559c35c4842f499b31e94e on testnet val p2wpkhTx: WitnessTransaction = WitnessTransaction( - "02000000000101ef710d693621082a77338b9c74260f01409120be7fb2a053f12d23c714adb16c01000000000000000001e803000000000000160014d931a218e08806bec7faa00157a26237c08d4101020021023b19cda60171c1660e95d9e42103d7c86a11a48e396271515d704e755b2bb2d200000000") + "02000000000101ef710d693621082a77338b9c74260f01409120be7fb2a053f12d23c714adb16c01000000000000000001e803000000000000160014d931a218e08806bec7faa00157a26237c08d4101020021023b19cda60171c1660e95d9e42103d7c86a11a48e396271515d704e755b2bb2d200000000" + ) val p2wpkhOutput: TransactionOutput = TransactionOutput( - "1027000000000000160014c5aff982b31b4c0f12978c56b37f6a814454df9d") + "1027000000000000160014c5aff982b31b4c0f12978c56b37f6a814454df9d" + ) val p2wpkhPubKey: ECPublicKey = ECPublicKey( - "023b19cda60171c1660e95d9e42103d7c86a11a48e396271515d704e755b2bb2d2") + "023b19cda60171c1660e95d9e42103d7c86a11a48e396271515d704e755b2bb2d2" + ) val p2wpkhSig: ECDigitalSignature = ECDigitalSignature( - "3045022100d7d5fabac9b8486f31b2a7c1217335fc24aa0aa1ff8abd3d78845bc2f8ff3bd3022018b9c79581c2bc2f7811f235fa4c21b23c6a2b478a46351c955adaba15acc4e201") + "3045022100d7d5fabac9b8486f31b2a7c1217335fc24aa0aa1ff8abd3d78845bc2f8ff3bd3022018b9c79581c2bc2f7811f235fa4c21b23c6a2b478a46351c955adaba15acc4e201" + ) it must "validate a P2WPKH sig" in { val txSignatureComponent = - WitnessTxSigComponentRaw(transaction = p2wpkhTx, - inputIndex = UInt32.zero, - output = p2wpkhOutput, - Policy.standardFlags) + WitnessTxSigComponentRaw( + transaction = p2wpkhTx, + inputIndex = UInt32.zero, + output = p2wpkhOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2wpkhPubKey, - p2wpkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2wpkhPubKey, + p2wpkhSig + ) assert(result.isValid, s"result: $result") } // df8d2ddcbe81b340b117d54efb4f11753c7769745ced9af38562ad5d28ef1b1c on testnet val p2shwpkhTx: WitnessTransaction = WitnessTransaction( - "020000000001012d84c922aafb935a95d0adcfd323cd127fcd5a70987013ae631470a3d09d7d81010000001716001422fe81d0b50f7a6407d4280e1603c10f5fc3fac8feffffff023062e3a00100000017a9143bdd9f87d2c1cb89ef720c0ad627262917a12ded8762831c000000000017a9144e36d1ac7c773f18b4b2ab4b88cb7fcad3d91abd870247304402207f27a20acc1e7ccae2d1fa6708fc989c5744e6a35d7b437a995fb8fa0cfbff5a02204f0a2a8879b8eccb580f8a1e0b6ed0ccc175b2ec471a1183a066f740c3dd21470121029ca7faef43714b34508589f31394e0b0b6ab24dd4e440eaa03e72841d48e50c5ed381a00") + "020000000001012d84c922aafb935a95d0adcfd323cd127fcd5a70987013ae631470a3d09d7d81010000001716001422fe81d0b50f7a6407d4280e1603c10f5fc3fac8feffffff023062e3a00100000017a9143bdd9f87d2c1cb89ef720c0ad627262917a12ded8762831c000000000017a9144e36d1ac7c773f18b4b2ab4b88cb7fcad3d91abd870247304402207f27a20acc1e7ccae2d1fa6708fc989c5744e6a35d7b437a995fb8fa0cfbff5a02204f0a2a8879b8eccb580f8a1e0b6ed0ccc175b2ec471a1183a066f740c3dd21470121029ca7faef43714b34508589f31394e0b0b6ab24dd4e440eaa03e72841d48e50c5ed381a00" + ) val p2shwpkhOutput: TransactionOutput = TransactionOutput( - "202d00a10100000017a914aa29eed6460a03219e92a3ff54d801a7473f2a7f87") + "202d00a10100000017a914aa29eed6460a03219e92a3ff54d801a7473f2a7f87" + ) val p2shwpkhRedeemScript: ScriptPubKey = ScriptPubKey("16001422fe81d0b50f7a6407d4280e1603c10f5fc3fac8") val p2shwpkhPubKey: ECPublicKeyBytes = ECPublicKeyBytes( - "029ca7faef43714b34508589f31394e0b0b6ab24dd4e440eaa03e72841d48e50c5") + "029ca7faef43714b34508589f31394e0b0b6ab24dd4e440eaa03e72841d48e50c5" + ) val p2shwpkhSig: ECDigitalSignature = ECDigitalSignature( - "304402207f27a20acc1e7ccae2d1fa6708fc989c5744e6a35d7b437a995fb8fa0cfbff5a02204f0a2a8879b8eccb580f8a1e0b6ed0ccc175b2ec471a1183a066f740c3dd214701") + "304402207f27a20acc1e7ccae2d1fa6708fc989c5744e6a35d7b437a995fb8fa0cfbff5a02204f0a2a8879b8eccb580f8a1e0b6ed0ccc175b2ec471a1183a066f740c3dd214701" + ) it must "validate a P2SH(P2WPKH) sig" in { val txSignatureComponent = - WitnessTxSigComponentP2SH(transaction = p2shwpkhTx, - inputIndex = UInt32.zero, - output = p2shwpkhOutput, - Policy.standardFlags) + WitnessTxSigComponentP2SH( + transaction = p2shwpkhTx, + inputIndex = UInt32.zero, + output = p2shwpkhOutput, + Policy.standardFlags + ) val result = TransactionSignatureChecker.checkSignature( @@ -196,57 +237,71 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { p2shwpkhRedeemScript.asm.toList, p2shwpkhPubKey, p2shwpkhSig, - Policy.standardFlags) + Policy.standardFlags + ) assert(result.isValid, s"result: $result") } // d7b77277cc38151606c604010b5cbc9a9e0e06e8b59d9f891d5cda0bb101ab39 on mainnet val p2wshTx: WitnessTransaction = WitnessTransaction( - "01000000000101ed91ad279e27cea42e12cc5fbda6a3b616fe0c6e4ac2a8ec79e33a3809fc2cbd0200000000ffffffff02c0cf6a000000000017a91467d1a505334bf8cb2e1090811ecc16b339de4f4087f2207a7100000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d040047304402207836deb67f9fe8209af34c5c83cb614f0ab9482afeab3ab44ed37dec74eb058d022001421e40e4ae478685b0845420f33621a42aded5389e72637a07a6cfaaebd8f10147304402202046a8e34daf0126ad23ca76460ad9074b373995babef5288edcccaafa052fbe0220381ebf98806a7bf6e5968e6c4374362b79f81b9ed9ed2b24ec743d3272b7a499016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000") + "01000000000101ed91ad279e27cea42e12cc5fbda6a3b616fe0c6e4ac2a8ec79e33a3809fc2cbd0200000000ffffffff02c0cf6a000000000017a91467d1a505334bf8cb2e1090811ecc16b339de4f4087f2207a7100000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d040047304402207836deb67f9fe8209af34c5c83cb614f0ab9482afeab3ab44ed37dec74eb058d022001421e40e4ae478685b0845420f33621a42aded5389e72637a07a6cfaaebd8f10147304402202046a8e34daf0126ad23ca76460ad9074b373995babef5288edcccaafa052fbe0220381ebf98806a7bf6e5968e6c4374362b79f81b9ed9ed2b24ec743d3272b7a499016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000" + ) val p2wshOutput: TransactionOutput = TransactionOutput( - "12dbe57100000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d") + "12dbe57100000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d" + ) val p2wshWitScript: MultiSignatureScriptPubKey = MultiSignatureScriptPubKey( - "6952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae") + "6952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae" + ) val p2wshPubKey1: ECPublicKeyBytes = ECPublicKeyBytes( - "0375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c") + "0375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c" + ) val p2wshPubKey2: ECPublicKeyBytes = ECPublicKeyBytes( - "03a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff") + "03a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff" + ) val p2wshSig1: ECDigitalSignature = ECDigitalSignature( - "304402207836deb67f9fe8209af34c5c83cb614f0ab9482afeab3ab44ed37dec74eb058d022001421e40e4ae478685b0845420f33621a42aded5389e72637a07a6cfaaebd8f101") + "304402207836deb67f9fe8209af34c5c83cb614f0ab9482afeab3ab44ed37dec74eb058d022001421e40e4ae478685b0845420f33621a42aded5389e72637a07a6cfaaebd8f101" + ) val p2wshSig2: ECDigitalSignature = ECDigitalSignature( - "304402202046a8e34daf0126ad23ca76460ad9074b373995babef5288edcccaafa052fbe0220381ebf98806a7bf6e5968e6c4374362b79f81b9ed9ed2b24ec743d3272b7a49901") + "304402202046a8e34daf0126ad23ca76460ad9074b373995babef5288edcccaafa052fbe0220381ebf98806a7bf6e5968e6c4374362b79f81b9ed9ed2b24ec743d3272b7a49901" + ) it must "validate P2WSH(Multisig) signatures" in { val txSignatureComponent = - WitnessTxSigComponent(transaction = p2wshTx, - inputIndex = UInt32.zero, - output = p2wshOutput, - PreviousOutputMap.empty, - Policy.standardFlags) + WitnessTxSigComponent( + transaction = p2wshTx, + inputIndex = UInt32.zero, + output = p2wshOutput, + PreviousOutputMap.empty, + Policy.standardFlags + ) val result1 = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2wshWitScript.asm.toList, - p2wshPubKey1, - p2wshSig1, - Policy.standardFlags) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2wshWitScript.asm.toList, + p2wshPubKey1, + p2wshSig1, + Policy.standardFlags + ) assert(result1.isValid, s"result: $result1") val result2 = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2wshWitScript.asm.toList, - p2wshPubKey2, - p2wshSig2, - Policy.standardFlags) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2wshWitScript.asm.toList, + p2wshPubKey2, + p2wshSig2, + Policy.standardFlags + ) assert(result2.isValid, s"result: $result2") @@ -257,7 +312,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { List(p2wshSig1, p2wshSig2), List(p2wshPubKey1, p2wshPubKey2), Policy.standardFlags, - 2) + 2 + ) assert(result3.isValid, s"result: $result3") } @@ -271,130 +327,164 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { it must "fail a P2PK sig with the wrong pubkey" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2pkTx, - inputIndex = UInt32.zero, - output = p2pkOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2pkTx, + inputIndex = UInt32.zero, + output = p2pkOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - incorrectPubKey, - p2pkSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + incorrectPubKey, + p2pkSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2PK sig with the wrong output" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2pkTx, - inputIndex = UInt32.zero, - output = incorrectOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2pkTx, + inputIndex = UInt32.zero, + output = incorrectOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2pkPubKey, - p2pkSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2pkPubKey, + p2pkSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2PK sig with the wrong tx" in { val txSignatureComponent = - BaseTxSigComponent(transaction = incorrectTx, - inputIndex = UInt32.zero, - output = p2pkOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = incorrectTx, + inputIndex = UInt32.zero, + output = p2pkOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2pkPubKey, - p2pkSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2pkPubKey, + p2pkSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2PK sig with the wrong input index" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2pkTx, - inputIndex = incorrectInputIndex, - output = p2pkOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2pkTx, + inputIndex = incorrectInputIndex, + output = p2pkOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2pkPubKey, - p2pkSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2pkPubKey, + p2pkSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2PKH sig with the wrong pubkey" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2pkhTx, - inputIndex = UInt32.zero, - output = p2pkhOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2pkhTx, + inputIndex = UInt32.zero, + output = p2pkhOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - incorrectPubKey, - p2pkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + incorrectPubKey, + p2pkhSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2PKH sig with the wrong output" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2pkhTx, - inputIndex = UInt32.zero, - output = incorrectOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2pkhTx, + inputIndex = UInt32.zero, + output = incorrectOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2pkhPubKey, - p2pkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2pkhPubKey, + p2pkhSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2PKH sig with the wrong tx" in { val txSignatureComponent = - BaseTxSigComponent(transaction = incorrectTx, - inputIndex = UInt32.zero, - output = p2pkhOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = incorrectTx, + inputIndex = UInt32.zero, + output = p2pkhOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2pkhPubKey, - p2pkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2pkhPubKey, + p2pkhSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2PKH sig with the wrong input index" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2pkhTx, - inputIndex = incorrectInputIndex, - output = p2pkhOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2pkhTx, + inputIndex = incorrectInputIndex, + output = p2pkhOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2pkhPubKey, - p2pkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2pkhPubKey, + p2pkhSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2SH(Multi) with the wrong pub key 1" in { val txSignatureComponent = - P2SHTxSigComponent(transaction = p2shMultiTx, - inputIndex = UInt32.zero, - output = p2shMultiOutput, - Policy.standardFlags) + P2SHTxSigComponent( + transaction = p2shMultiTx, + inputIndex = UInt32.zero, + output = p2shMultiOutput, + Policy.standardFlags + ) val result1 = TransactionSignatureChecker.checkSignature( @@ -402,7 +492,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { p2shMultiRedeemScript.asm.toList, incorrectPubKey, p2shMultiSig1, - Policy.standardFlags) + Policy.standardFlags + ) assert(!result1.isValid, s"result: $result1") @@ -412,7 +503,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { p2shMultiRedeemScript.asm.toList, p2shMultiPubKey2, p2shMultiSig2, - Policy.standardFlags) + Policy.standardFlags + ) assert(result2.isValid, s"result: $result2") @@ -431,10 +523,12 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { it must "fail a P2SH(Multi) with the wrong pub key 2" in { val txSignatureComponent = - P2SHTxSigComponent(transaction = p2shMultiTx, - inputIndex = UInt32.zero, - output = p2shMultiOutput, - Policy.standardFlags) + P2SHTxSigComponent( + transaction = p2shMultiTx, + inputIndex = UInt32.zero, + output = p2shMultiOutput, + Policy.standardFlags + ) val result1 = TransactionSignatureChecker.checkSignature( @@ -442,7 +536,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { p2shMultiRedeemScript.asm.toList, p2shMultiPubKey1, p2shMultiSig1, - Policy.standardFlags) + Policy.standardFlags + ) assert(result1.isValid, s"result: $result1") @@ -452,7 +547,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { p2shMultiRedeemScript.asm.toList, incorrectPubKey, p2shMultiSig2, - Policy.standardFlags) + Policy.standardFlags + ) assert(!result2.isValid, s"result: $result2") @@ -471,10 +567,12 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { it must "fail a P2SH(Multi) with the wrong number of sigs" in { val txSignatureComponent = - P2SHTxSigComponent(transaction = p2shMultiTx, - inputIndex = UInt32.zero, - output = p2shMultiOutput, - Policy.standardFlags) + P2SHTxSigComponent( + transaction = p2shMultiTx, + inputIndex = UInt32.zero, + output = p2shMultiOutput, + Policy.standardFlags + ) assertThrows[IllegalArgumentException]( TransactionSignatureChecker.multiSignatureEvaluator( @@ -484,7 +582,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { List(p2shMultiPubKey1, p2shMultiPubKey2), Policy.standardFlags, 1 - )) + ) + ) assertThrows[IllegalArgumentException]( TransactionSignatureChecker.multiSignatureEvaluator( @@ -494,83 +593,104 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { List(p2shMultiPubKey1, p2shMultiPubKey2), Policy.standardFlags, -1 - )) + ) + ) } it must "fail a P2WPKH sig with the wrong pubkey" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2wpkhTx, - inputIndex = UInt32.zero, - output = p2wpkhOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2wpkhTx, + inputIndex = UInt32.zero, + output = p2wpkhOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - incorrectPubKey, - p2wpkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + incorrectPubKey, + p2wpkhSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2WPKH sig with the wrong output" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2wpkhTx, - inputIndex = UInt32.zero, - output = incorrectOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2wpkhTx, + inputIndex = UInt32.zero, + output = incorrectOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2wpkhPubKey, - p2wpkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2wpkhPubKey, + p2wpkhSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2WPKH sig with the wrong tx" in { val txSignatureComponent = - BaseTxSigComponent(transaction = incorrectTx, - inputIndex = UInt32.zero, - output = p2wpkhOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = incorrectTx, + inputIndex = UInt32.zero, + output = p2wpkhOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2wpkhPubKey, - p2wpkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2wpkhPubKey, + p2wpkhSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2WPKH sig with the wrong input index" in { val txSignatureComponent = - BaseTxSigComponent(transaction = p2wpkhTx, - inputIndex = incorrectInputIndex, - output = p2wpkhOutput, - Policy.standardFlags) + BaseTxSigComponent( + transaction = p2wpkhTx, + inputIndex = incorrectInputIndex, + output = p2wpkhOutput, + Policy.standardFlags + ) val result = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2wpkhPubKey, - p2wpkhSig) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2wpkhPubKey, + p2wpkhSig + ) assert(!result.isValid, s"result: $result") } it must "fail a P2WSH(Multi) with the wrong pub key 1" in { val txSignatureComponent = - WitnessTxSigComponent(transaction = p2wshTx, - inputIndex = UInt32.zero, - output = p2wshOutput, - PreviousOutputMap.empty, - Policy.standardFlags) + WitnessTxSigComponent( + transaction = p2wshTx, + inputIndex = UInt32.zero, + output = p2wshOutput, + PreviousOutputMap.empty, + Policy.standardFlags + ) val result1 = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2wshWitScript.asm.toList, - incorrectPubKey, - p2wshSig1, - Policy.standardFlags) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2wshWitScript.asm.toList, + incorrectPubKey, + p2wshSig1, + Policy.standardFlags + ) assert(!result1.isValid, s"result: $result1") @@ -580,7 +700,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { p2shMultiRedeemScript.asm.toList, p2wshPubKey2, p2wshSig2, - Policy.standardFlags) + Policy.standardFlags + ) assert(result2.isValid, s"result: $result2") @@ -599,18 +720,22 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { it must "fail a P2WSH(Multi) with the wrong pub key 2" in { val txSignatureComponent = - WitnessTxSigComponent(transaction = p2wshTx, - inputIndex = UInt32.zero, - output = p2wshOutput, - PreviousOutputMap.empty, - Policy.standardFlags) + WitnessTxSigComponent( + transaction = p2wshTx, + inputIndex = UInt32.zero, + output = p2wshOutput, + PreviousOutputMap.empty, + Policy.standardFlags + ) val result1 = - TransactionSignatureChecker.checkSignature(txSignatureComponent, - p2wshWitScript.asm.toList, - p2wshPubKey1, - p2wshSig1, - Policy.standardFlags) + TransactionSignatureChecker.checkSignature( + txSignatureComponent, + p2wshWitScript.asm.toList, + p2wshPubKey1, + p2wshSig1, + Policy.standardFlags + ) assert(result1.isValid, s"result: $result1") @@ -620,7 +745,8 @@ class TransactionSignatureCheckerTest extends BitcoinSUnitTest { p2shMultiRedeemScript.asm.toList, incorrectPubKey, p2wshSig2, - Policy.standardFlags) + Policy.standardFlags + ) assert(!result2.isValid, s"result: $result2") diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala index b16e00ce77..ce07d93c09 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorSpec.scala @@ -14,7 +14,7 @@ class TransactionSignatureCreatorSpec property("Must generate a valid signature for a p2pk transaction") = Prop.forAll(TransactionGenerators.signedP2PKTransaction) { case (txSignatureComponent: TxSigComponent, _) => - //run it through the interpreter + // run it through the interpreter val program: PreExecutionScriptProgram = PreExecutionScriptProgram(txSignatureComponent) val result = ScriptInterpreter.run(program) @@ -24,7 +24,7 @@ class TransactionSignatureCreatorSpec property("generate valid signatures for a multisignature transaction") = Prop.forAllNoShrink(TransactionGenerators.signedMultiSigTransaction) { case (txSignatureComponent: TxSigComponent, _) => - //run it through the interpreter + // run it through the interpreter val program = PreExecutionScriptProgram(txSignatureComponent) val result = ScriptInterpreter.run(program) result == ScriptOk @@ -33,56 +33,54 @@ class TransactionSignatureCreatorSpec property("generate a valid signature for a p2sh transaction") = Prop.forAll(TransactionGenerators.signedP2SHTransaction) { case (txSignatureComponent: TxSigComponent, _) => - //run it through the interpreter + // run it through the interpreter val program = PreExecutionScriptProgram(txSignatureComponent) val result = ScriptInterpreter.run(program) - //can be ScriptErrorPushSize if the redeemScript is larger than 520 bytes + // can be ScriptErrorPushSize if the redeemScript is larger than 520 bytes Seq(ScriptOk, ScriptErrorPushSize).contains(result) } property( - "generate a valid signature for a valid and spendable cltv transaction") = - Prop.forAllNoShrink( - TransactionGenerators.spendableCLTVTransaction :| "cltv_spendable") { - case (txSignatureComponent: TxSigComponent, _) => - val program = PreExecutionScriptProgram(txSignatureComponent) - val result = ScriptInterpreter.run(program) - result == ScriptOk - } + "generate a valid signature for a valid and spendable cltv transaction" + ) = Prop.forAllNoShrink( + TransactionGenerators.spendableCLTVTransaction :| "cltv_spendable" + ) { case (txSignatureComponent: TxSigComponent, _) => + val program = PreExecutionScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + result == ScriptOk + } property( - "fail to verify a transaction with a locktime that has not yet been met") = - Prop.forAllNoShrink( - TransactionGenerators.unspendableCLTVTransaction :| "cltv_unspendable") { - case (txSignatureComponent: TxSigComponent, _) => - val program = PreExecutionScriptProgram(txSignatureComponent) - val result = ScriptInterpreter.run(program) - Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains( - result) - } + "fail to verify a transaction with a locktime that has not yet been met" + ) = Prop.forAllNoShrink( + TransactionGenerators.unspendableCLTVTransaction :| "cltv_unspendable" + ) { case (txSignatureComponent: TxSigComponent, _) => + val program = PreExecutionScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(result) + } property( - "generate a valid signature for a valid and spendable csv transaction") = - Prop.forAllNoShrink( - TransactionGenerators.spendableCSVTransaction :| "spendable csv") { - case (txSignatureComponent: TxSigComponent, _) => - //run it through the interpreter - val program = PreExecutionScriptProgram(txSignatureComponent) - val result = ScriptInterpreter.run(program) - Seq(ScriptOk, ScriptErrorPushSize).contains(result) - } + "generate a valid signature for a valid and spendable csv transaction" + ) = Prop.forAllNoShrink( + TransactionGenerators.spendableCSVTransaction :| "spendable csv" + ) { case (txSignatureComponent: TxSigComponent, _) => + // run it through the interpreter + val program = PreExecutionScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + Seq(ScriptOk, ScriptErrorPushSize).contains(result) + } property( - "fail to verify a transaction with a relative locktime that has not been satisfied yet") = - Prop.forAllNoShrink( - TransactionGenerators.unspendableCSVTransaction :| "unspendable csv") { - case (txSignatureComponent: TxSigComponent, _) => - //run it through the interpreter - val program = PreExecutionScriptProgram(txSignatureComponent) - val result = ScriptInterpreter.run(program) - Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains( - result) + "fail to verify a transaction with a relative locktime that has not been satisfied yet" + ) = Prop.forAllNoShrink( + TransactionGenerators.unspendableCSVTransaction :| "unspendable csv" + ) { case (txSignatureComponent: TxSigComponent, _) => + // run it through the interpreter + val program = PreExecutionScriptProgram(txSignatureComponent) + val result = ScriptInterpreter.run(program) + Seq(ScriptErrorUnsatisfiedLocktime, ScriptErrorPushSize).contains(result) - } + } property("generate a valid signature for a p2wpkh witness transaction") = Prop.forAllNoShrink(TransactionGenerators.signedP2WPKHTransaction) { @@ -93,28 +91,28 @@ class TransactionSignatureCreatorSpec } property( - "generate a valid signature for a p2wsh(old scriptPubkey tx) witness transaction") = - Prop.forAllNoShrink(TransactionGenerators.signedP2WSHTransaction) { - case (wtxSigComponent, _) => - val program = PreExecutionScriptProgram(wtxSigComponent) - val result = ScriptInterpreter.run(program) - Seq(ScriptErrorPushSize, ScriptOk).contains(result) - } + "generate a valid signature for a p2wsh(old scriptPubkey tx) witness transaction" + ) = Prop.forAllNoShrink(TransactionGenerators.signedP2WSHTransaction) { + case (wtxSigComponent, _) => + val program = PreExecutionScriptProgram(wtxSigComponent) + val result = ScriptInterpreter.run(program) + Seq(ScriptErrorPushSize, ScriptOk).contains(result) + } property( - "generate a valid signature from a p2sh(p2wpkh) witness transaction") = - Prop.forAllNoShrink(TransactionGenerators.signedP2SHP2WPKHTransaction) { - case (wtxSigComponent, _) => - val program = PreExecutionScriptProgram(wtxSigComponent) - val result = ScriptInterpreter.run(program) - result == ScriptOk - } + "generate a valid signature from a p2sh(p2wpkh) witness transaction" + ) = Prop.forAllNoShrink(TransactionGenerators.signedP2SHP2WPKHTransaction) { + case (wtxSigComponent, _) => + val program = PreExecutionScriptProgram(wtxSigComponent) + val result = ScriptInterpreter.run(program) + result == ScriptOk + } property( - "generate a valid signature from a p2sh(p2wsh) witness tranasction") = - Prop.forAllNoShrink(TransactionGenerators.signedP2SHP2WSHTransaction) { - case (wtxSigComponent, _) => - val program = PreExecutionScriptProgram(wtxSigComponent) - val result = ScriptInterpreter.run(program) - Seq(ScriptErrorPushSize, ScriptOk).contains(result) - } + "generate a valid signature from a p2sh(p2wsh) witness tranasction" + ) = Prop.forAllNoShrink(TransactionGenerators.signedP2SHP2WSHTransaction) { + case (wtxSigComponent, _) => + val program = PreExecutionScriptProgram(wtxSigComponent) + val result = ScriptInterpreter.run(program) + Seq(ScriptErrorPushSize, ScriptOk).contains(result) + } } diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala index 536ba19f1e..e1eed6cbf1 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureCreatorTest.scala @@ -31,11 +31,12 @@ import scala.concurrent.Future class TransactionSignatureCreatorTest extends BitcoinSJvmTest { "TransactionSignatureCreator" must "create a signature for a scriptSignature in a transaction" in { - //this is a signed tx, but since TransactionSignatureSerializer removes scriptSigs, it will work for testing this - //from fe6ef8e20a9ca9cb5d59cb1c0f30eff2b23be2e3cc2bf4b4cfff519414e9a300 on testnet - //"30440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d01" + // this is a signed tx, but since TransactionSignatureSerializer removes scriptSigs, it will work for testing this + // from fe6ef8e20a9ca9cb5d59cb1c0f30eff2b23be2e3cc2bf4b4cfff519414e9a300 on testnet + // "30440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d01" val expectedSig = ECDigitalSignature( - "30440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d01") + "30440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d01" + ) val rawTx = "01000000021d50bf7c05b6169ea8d8fb5b79dd2978bbd2ac756a656a777279da43b19fd9d9000000006b4830450221008f2c818a55045a1c9dcda54fcd5b6377f5d09723a9ccd8c71df76ee4bdf7c16802201817cbd71d8148a5d53b11d33c9c58ad1086fe7ddf308da2a7cceb7d85df293e01210381c82dc267a958be06f1c920dc635bcd191d698c167e67a45a882a551c57ce1dfeffffffd4a6a37abfe003a9d10155df215e662f88d5b878b908d1a3772a9fbd195d008d010000006a4730440220357864ae2beba3d6ec34c0ce42262c1c12939502f0f8f4bd338c9d8b307593420220656687c327589dc3e464700fa7b784c7efc2b465c627a60c2f1ce402d05fc39d0121036301d848aec3dfc47789a63ee3c85c6d3bf757162ef77cb1580981b422838ed7feffffff0200e1f505000000001976a9146d39bac171d0bf450698fa0ebd93f51e79dcb6ac88ac35a96d00000000001976a914e11753f499ac7a910148e53156ab273557ed517e88acd6090b00" val transaction = Transaction(rawTx) @@ -45,26 +46,31 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { val scriptPubKey = ScriptPubKey("1976a914d7b4717a934386601ac3f980d01b48c83b8a0b4b88ac") val txSignatureComponent = - BaseTxSigComponent(transaction = transaction, - inputIndex = UInt32.one, - output = - TransactionOutput(10000000.sats, scriptPubKey), - Policy.standardScriptVerifyFlags) + BaseTxSigComponent( + transaction = transaction, + inputIndex = UInt32.one, + output = TransactionOutput(10000000.sats, scriptPubKey), + Policy.standardScriptVerifyFlags + ) val privateKey = ECPrivateKeyUtil.fromWIFToPrivateKey( - "cTPg4Zc5Jis2EZXy3NXShgbn487GWBTapbU63BerLDZM3w2hQSjC") + "cTPg4Zc5Jis2EZXy3NXShgbn487GWBTapbU63BerLDZM3w2hQSjC" + ) val txSignature = - TransactionSignatureCreator.createSig(txSignatureComponent, - privateKey.toPrivateKey, - HashType.sigHashAll) + TransactionSignatureCreator.createSig( + txSignatureComponent, + privateKey.toPrivateKey, + HashType.sigHashAll + ) txSignature.r must be(expectedSig.r) txSignature.s must be(expectedSig.s) txSignature.hex must be(expectedSig.hex) } it must "create the correct digital signature for a transaction with 1 input using a TxSignatureComponent" in { - //66f48fa8ef5db20a3b4be6b13f024b6e23480fd83df26ffbe7449110b113a665 on testnet + // 66f48fa8ef5db20a3b4be6b13f024b6e23480fd83df26ffbe7449110b113a665 on testnet val expectedSig = ECDigitalSignature( - "3044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a201") + "3044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a201" + ) val rawTx = "0100000001b8a1278696acfa85f1f576836aa30d335207b69bdaff43d9464cc1db40fe19ae000000006a473044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a2012102a01aaa27b468ec3fb2ae0c2a9fa1d5dce9b79b35062178f479156d8daa6c0e50feffffff02a0860100000000001976a914775bd9c79a9e988c0d6177a9205a611a50b7229188acb6342900000000001976a914f23a46f930320ab3cc7ad8c1660325f4c434d11688ac63b70d00" val transaction = Transaction(rawTx) @@ -74,49 +80,63 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { val scriptPubKey = ScriptPubKey("1976a914cd0385f813ec73f8fc340b7069daf566878a0d6b88ac") val txSignatureComponent = - BaseTxSigComponent(transaction = transaction, - inputIndex = UInt32.zero, - output = TransactionOutput(2806419.sats, scriptPubKey), - Policy.standardScriptVerifyFlags) + BaseTxSigComponent( + transaction = transaction, + inputIndex = UInt32.zero, + output = TransactionOutput(2806419.sats, scriptPubKey), + Policy.standardScriptVerifyFlags + ) val privateKey = ECPrivateKeyUtil.fromWIFToPrivateKey( - "cTTh7jNtZhg3vHTjvYK8zcHkLfsMAS8iqL7pfZ6eVAVHHF8fN1qy") + "cTTh7jNtZhg3vHTjvYK8zcHkLfsMAS8iqL7pfZ6eVAVHHF8fN1qy" + ) val txSignature = - TransactionSignatureCreator.createSig(txSignatureComponent, - privateKey.toPrivateKey, - HashType.sigHashAll) + TransactionSignatureCreator.createSig( + txSignatureComponent, + privateKey.toPrivateKey, + HashType.sigHashAll + ) txSignature.r must be(expectedSig.r) txSignature.s must be(expectedSig.s) txSignature.hex must be(expectedSig.hex) } it must "create the correct digital signature for a transaction with 1 input" in { - //66f48fa8ef5db20a3b4be6b13f024b6e23480fd83df26ffbe7449110b113a665 on testnet + // 66f48fa8ef5db20a3b4be6b13f024b6e23480fd83df26ffbe7449110b113a665 on testnet val expectedSig = ECDigitalSignature( - "3044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a201") + "3044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a201" + ) val rawTx = "0100000001b8a1278696acfa85f1f576836aa30d335207b69bdaff43d9464cc1db40fe19ae000000006a473044022075b4ab08ff34799ee6f8048a5044be98dff493fc5a0b8a36dcaee3bd7a9993ae02207bc532ceab09c10f1d54035d03ff9aad0e1004c3e0325a8b97b6be04b7d6c3a2012102a01aaa27b468ec3fb2ae0c2a9fa1d5dce9b79b35062178f479156d8daa6c0e50feffffff02a0860100000000001976a914775bd9c79a9e988c0d6177a9205a611a50b7229188acb6342900000000001976a914f23a46f930320ab3cc7ad8c1660325f4c434d11688ac63b70d00" val transaction = Transaction(rawTx) val prevTransaction = Transaction( - "0100000001e4dbac0d73f4e3a9e99e70596a5f81b35a75f95b0474d051fbfd9dc249a5b67e000000006a4730440220486f112aee12997f6e484754d53d5c2158c18cc6d1d3f13aefcdf0ed19c47b290220136133d934d9e79a57408166c39fbce38e217ea9d417cabc20744134f04f06960121021f8cb5c3d611cf24dd665adff3fd540e4c155a05adaa6b672bfa7897c126d9b6feffffff0293d22a00000000001976a914cd0385f813ec73f8fc340b7069daf566878a0d6b88ac40420f000000000017a91480f7a6c14a8407da3546b4abfc3086876ca9a0668700000000") + "0100000001e4dbac0d73f4e3a9e99e70596a5f81b35a75f95b0474d051fbfd9dc249a5b67e000000006a4730440220486f112aee12997f6e484754d53d5c2158c18cc6d1d3f13aefcdf0ed19c47b290220136133d934d9e79a57408166c39fbce38e217ea9d417cabc20744134f04f06960121021f8cb5c3d611cf24dd665adff3fd540e4c155a05adaa6b672bfa7897c126d9b6feffffff0293d22a00000000001976a914cd0385f813ec73f8fc340b7069daf566878a0d6b88ac40420f000000000017a91480f7a6c14a8407da3546b4abfc3086876ca9a0668700000000" + ) val privateKey = ECPrivateKeyUtil .fromWIFToPrivateKey( - "cTTh7jNtZhg3vHTjvYK8zcHkLfsMAS8iqL7pfZ6eVAVHHF8fN1qy") + "cTTh7jNtZhg3vHTjvYK8zcHkLfsMAS8iqL7pfZ6eVAVHHF8fN1qy" + ) .toPrivateKey val inputInfo = - P2PKHInputInfo(TransactionOutPoint(prevTransaction.txId, UInt32.zero), - 2806419.sats, - privateKey.publicKey) - val signingInfo = ECSignatureParams(inputInfo, - prevTransaction, - privateKey, - HashType.sigHashAll) + P2PKHInputInfo( + TransactionOutPoint(prevTransaction.txId, UInt32.zero), + 2806419.sats, + privateKey.publicKey + ) + val signingInfo = ECSignatureParams( + inputInfo, + prevTransaction, + privateKey, + HashType.sigHashAll + ) val txSignature = - TransactionSignatureCreator.createSig(transaction, - signingInfo, - privateKey, - HashType.sigHashAll) + TransactionSignatureCreator.createSig( + transaction, + signingInfo, + privateKey, + HashType.sigHashAll + ) txSignature.r must be(expectedSig.r) txSignature.s must be(expectedSig.s) txSignature.hex must be(expectedSig.hex) @@ -128,10 +148,12 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { val fee = SatoshisPerVirtualByte(Satoshis(100)) val spendingTx = StandardNonInteractiveFinalizer - .txFrom(outputs = destinations, - utxos = creditingTxsInfo, - feeRate = fee, - changeSPK = changeSPK) + .txFrom( + outputs = destinations, + utxos = creditingTxsInfo, + feeRate = fee, + changeSPK = changeSPK + ) val prevOutMap = PreviousOutputMap.fromScriptSignatureParams(creditingTxsInfo) @@ -143,15 +165,19 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { TxSigComponent(signInfo.inputInfo, spendingTx, prevOutMap) val oldSig = - TransactionSignatureCreator.createSig(txSignatureComponent, - signer.sign(_), - signInfo.hashType) + TransactionSignatureCreator.createSig( + txSignatureComponent, + signer.sign(_), + signInfo.hashType + ) val newSig = - TransactionSignatureCreator.createSig(spendingTx, - signInfo, - signer.sign(_), - signInfo.hashType) + TransactionSignatureCreator.createSig( + spendingTx, + signInfo, + signer.sign(_), + signInfo.hashType + ) (oldSig.r == newSig.r) && (oldSig.s == newSig.s) && @@ -172,37 +198,45 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { TransactionTestUtil.buildCreditingTransaction(scriptPubKey) val scriptSig = EmptyScriptSignature val (spendingTx, inputIndex) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - scriptSig, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + scriptSig, + outputIndex + ) val txSignatureComponent = BaseTxSigComponent( transaction = spendingTx, inputIndex = inputIndex, output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - flags = Policy.standardScriptVerifyFlags) + flags = Policy.standardScriptVerifyFlags + ) val txSignature = - TransactionSignatureCreator.createSig(txSignatureComponent, - privateKey, - HashType.sigHashAll) + TransactionSignatureCreator.createSig( + txSignatureComponent, + privateKey, + HashType.sigHashAll + ) - //add the signature to the scriptSig instead of having an empty scriptSig + // add the signature to the scriptSig instead of having an empty scriptSig val signedScriptSig = P2PKScriptSignature(txSignature) val (signedTx, _) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - signedScriptSig, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + signedScriptSig, + outputIndex + ) val signedTxSigComponent = BaseTxSigComponent( transaction = signedTx, inputIndex = inputIndex, output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - flags = Policy.standardScriptVerifyFlags) + flags = Policy.standardScriptVerifyFlags + ) - //run it through the interpreter + // run it through the interpreter val program = PreExecutionScriptProgram(signedTxSigComponent) val result = ScriptInterpreter.run(program) @@ -219,34 +253,42 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { TransactionTestUtil.buildCreditingTransaction(scriptPubKey) val scriptSig = EmptyScriptSignature val (spendingTx, inputIndex) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - scriptSig, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + scriptSig, + outputIndex + ) val txSignatureComponent = BaseTxSigComponent( transaction = spendingTx, inputIndex = inputIndex, output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) val txSignature = - TransactionSignatureCreator.createSig(txSignatureComponent, - privateKey, - HashType.sigHashAll) + TransactionSignatureCreator.createSig( + txSignatureComponent, + privateKey, + HashType.sigHashAll + ) - //add the signature to the scriptSig instead of having an empty scriptSig + // add the signature to the scriptSig instead of having an empty scriptSig val signedScriptSig = P2PKHScriptSignature(txSignature, publicKey) val (signedTx, _) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - signedScriptSig, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + signedScriptSig, + outputIndex + ) - //run it through the interpreter + // run it through the interpreter val signedTxSigComponent = BaseTxSigComponent( transaction = signedTx, inputIndex = inputIndex, output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) val program = PreExecutionScriptProgram(signedTxSigComponent) val result = ScriptInterpreter.run(program) @@ -262,34 +304,42 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { TransactionTestUtil.buildCreditingTransaction(scriptPubKey) val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature)) val (spendingTx, inputIndex) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - scriptSig, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + scriptSig, + outputIndex + ) val txSignatureComponent = BaseTxSigComponent( transaction = spendingTx, inputIndex = inputIndex, output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) val txSignature = - TransactionSignatureCreator.createSig(txSignatureComponent, - privateKey, - HashType.sigHashAll) + TransactionSignatureCreator.createSig( + txSignatureComponent, + privateKey, + HashType.sigHashAll + ) - //add the signature to the scriptSig instead of having an empty scriptSig + // add the signature to the scriptSig instead of having an empty scriptSig val signedScriptSig = MultiSignatureScriptSignature(Seq(txSignature)) val (signedTx, _) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - signedScriptSig, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + signedScriptSig, + outputIndex + ) val signedTxSigComponent = BaseTxSigComponent( transaction = signedTx, inputIndex = inputIndex, output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardScriptVerifyFlags) - //run it through the interpreter + Policy.standardScriptVerifyFlags + ) + // run it through the interpreter val program = PreExecutionScriptProgram(signedTxSigComponent) val result = ScriptInterpreter.run(program) @@ -308,34 +358,42 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature)) val (spendingTx, inputIndex) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - scriptSig, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + scriptSig, + outputIndex + ) val txSignatureComponent = BaseTxSigComponent( transaction = spendingTx, inputIndex = inputIndex, output = TransactionOutput(CurrencyUnits.zero, redeemScript), - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) val txSignature = - TransactionSignatureCreator.createSig(txSignatureComponent, - privateKey, - HashType.sigHashAll) + TransactionSignatureCreator.createSig( + txSignatureComponent, + privateKey, + HashType.sigHashAll + ) val signedScriptSig = MultiSignatureScriptSignature(Seq(txSignature)) val p2shScriptSig = P2SHScriptSignature(signedScriptSig, redeemScript) val (signedTx, _) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - p2shScriptSig, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + p2shScriptSig, + outputIndex + ) val signedTxSigComponent = BaseTxSigComponent( transaction = signedTx, inputIndex = inputIndex, output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardScriptVerifyFlags) - //run it through the interpreter + Policy.standardScriptVerifyFlags + ) + // run it through the interpreter val program = PreExecutionScriptProgram(signedTxSigComponent) val result = ScriptInterpreter.run(program) result must be(ScriptOk) @@ -351,22 +409,27 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { val scriptSig = MultiSignatureScriptSignature(Seq(EmptyDigitalSignature)) val (spendingTx, inputIndex) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - scriptSig, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + scriptSig, + outputIndex + ) val txSignatureComponent = - BaseTxSigComponent(transaction = spendingTx, - inputIndex = inputIndex, - output = - TransactionOutput(CurrencyUnits.zero, redeemScript), - flags = Policy.standardScriptVerifyFlags) + BaseTxSigComponent( + transaction = spendingTx, + inputIndex = inputIndex, + output = TransactionOutput(CurrencyUnits.zero, redeemScript), + flags = Policy.standardScriptVerifyFlags + ) val sign: ByteVector => Future[ECDigitalSignature] = { bytes: ByteVector => Future(privateKey.sign(bytes)) } @nowarn val txSignature = - TransactionSignatureCreator.createSig(txSignatureComponent, - sign, - HashType.sigHashAll) + TransactionSignatureCreator.createSig( + txSignatureComponent, + sign, + HashType.sigHashAll + ) val signedScriptSig = txSignature.map(sig => MultiSignatureScriptSignature(Seq(sig))) @@ -374,17 +437,20 @@ class TransactionSignatureCreatorTest extends BitcoinSJvmTest { signedScriptSig.map(ss => P2SHScriptSignature(ss, redeemScript)) val signedTxFuture: Future[(Transaction, UInt32)] = p2shScriptSig.map { ss => - TransactionTestUtil.buildSpendingTransaction(creditingTx, - ss, - outputIndex) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + ss, + outputIndex + ) } - //run it through the interpreter + // run it through the interpreter val program = signedTxFuture.map { case (tx, _) => val signedTxSigComponent = BaseTxSigComponent( transaction = tx, inputIndex = inputIndex, output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) PreExecutionScriptProgram(signedTxSigComponent) } diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureSerializerTest.scala index 908bd2a5fb..d524d2c3de 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/TransactionSignatureSerializerTest.scala @@ -22,136 +22,165 @@ import scala.util.Try class TransactionSignatureSerializerTest extends BitcoinSUnitTest { "TransactionSignatureSerializer" must "correctly serialize an input that is being checked where another input in the same tx is using SIGHASH_ANYONECANPAY" in { - //this is from a test case inside of tx_valid.json - //https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L91 + // this is from a test case inside of tx_valid.json + // https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L91 val rawTx = "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000" val inputIndex = UInt32.zero val spendingTx = Transaction(rawTx) val scriptPubKeyFromString = ScriptParser.fromString( - "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG") + "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG" + ) val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString) val txSigComponent = - BaseTxSigComponent(spendingTx, - inputIndex, - TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardFlags) + BaseTxSigComponent( + spendingTx, + inputIndex, + TransactionOutput(CurrencyUnits.zero, scriptPubKey), + Policy.standardFlags + ) val serializedTxForSig: String = BytesUtil.encodeHex( TransactionSignatureSerializer.serializeForSignature( txSigComponent = txSigComponent, hashType = HashType.sigHashAll, - taprootOptions = TaprootSerializationOptions.empty)) + taprootOptions = TaprootSerializationOptions.empty + ) + ) - //serialization is from bitcoin core + // serialization is from bitcoin core serializedTxForSig must be( - "01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac0100000000020000000000000000000000000000000000000000000000000000000000000000000000ffffffff01010000000000000001510000000001000000") + "01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac0100000000020000000000000000000000000000000000000000000000000000000000000000000000ffffffff01010000000000000001510000000001000000" + ) } it must "correctly serialize a tx for signing with multiple inputs using SIGHASH_SINGLE" in { - //this is from a test case inside of tx_valid.json - //https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L96 + // this is from a test case inside of tx_valid.json + // https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L96 val rawTx = "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000" val inputIndex = UInt32.zero val spendingTx = Transaction(rawTx) val scriptPubKeyFromString = ScriptParser.fromString( - "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG") + "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG" + ) val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString) val txSigComponent = - BaseTxSigComponent(spendingTx, - inputIndex, - TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardFlags) + BaseTxSigComponent( + spendingTx, + inputIndex, + TransactionOutput(CurrencyUnits.zero, scriptPubKey), + Policy.standardFlags + ) val serializedTxForSig: String = BytesUtil.encodeHex( TransactionSignatureSerializer - .serializeForSignature(txSigComponent, - HashType.sigHashSingle, - taprootOptions = - TaprootSerializationOptions.empty)) - //serialization is from bitcoin core + .serializeForSignature( + txSigComponent, + HashType.sigHashSingle, + taprootOptions = TaprootSerializationOptions.empty + ) + ) + // serialization is from bitcoin core serializedTxForSig must be( - "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee0100000000000000000180841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac0000000003000000") + "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee0100000000000000000180841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac0000000003000000" + ) } it must "correctly serialize a tx for signing with the last input using SIGHASH_SINGLE" in { - //this is from a test case inside of tx_valid.json - //https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L96 + // this is from a test case inside of tx_valid.json + // https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L96 val rawTx = "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000" val inputIndex = UInt32(2) val spendingTx = Transaction(rawTx) val scriptPubKeyFromString = ScriptParser.fromString( - "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG") + "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG" + ) val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString) val txSigComponent = - BaseTxSigComponent(spendingTx, - inputIndex, - TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardFlags) + BaseTxSigComponent( + spendingTx, + inputIndex, + TransactionOutput(CurrencyUnits.zero, scriptPubKey), + Policy.standardFlags + ) val serializedTxForSig: String = BytesUtil.encodeHex( TransactionSignatureSerializer - .serializeForSignature(txSigComponent, - HashType.sigHashSingle, - taprootOptions = - TaprootSerializationOptions.empty)) - //serialization is from bitcoin core + .serializeForSignature( + txSigComponent, + HashType.sigHashSingle, + taprootOptions = TaprootSerializationOptions.empty + ) + ) + // serialization is from bitcoin core serializedTxForSig must be( - "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf630000000000000000007d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff03ffffffffffffffff00ffffffffffffffff00e0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac0000000003000000") + "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf630000000000000000007d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000000000003f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff03ffffffffffffffff00ffffffffffffffff00e0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac0000000003000000" + ) } it must "correctly serialize a tx which spends an input that pushes using a PUSHDATA1 that is negative when read as signed" in { - //this is from a test case inside of tx_valid.json - //https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L102 + // this is from a test case inside of tx_valid.json + // https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json#L102 val rawTx = "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000" val inputIndex = UInt32.zero val spendingTx = Transaction(rawTx) val scriptPubKeyFromString = ScriptParser.fromString( - "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG") + "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG" + ) val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString) val txSigComponent = - BaseTxSigComponent(spendingTx, - inputIndex, - TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardFlags) + BaseTxSigComponent( + spendingTx, + inputIndex, + TransactionOutput(CurrencyUnits.zero, scriptPubKey), + Policy.standardFlags + ) val serializedTxForSig: String = TransactionSignatureSerializer - .serializeForSignature(txSigComponent, - HashType.sigHashAll, - taprootOptions = - TaprootSerializationOptions.empty) + .serializeForSignature( + txSigComponent, + HashType.sigHashAll, + taprootOptions = TaprootSerializationOptions.empty + ) .toHex - //serialization is from bitcoin core + // serialization is from bitcoin core serializedTxForSig must be( - "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c500000000ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288acffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac0000000001000000") + "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c500000000ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288acffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac0000000001000000" + ) } it must "correctly hash a tx with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature" in { - //this is from a test case inside of tx_invalid.json - //https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L75 + // this is from a test case inside of tx_invalid.json + // https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_invalid.json#L75 val rawTx = "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000" val inputIndex = UInt32.zero val spendingTx = Transaction(rawTx) val scriptPubKeyFromString = ScriptParser.fromString( - "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG") + "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG" + ) val scriptPubKey = ScriptPubKey.fromAsm(scriptPubKeyFromString) val txSigComponent = - BaseTxSigComponent(spendingTx, - inputIndex, - TransactionOutput(CurrencyUnits.zero, scriptPubKey), - Policy.standardFlags) + BaseTxSigComponent( + spendingTx, + inputIndex, + TransactionOutput(CurrencyUnits.zero, scriptPubKey), + Policy.standardFlags + ) val serializedTxForSig: String = TransactionSignatureSerializer - .serializeForSignature(txSigComponent, - HashType.sigHashAll, - taprootOptions = TaprootSerializationOptions.empty) + .serializeForSignature( + txSigComponent, + HashType.sigHashAll, + taprootOptions = TaprootSerializationOptions.empty + ) .toHex serializedTxForSig must be( - "01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac01000000000200000000000000000000000000000000000000000000000000000000000000000000000100000001010000000000000001510000000001000000") + "01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac01000000000200000000000000000000000000000000000000000000000000000000000000000000000100000001010000000000000001510000000001000000" + ) } @@ -164,23 +193,28 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { P2WPKHWitnessSPKV0("1600144c9c3dfac4207d5d8cb89df5722cb3d712385e3f") val amount = Satoshis(2000) val txSigComponent = - WitnessTxSigComponentRaw(wtx, - inputIndex, - TransactionOutput(amount, witScriptPubKey), - Policy.standardFlags) + WitnessTxSigComponentRaw( + wtx, + inputIndex, + TransactionOutput(amount, witScriptPubKey), + Policy.standardFlags + ) val serializedForSig = TransactionSignatureSerializer - .serializeForSignature(txSigComponent, - HashType.sigHashSingleAnyoneCanPay, - taprootOptions = TaprootSerializationOptions.empty) + .serializeForSignature( + txSigComponent, + HashType.sigHashSingleAnyoneCanPay, + taprootOptions = TaprootSerializationOptions.empty + ) .toHex serializedForSig must be( - "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88acd007000000000000ffffffff2d793f9722ac8cbea9b2e0a2929cda4007b8312c6ec3b997088439e48e7aa64e0000000083000000") + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88acd007000000000000ffffffff2d793f9722ac8cbea9b2e0a2929cda4007b8312c6ec3b997088439e48e7aa64e0000000083000000" + ) } it must "work with the p2sh(p2wpkh) example in BIP143" in { - //https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#p2sh-p2wpkh + // https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#p2sh-p2wpkh val expected = { "01000000" + @@ -196,20 +230,23 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { } val expectedHash = DoubleSha256Digest.fromHex( - "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6") + "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6" + ) val inputIndex = UInt32.zero val p2sh = P2SHScriptPubKey.fromAsmHex( - "a9144733f37cf4db86fbc2efed2500b4f4e49f31202387") + "a9144733f37cf4db86fbc2efed2500b4f4e49f31202387" + ) val redeemScript = P2WPKHWitnessSPKV0.fromAsmHex( - "001479091972186c449eb1ded22b78e40d009bdf0089") + "001479091972186c449eb1ded22b78e40d009bdf0089" + ) val amount = Bitcoins(10) val output = TransactionOutput(amount, p2sh) - //https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#p2sh-p2wpkh + // https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#p2sh-p2wpkh val unsignedTx = "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000" @@ -219,30 +256,38 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val oldInput = ubtx.inputs(inputIndex.toInt) - val updatedInput = TransactionInput(oldInput.previousOutput, - p2shScriptSig, - oldInput.sequence) + val updatedInput = TransactionInput( + oldInput.previousOutput, + p2shScriptSig, + oldInput.sequence + ) val updatedInputs = ubtx.inputs.updated(inputIndex.toInt, updatedInput) val witness = EmptyWitness.fromInputs(updatedInputs) - val uwtx = WitnessTransaction(version = ubtx.version, - inputs = updatedInputs, - outputs = ubtx.outputs, - lockTime = ubtx.lockTime, - witness = witness) + val uwtx = WitnessTransaction( + version = ubtx.version, + inputs = updatedInputs, + outputs = ubtx.outputs, + lockTime = ubtx.lockTime, + witness = witness + ) val wtxSigComp = { - WitnessTxSigComponentP2SH(transaction = uwtx, - inputIndex = inputIndex, - output = output, - flags = Policy.standardFlags) + WitnessTxSigComponentP2SH( + transaction = uwtx, + inputIndex = inputIndex, + output = output, + flags = Policy.standardFlags + ) } val serialized = TransactionSignatureSerializer - .serializeForSignature(txSigComponent = wtxSigComp, - hashType = HashType.sigHashAll, - taprootOptions = TaprootSerializationOptions.empty) + .serializeForSignature( + txSigComponent = wtxSigComp, + hashType = HashType.sigHashAll, + taprootOptions = TaprootSerializationOptions.empty + ) .toHex serialized must be(expected) @@ -250,13 +295,14 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val hash = TransactionSignatureSerializer.hashForSignature( txSigComponent = wtxSigComp, hashType = HashType.sigHashAll, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) hash must be(expectedHash) } it must "serialize the BIP143 p2sh(p2wsh) examples" in { - //https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#p2sh-p2wsh + // https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#p2sh-p2wsh val unsignedTx = "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000ffffffff" + @@ -270,39 +316,48 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val bitcoins = Bitcoins(9.87654321) val p2wsh = P2WSHWitnessSPKV0.fromAsmHex( - "0020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54") + "0020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54" + ) val p2shSPK = P2SHScriptPubKey.fromAsmHex( - "a9149993a429037b5d912407a71c252019287b8d27a587") + "a9149993a429037b5d912407a71c252019287b8d27a587" + ) val p2shScriptSig = P2SHScriptSignature(witnessScriptPubKey = p2wsh) val oldInput = ubtx.inputs(inputIndex.toInt) - val updatedInput = TransactionInput(oldInput.previousOutput, - p2shScriptSig, - oldInput.sequence) + val updatedInput = TransactionInput( + oldInput.previousOutput, + p2shScriptSig, + oldInput.sequence + ) val updatedInputs = ubtx.inputs.updated(inputIndex.toInt, updatedInput) val m = MultiSignatureScriptPubKey.fromAsmHex( - "56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae") + "56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae" + ) val witnessScript = P2WSHWitnessV0(m) val txWit = TransactionWitness(Vector(witnessScript)) - val uwtx = WitnessTransaction(ubtx.version, - updatedInputs, - ubtx.outputs, - ubtx.lockTime, - txWit) + val uwtx = WitnessTransaction( + ubtx.version, + updatedInputs, + ubtx.outputs, + ubtx.lockTime, + txWit + ) val output = TransactionOutput(bitcoins, p2shSPK) val wtxSigComp = { - WitnessTxSigComponentP2SH(transaction = uwtx, - inputIndex = inputIndex, - output = output, - flags = Policy.standardFlags) + WitnessTxSigComponentP2SH( + transaction = uwtx, + inputIndex = inputIndex, + output = output, + flags = Policy.standardFlags + ) } val expectedSerialization = @@ -311,11 +366,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val serialization = TransactionSignatureSerializer.serializeForSignature( txSigComponent = wtxSigComp, hashType = HashType.sigHashAll, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) serialization.toHex must be(expectedSerialization) - //with a SIGHASH_NONE + // with a SIGHASH_NONE val expectedSigHashNone = "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000002000000" @@ -324,11 +380,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { TransactionSignatureSerializer.serializeForSignature( txSigComponent = wtxSigComp, hashType = HashType.sigHashNone, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) serializationSigHashNone.toHex must be(expectedSigHashNone) - //with sighash single + // with sighash single val expectedSigHashSingle = "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000003000000" @@ -337,7 +394,8 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { TransactionSignatureSerializer.serializeForSignature( txSigComponent = wtxSigComp, hashType = HashType.sigHashSingle, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) serializationSigHashSingle.toHex must be(expectedSigHashSingle) @@ -348,10 +406,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { TransactionSignatureSerializer.serializeForSignature( txSigComponent = wtxSigComp, hashType = HashType.sigHashAllAnyoneCanPay, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) serializationSigHashAllAnyoneCanPay.toHex must be( - expectedSigHashAllAnyoneCanPay) + expectedSigHashAllAnyoneCanPay + ) val expectedSigHashNoneAnyoneCanPay = "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000082000000" @@ -360,11 +420,13 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { TransactionSignatureSerializer.serializeForSignature( txSigComponent = wtxSigComp, hashType = HashType.sigHashNoneAnyoneCanPay, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) } serializationSigHashNoneAnyoneCanPay.toHex must be( - expectedSigHashNoneAnyoneCanPay) + expectedSigHashNoneAnyoneCanPay + ) val expectedSigHashSingleAnyoneCanPay = "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e01000000cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56aeb168de3a00000000ffffffff9efe0c13a6b16c14a41b04ebe6a63f419bdacb2f8705b494a43063ca3cd4f7080000000083000000" @@ -372,11 +434,13 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { TransactionSignatureSerializer.serializeForSignature( txSigComponent = wtxSigComp, hashType = HashType.sigHashSingleAnyoneCanPay, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) } serializationSigHashSingleAnyoneCanPay.toHex must be( - expectedSigHashSingleAnyoneCanPay) + expectedSigHashSingleAnyoneCanPay + ) } @@ -387,34 +451,41 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val inputIndex = UInt32.zero val p2wsh = P2WSHWitnessSPKV0.fromAsmHex( - "00209e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19") + "00209e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19" + ) val amount = Satoshis(200000) val output = TransactionOutput(amount, p2wsh) - //OP_CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> + // OP_CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> val redeemScript = NonStandardScriptPubKey.fromAsmHex( - "ad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01") + "ad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01" + ) val scriptWit = P2WSHWitnessV0(redeemScript) val txWit = TransactionWitness(Vector(scriptWit)) - val uwtx = WitnessTransaction(ubtx.version, - ubtx.inputs, - ubtx.outputs, - ubtx.lockTime, - txWit) + val uwtx = WitnessTransaction( + ubtx.version, + ubtx.inputs, + ubtx.outputs, + ubtx.lockTime, + txWit + ) val wtxSigCompRaw = { - WitnessTxSigComponentRaw(transaction = uwtx, - inputIndex = inputIndex, - output = output, - flags = Policy.standardFlags) + WitnessTxSigComponentRaw( + transaction = uwtx, + inputIndex = inputIndex, + output = output, + flags = Policy.standardFlags + ) } val serialized = TransactionSignatureSerializer.serializeForSignature( txSigComponent = wtxSigCompRaw, hashType = HashType.sigHashAll, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) val expectedSerialization = "01000000b67c76d200c6ce72962d919dc107884b9d5d0e26f2aea7474b46a1904c53359f3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504469c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d00004aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01400d030000000000ffffffffe5d196bfb21caca9dbd654cafb3b4dc0c4882c8927d2eb300d9539dd0b9342280000000001000000" @@ -438,10 +509,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val fee = SatoshisPerVirtualByte(Satoshis(100)) val spendingTx = StandardNonInteractiveFinalizer - .txFrom(outputs = destinations, - utxos = creditingTxsInfo, - feeRate = fee, - changeSPK = changeSPK) + .txFrom( + outputs = destinations, + utxos = creditingTxsInfo, + feeRate = fee, + changeSPK = changeSPK + ) val prevOutMap = PreviousOutputMap.fromScriptSignatureParams(creditingTxsInfo) @@ -456,14 +529,16 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { TransactionSignatureSerializer.serializeForSignature( txSigComponent, signInfo.hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) val newBytes = TransactionSignatureSerializer.serializeForSignature( spendingTx, signInfo, signInfo.hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) oldBytes == newBytes } @@ -479,10 +554,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val fee = SatoshisPerVirtualByte(Satoshis(100)) val spendingTx = StandardNonInteractiveFinalizer - .txFrom(outputs = destinations, - utxos = creditingTxsInfo, - feeRate = fee, - changeSPK = changeSPK) + .txFrom( + outputs = destinations, + utxos = creditingTxsInfo, + feeRate = fee, + changeSPK = changeSPK + ) val prevOutMap = PreviousOutputMap.fromScriptSignatureParams(creditingTxsInfo) @@ -497,14 +574,16 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { TransactionSignatureSerializer.hashForSignature( txSigComponent, signInfo.hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) val newHash = TransactionSignatureSerializer.hashForSignature( spendingTx, signInfo, signInfo.hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) oldHash == newHash } @@ -520,10 +599,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val fee = SatoshisPerVirtualByte(Satoshis(100)) val spendingTx = StandardNonInteractiveFinalizer - .txFrom(outputs = destinations, - utxos = creditingTxsInfo, - feeRate = fee, - changeSPK = changeSPK) + .txFrom( + outputs = destinations, + utxos = creditingTxsInfo, + feeRate = fee, + changeSPK = changeSPK + ) val prevOutMap = PreviousOutputMap.fromScriptSignatureParams(creditingTxsInfo) @@ -537,13 +618,15 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val oldScript = BitcoinScriptUtil.calculateScriptForSigning( txSigComponent, - txSigComponent.output.scriptPubKey.asm) + txSigComponent.output.scriptPubKey.asm + ) val newScript = BitcoinScriptUtil.calculateScriptForSigning( spendingTx, signInfo, - signInfo.output.scriptPubKey.asm) + signInfo.output.scriptPubKey.asm + ) oldScript == newScript } @@ -571,20 +654,24 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val outputMap: PreviousOutputMap = PreviousOutputMap( - spendingTx.inputs.map(_.previousOutput).zip(Vector(prevOutput)).toMap) + spendingTx.inputs.map(_.previousOutput).zip(Vector(prevOutput)).toMap + ) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, - inputIndex, - outputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, + inputIndex, + outputMap, + Policy.standardFlags + ) val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashNone, - //keypath doesn't use the tapscript tree - taprootOptions = TaprootSerializationOptions.empty) + // keypath doesn't use the tapscript tree + taprootOptions = TaprootSerializationOptions.empty + ) - //generated from: https://github.com/Christewart/bitcoin/tree/2022-06-12-taproot-sig-serialization - //command to run it: DIR_UNIT_TEST_DATA=/home/chris/dev/bitcoin-s/core-test/.jvm/src/test/resources ./src/test/test_bitcoin --run_test=script_tests/script_assets_test + // generated from: https://github.com/Christewart/bitcoin/tree/2022-06-12-taproot-sig-serialization + // command to run it: DIR_UNIT_TEST_DATA=/home/chris/dev/bitcoin-s/core-test/.jvm/src/test/resources ./src/test/test_bitcoin --run_test=script_tests/script_assets_test val expected = "0002f705d6e805406346214cba8933db55eb868be9a32446d8c1a96a0fbb20ab184f4d6199b4f0355a5670646bb1b064d5cba210cc2b4c335874223c44a3efea5a465e80dd202c0356595f2625da12f1a7711bc1a16f9c9021d4b18b925c02a0b2aea05e43a38536cccf2eed245a04e82b3c153c4253d628f837e619e8ee21f76f6d11f8e45782debb6a0000000000" @@ -594,7 +681,8 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { TransactionSignatureSerializer.hashForSignature( txSigComponent = taprootTxSigComponent, hashType = HashType.sigHashNone, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) assert(serialize.toHex == expected) assert(hash.hex == expectedHash) } @@ -627,20 +715,25 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val outputMap: PreviousOutputMap = PreviousOutputMap( - spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap) + spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap + ) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, - inputIndex, - outputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, + inputIndex, + outputMap, + Policy.standardFlags + ) val leafHash = Sha256Digest.fromHex( - "8d76c657582b87b087f36579a9ea78816d7e2a94098bc3e3c6113ed4b6315bb4") + "8d76c657582b87b087f36579a9ea78816d7e2a94098bc3e3c6113ed4b6315bb4" + ) val taprootOptions = TaprootSerializationOptions(Some(leafHash), None, None) val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashNone, - taprootOptions) + taprootOptions + ) val expected = "000226dc279d4a08671ec49b9ed79ac5ddae54b41edb90d86bf61adc5366f7e569cb742c46f6a0452d0f2293f7596a74fc91f3471ca363a2" + @@ -660,11 +753,13 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val spendingTx = Transaction.fromHex(spendingTxHex) val inputIndex = UInt32.zero val prevout = TransactionOutput.fromHex( - "5ba3440100000000225120325901f5659ff9031572e5f790166d9efbc9c693daa47d4acd2ba873176d7879") + "5ba3440100000000225120325901f5659ff9031572e5f790166d9efbc9c693daa47d4acd2ba873176d7879" + ) val prevOutputs = Vector(prevout) val outputMap: PreviousOutputMap = PreviousOutputMap( - spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap) + spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap + ) val witnessStackHex = Vector( "de7950201305f38c82b1f9743b1cecbc0dda2ea4557c1ff22b769666e12539302a0988cd0e1489b8123c1181e275b576fe8ea7c4a997d332bcf90a5dc6604a2701", @@ -703,20 +798,24 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .toWitnessTx(spendingTx) .updateWitness(inputIndex.toInt, witness) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, - inputIndex, - outputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, + inputIndex, + outputMap, + Policy.standardFlags + ) val leafHash = Sha256Digest.fromHex( - "0c013c8aa4ee2a624a516c877892db854d6ccc9fd1cd8b94895cff88abaccbc6") + "0c013c8aa4ee2a624a516c877892db854d6ccc9fd1cd8b94895cff88abaccbc6" + ) val taprootOptions = TaprootSerializationOptions(Some(leafHash), None, None) val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashAll, - taprootOptions) + taprootOptions + ) assert(serialize.toHex == expected) } @@ -727,11 +826,13 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val spendingTx = Transaction.fromHex(spendingTxHex) val inputIndex = UInt32.zero val prevout = TransactionOutput.fromHex( - "0aab5f01000000002251204aeed300fcf09260e6c44f6680f5f0eff387e6c4594700358dae78e695aafbe0") + "0aab5f01000000002251204aeed300fcf09260e6c44f6680f5f0eff387e6c4594700358dae78e695aafbe0" + ) val prevOutputs = Vector(prevout) val outputMap: PreviousOutputMap = PreviousOutputMap( - spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap) + spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap + ) val witnessStackHex = Vector( "ce51561684cec9066e9a4f336fcf7d8a5e6386be8196bbbd283ff95f8a6dc3a3c06468b66640b0d46d2a03836250d23dff5286a98b9d7db760754289238b181701", @@ -749,24 +850,29 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .toWitnessTx(spendingTx) .updateWitness(inputIndex.toInt, witness) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, - inputIndex, - outputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, + inputIndex, + outputMap, + Policy.standardFlags + ) val expected = "0001fff6a5bef6000000808b524996f052e920857d3ee62dc9a6160b403cfcef0d2d03073e47a8871b6adc0a61e1e5fe3f77ae9a3b77a839068254192f52a55e557867aac49c8436c22c6c327e7aab9f14bfb15549767a609af732876f93dac0aab5d94f15cb5341b23a9f5a4670a9fb185fdc4c0c846835c824e40d8fcdc14f75f910ca82ce5fc1290d63628cb6889362ecf4d6c48063afdabdd9307d0638967e263e2badd09c6f9aa9030000000071795496bb62e1315323528edbc764523cec139391ab634e956558cc7fcb570ba719f64a128792e8150c63c71d6e26182e239571885f63404cb8719223adbbf800ffffffff" val leafHash = Sha256Digest.fromHex( - "a719f64a128792e8150c63c71d6e26182e239571885f63404cb8719223adbbf8") + "a719f64a128792e8150c63c71d6e26182e239571885f63404cb8719223adbbf8" + ) val annexHash = Sha256Digest.fromHex( - "71795496bb62e1315323528edbc764523cec139391ab634e956558cc7fcb570b") + "71795496bb62e1315323528edbc764523cec139391ab634e956558cc7fcb570b" + ) val taprootOptions = TaprootSerializationOptions(Some(leafHash), Some(annexHash), None) val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashAll, - taprootOptions) + taprootOptions + ) assert(serialize.toHex == expected) } @@ -780,11 +886,13 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val spendingTx = Transaction.fromHex(spendingTxHex) val inputIndex = UInt32.zero val prevout = TransactionOutput.fromHex( - "5e6aae010000000022512045cad6b20c81a782892f064caeab47cad9c276a917bed28ac30435e343a82188") + "5e6aae010000000022512045cad6b20c81a782892f064caeab47cad9c276a917bed28ac30435e343a82188" + ) val prevOutputs = Vector(prevout) val outputMap: PreviousOutputMap = PreviousOutputMap( - spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap) + spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap + ) val witnessStackHex = Vector( "2c6347f19bd72e40ff0d3ffcb872973ead3100bd0dc39d2dc48d31bb039e0f281f24c963404922771ef28ec09ec6f3875dca076f8ebc0c59d99cfa3e0eafdf0483", @@ -801,10 +909,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .toWitnessTx(spendingTx) .updateWitness(inputIndex.toInt, witness) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, - inputIndex, - outputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, + inputIndex, + outputMap, + Policy.standardFlags + ) val leafHashHex = "6757e0866b83772c944df11581616b8752bb2596a43c8941de0e427ce4fa0630" @@ -814,7 +924,8 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashDefault, - taprootOptions) + taprootOptions + ) assert(serialize.toHex == expected) } @@ -828,11 +939,13 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val spendingTx = Transaction.fromHex(spendingTxHex) val inputIndex = UInt32.zero val prevout = TransactionOutput.fromHex( - "5e6aae010000000022512045cad6b20c81a782892f064caeab47cad9c276a917bed28ac30435e343a82188") + "5e6aae010000000022512045cad6b20c81a782892f064caeab47cad9c276a917bed28ac30435e343a82188" + ) val prevOutputs = Vector(prevout) val outputMap: PreviousOutputMap = PreviousOutputMap( - spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap) + spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap + ) val witnessStackHex = Vector( "2c6347f19bd72e40ff0d3ffcb872973ead3100bd0dc39d2dc48d31bb039e0f281f24c963404922771ef28ec09ec6f3875dca076f8ebc0c59d99cfa3e0eafdf0483", @@ -849,10 +962,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .toWitnessTx(spendingTx) .updateWitness(inputIndex.toInt, witness) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, - inputIndex, - outputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, + inputIndex, + outputMap, + Policy.standardFlags + ) val leafHashHex = "6757e0866b83772c944df11581616b8752bb2596a43c8941de0e427ce4fa0630" @@ -862,7 +977,8 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashSingleAnyoneCanPay, - taprootOptions) + taprootOptions + ) assert(serialize.toHex == expected) } @@ -876,7 +992,8 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val spendingTx = Transaction.fromHex(spendingTxHex) val inputIndex = UInt32.zero val prevout = TransactionOutput.fromHex( - "a84e940100000000160014d3165d2dcffd0c2461e33ee2de0ef4810e1630ec") + "a84e940100000000160014d3165d2dcffd0c2461e33ee2de0ef4810e1630ec" + ) val witnessStackHex = Vector( "304402201ed30e9c471f4feca0557f353b7bacd5ace564ba9de5d51a0fff206468ddbb0602207dc60f5109b2bd3c80f5f79ffa7532a38e7e31a6583e355d83e1e355093d88c858", @@ -898,17 +1015,20 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .updateWitness(inputIndex.toInt, witness) val taprootTxSigComponent = - WitnessTxSigComponentRaw(witnessTx, - inputIndex, - prevout, - Policy.standardFlags) + WitnessTxSigComponentRaw( + witnessTx, + inputIndex, + prevout, + Policy.standardFlags + ) val taprootOptions = TaprootSerializationOptions.empty val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, hashType, - taprootOptions) + taprootOptions + ) assert(serialize.toHex == expected) } @@ -928,10 +1048,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .map(TransactionOutput.fromHex) val outputMap: PreviousOutputMap = PreviousOutputMap( - spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap) + spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap + ) val witnessStackHex = Vector( - "85b5c1a31fda48328459aec83811bfd5754a24110c3fb7026500561e4880f313fbdb44125ca7e06f3a37490e1fcd0d9383ff970ff7b7f724a9df7dca8cf17d4d03") + "85b5c1a31fda48328459aec83811bfd5754a24110c3fb7026500561e4880f313fbdb44125ca7e06f3a37490e1fcd0d9383ff970ff7b7f724a9df7dca8cf17d4d03" + ) val witnessStack = witnessStackHex.map(w => ByteVector.fromValidHex(w)) val witness = TaprootWitness.fromStack(witnessStack.reverse) @@ -941,17 +1063,20 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .toWitnessTx(spendingTx) .updateWitness(inputIndex.toInt, witness) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, - inputIndex, - outputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, + inputIndex, + outputMap, + Policy.standardFlags + ) val taprootOptions = TaprootSerializationOptions.empty val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashSingle, - taprootOptions) + taprootOptions + ) assert(serialize.toHex == expected) } @@ -965,11 +1090,13 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val spendingTx = Transaction.fromHex(spendingTxHex) val inputIndex = UInt32.zero val prevout = TransactionOutput.fromHex( - "bd2897010000000022512088ffcb569bf1dc1a9e0b22b8cb164c31bcf65e6e95fa113ddbdbbead6e85fedf") + "bd2897010000000022512088ffcb569bf1dc1a9e0b22b8cb164c31bcf65e6e95fa113ddbdbbead6e85fedf" + ) val prevOutputs = Vector(prevout) val outputMap: PreviousOutputMap = PreviousOutputMap( - spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap) + spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap + ) val witnessStackHex = Vector( "f14afc2bf9b4a9f8e4b5e8503e396de9ad12aacf7726fd53dc147978f52bf9435d658cb326f533b39c57af2c8406f5177120eda69e51f52e0fd076040c7d831d83", "50d8" @@ -983,22 +1110,27 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .toWitnessTx(spendingTx) .updateWitness(inputIndex.toInt, witness) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, - inputIndex, - outputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, + inputIndex, + outputMap, + Policy.standardFlags + ) val annexHashHex = "b0d1ad766994166c07455739e8a49adf25972a25046ede7f1573ec61b75beb3f" val annexHash = Sha256Digest.fromHex(annexHashHex) val taprootOptions = - TaprootSerializationOptions(tapLeafHashOpt = None, - annexHashOpt = Some(annexHash), - codeSeparatorPosOpt = None) + TaprootSerializationOptions( + tapLeafHashOpt = None, + annexHashOpt = Some(annexHash), + codeSeparatorPosOpt = None + ) val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashSingleAnyoneCanPay, - taprootOptions) + taprootOptions + ) assert(serialize.toHex == expected) } @@ -1012,13 +1144,16 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val spendingTx = Transaction.fromHex(spendingTxHex) val inputIndex = UInt32.zero val prevout = TransactionOutput.fromHex( - "94037f010000000022512057c1162a56ec9db80a8eb342634f613c8d990bf305925df7ddb85b356ce8f0bb") + "94037f010000000022512057c1162a56ec9db80a8eb342634f613c8d990bf305925df7ddb85b356ce8f0bb" + ) val prevOutputs = Vector(prevout) val outputMap: PreviousOutputMap = PreviousOutputMap( - spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap) + spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap + ) val witnessStackHex = Vector( - "228187c314a903fe94c1c8260c243e0949a3233d404a58f90cd991a44f5dad4d89bd5763525b437a10a973abd8eb99adcfec9e2865fa235fa4d6af82c427f17a81") + "228187c314a903fe94c1c8260c243e0949a3233d404a58f90cd991a44f5dad4d89bd5763525b437a10a973abd8eb99adcfec9e2865fa235fa4d6af82c427f17a81" + ) val witnessStack = witnessStackHex.map(w => ByteVector.fromValidHex(w)) val witness = TaprootKeyPath.fromStack(witnessStack.reverse) @@ -1028,17 +1163,20 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .toWitnessTx(spendingTx) .updateWitness(inputIndex.toInt, witness) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, - inputIndex, - outputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, + inputIndex, + outputMap, + Policy.standardFlags + ) val taprootOptions = TaprootSerializationOptions.empty val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashAllAnyoneCanPay, - taprootOptions) + taprootOptions + ) assert(serialize.toHex == expected) } @@ -1052,7 +1190,8 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val spendingTx = Transaction.fromHex(spendingTxHex) val inputIndex = UInt32.zero val prevout = TransactionOutput.fromHex( - "bf72520100000000225120b38f5c375c5df5852727048cd6d2769430afedabafa5897df1636cb87fecc14f") + "bf72520100000000225120b38f5c375c5df5852727048cd6d2769430afedabafa5897df1636cb87fecc14f" + ) val prevOutputs = Vector(prevout) val outputMap: Map[TransactionOutPoint, TransactionOutput] = spendingTx.inputs.map(_.previousOutput).zip(prevOutputs).toMap @@ -1070,10 +1209,12 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { .toWitnessTx(spendingTx) .updateWitness(inputIndex.toInt, witness) - val taprootTxSigComponent = TaprootTxSigComponent(witnessTx, //spendingTx, - inputIndex, - prevOutputMap, - Policy.standardFlags) + val taprootTxSigComponent = TaprootTxSigComponent( + witnessTx, // spendingTx, + inputIndex, + prevOutputMap, + Policy.standardFlags + ) val annexHashHex = "eee244e957e1df84bc631fa02a0b7d0ef2fea17e7f5aad4a2aaa50a6aca16eee" @@ -1083,7 +1224,8 @@ class TransactionSignatureSerializerTest extends BitcoinSUnitTest { val serialize = TransactionSignatureSerializer.serializeForSignature( taprootTxSigComponent, HashType.sigHashSingle, - taprootOptions) + taprootOptions + ) assert(serialize.toHex == expected) } diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/TxSigComponentTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/TxSigComponentTest.scala index fae04ec5a2..0258e9d7bd 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/TxSigComponentTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/TxSigComponentTest.scala @@ -23,21 +23,27 @@ class TxSigComponentTest extends BitcoinSUnitTest { Vector( TransactionInput( TransactionOutPoint(DoubleSha256Digest.empty, UInt32.zero), - P2SHScriptSignature(scriptSig = - ConditionalScriptSignature(EmptyScriptSignature, - condition = true), - redeemScript = P2WPKHWitnessSPKV0(pubKey)), + P2SHScriptSignature( + scriptSig = ConditionalScriptSignature( + EmptyScriptSignature, + condition = true + ), + redeemScript = P2WPKHWitnessSPKV0(pubKey) + ), TransactionConstants.sequence - )), + ) + ), Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)), UInt32.zero ) val nonWitnessP2SH = - P2SHTxSigComponent(btx, - UInt32.zero, - TransactionOutput(Satoshis.one, p2shNoNest), - Policy.standardFlags) + P2SHTxSigComponent( + btx, + UInt32.zero, + TransactionOutput(Satoshis.one, p2shNoNest), + Policy.standardFlags + ) assert(!nonWitnessP2SH.isInstanceOf[WitnessTxSigComponentP2SH]) } @@ -53,18 +59,22 @@ class TxSigComponentTest extends BitcoinSUnitTest { TransactionOutPoint(DoubleSha256Digest.empty, UInt32.zero), P2SHScriptSignature(wspk), TransactionConstants.sequence - )), + ) + ), Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)), UInt32.zero, TransactionWitness( - Vector(P2WPKHWitnessV0(pubKey, DummyECDigitalSignature))) + Vector(P2WPKHWitnessV0(pubKey, DummyECDigitalSignature)) + ) ) val witnessP2SH = - P2SHTxSigComponent(wtx, - UInt32.zero, - TransactionOutput(Satoshis.one, p2shNested), - Policy.standardFlags) + P2SHTxSigComponent( + wtx, + UInt32.zero, + TransactionOutput(Satoshis.one, p2shNested), + Policy.standardFlags + ) assert(witnessP2SH.isInstanceOf[WitnessTxSigComponentP2SH]) } diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/WIFEncodingTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/WIFEncodingTest.scala index 33923dc2a8..a667ca998d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/WIFEncodingTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/WIFEncodingTest.scala @@ -44,23 +44,28 @@ class WIFEncodingTest extends BitcoinSUnitTest { it must "correctly decode a private key from WIF" in { val privateKey = ECPrivateKeyUtil.fromWIFToPrivateKey( - "cTPg4Zc5Jis2EZXy3NXShgbn487GWBTapbU63BerLDZM3w2hQSjC") - //derived hex on bitcore's playground + "cTPg4Zc5Jis2EZXy3NXShgbn487GWBTapbU63BerLDZM3w2hQSjC" + ) + // derived hex on bitcore's playground privateKey.hex must be( - "ad59fb6aadf617fb0f93469741fcd9a9f48700f1d1f465ddc0f26fa7f7bfa1ac") + "ad59fb6aadf617fb0f93469741fcd9a9f48700f1d1f465ddc0f26fa7f7bfa1ac" + ) } it must "decode a WIF private key corresponding to uncompressed public key" in { val wif = "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C" val privKey = ECPrivateKeyUtil.fromWIFToPrivateKey(wif) privKey.publicKeyBytes.hex must be( - "045b81f0017e2091e2edcd5eecf10d5bdd120a5514cb3ee65b8447ec18bfc4575c6d5bf415e54e03b1067934a0f0ba76b01c6b9ab227142ee1d543764b69d901e0") + "045b81f0017e2091e2edcd5eecf10d5bdd120a5514cb3ee65b8447ec18bfc4575c6d5bf415e54e03b1067934a0f0ba76b01c6b9ab227142ee1d543764b69d901e0" + ) } it must "have serialization symmetry for WIF format" in { - forAll(CryptoGenerators.privateKey, - ChainParamsGenerator.networkParams, - NumberGenerator.bool) { (privKey, network, compressed) => + forAll( + CryptoGenerators.privateKey, + ChainParamsGenerator.networkParams, + NumberGenerator.bool + ) { (privKey, network, compressed) => val wif = ECPrivateKeyUtil.toWIF(privKey.toPrivateKeyBytes(compressed), network) assert(ECPrivateKeyUtil.isCompressed(wif) == compressed) @@ -72,21 +77,27 @@ class WIFEncodingTest extends BitcoinSUnitTest { } assert( ECPrivateKeyUtil.fromWIFToPrivateKey(wif) == privKey.toPrivateKeyBytes( - compressed)) + compressed + ) + ) } } it must "have serialization symmetry for WIF format when private key ends in 0x01" in { val privKey = ECPrivateKey( - "710ed6c96012015f02e352cddd6f5a5b32499f2926ac7752b57d93b38be8c701") + "710ed6c96012015f02e352cddd6f5a5b32499f2926ac7752b57d93b38be8c701" + ) val wif = - ECPrivateKeyUtil.toWIF(privKey.toPrivateKeyBytes(isCompressed = false), - TestNet3) + ECPrivateKeyUtil.toWIF( + privKey.toPrivateKeyBytes(isCompressed = false), + TestNet3 + ) assert(!ECPrivateKeyUtil.isCompressed(wif)) assert(ECPrivateKeyUtil.parseNetworkFromWIF(wif).get == TestNet3) assert( ECPrivateKeyUtil.fromWIFToPrivateKey(wif) == privKey - .toPrivateKeyBytes(isCompressed = false)) + .toPrivateKeyBytes(isCompressed = false) + ) } it must "fail to parse unknown WIF networks" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/crypto/bip32/BIP32PathTest.scala b/core-test/src/test/scala/org/bitcoins/core/crypto/bip32/BIP32PathTest.scala index 4f281a41b8..a2a078146e 100644 --- a/core-test/src/test/scala/org/bitcoins/core/crypto/bip32/BIP32PathTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/crypto/bip32/BIP32PathTest.scala @@ -80,7 +80,8 @@ class BIP32PathTest extends BitcoinSUnitTest { (path, char) => val badPathString = char.toString + path.toString.drop(1) assertThrows[IllegalArgumentException]( - BIP32Path.fromString(badPathString)) + BIP32Path.fromString(badPathString) + ) } } @@ -104,14 +105,20 @@ class BIP32PathTest extends BitcoinSUnitTest { it must "parse the paths from the BIP32 test vectors" in { val expected1 = BIP32Path( - Vector(BIP32Node(0, hardenedOpt = HardenedType.defaultOpt), - BIP32Node(1, hardenedOpt = None))) + Vector( + BIP32Node(0, hardenedOpt = HardenedType.defaultOpt), + BIP32Node(1, hardenedOpt = None) + ) + ) assert(BIP32Path.fromString("m/0'/1") == expected1) val expected2 = BIP32Path( - Vector(BIP32Node(0, hardenedOpt = HardenedType.defaultOpt), - BIP32Node(1, hardenedOpt = None), - BIP32Node(2, hardenedOpt = HardenedType.defaultOpt))) + Vector( + BIP32Node(0, hardenedOpt = HardenedType.defaultOpt), + BIP32Node(1, hardenedOpt = None), + BIP32Node(2, hardenedOpt = HardenedType.defaultOpt) + ) + ) assert(BIP32Path.fromString("m/0'/1/2'") == expected2) val expected3 = BIP32Path( @@ -120,7 +127,8 @@ class BIP32PathTest extends BitcoinSUnitTest { BIP32Node(1, hardenedOpt = None), BIP32Node(2, hardenedOpt = HardenedType.defaultOpt), BIP32Node(2, hardenedOpt = None) - )) + ) + ) assert(BIP32Path.fromString("m/0'/1/2'/2") == expected3) val expected4 = BIP32Path( @@ -130,20 +138,27 @@ class BIP32PathTest extends BitcoinSUnitTest { BIP32Node(2, hardenedOpt = HardenedType.defaultOpt), BIP32Node(2, hardenedOpt = None), BIP32Node(1000000000, hardenedOpt = None) - )) + ) + ) assert(BIP32Path.fromString("m/0'/1/2'/2/1000000000") == expected4) } it must "parse the paths from the BIP32 test vector from bytes" in { val expected1 = BIP32Path( - Vector(BIP32Node(0, hardenedOpt = HardenedType.defaultOpt), - BIP32Node(1, hardenedOpt = None))) + Vector( + BIP32Node(0, hardenedOpt = HardenedType.defaultOpt), + BIP32Node(1, hardenedOpt = None) + ) + ) assert(BIP32Path.fromBytes(hex"0x8000000000000001") == expected1) val expected2 = BIP32Path( - Vector(BIP32Node(0, hardenedOpt = HardenedType.defaultOpt), - BIP32Node(1, hardenedOpt = None), - BIP32Node(2, hardenedOpt = HardenedType.defaultOpt))) + Vector( + BIP32Node(0, hardenedOpt = HardenedType.defaultOpt), + BIP32Node(1, hardenedOpt = None), + BIP32Node(2, hardenedOpt = HardenedType.defaultOpt) + ) + ) assert(BIP32Path.fromBytes(hex"0x800000000000000180000002") == expected2) val expected3 = BIP32Path( @@ -152,9 +167,11 @@ class BIP32PathTest extends BitcoinSUnitTest { BIP32Node(1, hardenedOpt = None), BIP32Node(2, hardenedOpt = HardenedType.defaultOpt), BIP32Node(2, hardenedOpt = None) - )) + ) + ) assert( - BIP32Path.fromBytes(hex"0x80000000000000018000000200000002") == expected3) + BIP32Path.fromBytes(hex"0x80000000000000018000000200000002") == expected3 + ) val expected4 = BIP32Path( Vector( @@ -163,9 +180,12 @@ class BIP32PathTest extends BitcoinSUnitTest { BIP32Node(2, hardenedOpt = HardenedType.defaultOpt), BIP32Node(2, hardenedOpt = None), BIP32Node(1000000000, hardenedOpt = None) - )) - assert(BIP32Path - .fromBytes(hex"0x800000000000000180000002000000023B9ACA00") == expected4) + ) + ) + assert( + BIP32Path + .fromBytes(hex"0x800000000000000180000002000000023B9ACA00") == expected4 + ) } it must "have fromString and toString symmetry" in { @@ -243,7 +263,7 @@ class BIP32PathTest extends BitcoinSUnitTest { val bip32Path = BIP32Path.fromHardenedString(string) assert(bip32Path.toString == string) - //bad paths + // bad paths val badPath1 = "m/1/2'/3'/4'/5'" assertThrows[IllegalArgumentException] { BIP32Path.fromHardenedString(badPath1) diff --git a/core-test/src/test/scala/org/bitcoins/core/currency/CurrencyUnitTest.scala b/core-test/src/test/scala/org/bitcoins/core/currency/CurrencyUnitTest.scala index 6a52548d22..12b1a68c86 100644 --- a/core-test/src/test/scala/org/bitcoins/core/currency/CurrencyUnitTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/currency/CurrencyUnitTest.scala @@ -209,7 +209,8 @@ class CurrencyUnitTest extends BitcoinSUnitTest { assert( CurrencyUnits .parseString("12345678900") - .contains(Satoshis(12345678900L))) + .contains(Satoshis(12345678900L)) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/dlc/DLCAdaptorPointComputerTest.scala b/core-test/src/test/scala/org/bitcoins/core/dlc/DLCAdaptorPointComputerTest.scala index 2c36bd5fd6..cef9244aa4 100644 --- a/core-test/src/test/scala/org/bitcoins/core/dlc/DLCAdaptorPointComputerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/dlc/DLCAdaptorPointComputerTest.scala @@ -13,25 +13,32 @@ class DLCAdaptorPointComputerTest extends BitcoinSJvmTest with DLCTest { runTestsForParam(Vector((1, 1), (2, 3), (3, 5))) { case (threshold, numOracles) => runTestsForParam( - Vector(None, - Some( - OracleParamsV0TLV(numDigitsOrOutcomes / 2 + 1, - numDigitsOrOutcomes / 2, - maximizeCoverage = true)))) { - oracleParams => - val contractParams = SingleContractParams(numDigitsOrOutcomes, - isNumeric, - threshold, - numOracles, - oracleParams) - val (client, _, _) = constructDLCClients(contractParams) - val contract = client.offer.contractInfo - val outcomes = contract.allOutcomes + Vector( + None, + Some( + OracleParamsV0TLV( + numDigitsOrOutcomes / 2 + 1, + numDigitsOrOutcomes / 2, + maximizeCoverage = true + ) + ) + ) + ) { oracleParams => + val contractParams = SingleContractParams( + numDigitsOrOutcomes, + isNumeric, + threshold, + numOracles, + oracleParams + ) + val (client, _, _) = constructDLCClients(contractParams) + val contract = client.offer.contractInfo + val outcomes = contract.allOutcomes - val adaptorPoints = contract.adaptorPoints - val expectedAdaptorPoints = outcomes.map(_.sigPoint) + val adaptorPoints = contract.adaptorPoints + val expectedAdaptorPoints = outcomes.map(_.sigPoint) - assert(adaptorPoints == expectedAdaptorPoints) + assert(adaptorPoints == expectedAdaptorPoints) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/dlc/DLCValidationTest.scala b/core-test/src/test/scala/org/bitcoins/core/dlc/DLCValidationTest.scala index d748cd8266..7aed8a15f5 100644 --- a/core-test/src/test/scala/org/bitcoins/core/dlc/DLCValidationTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/dlc/DLCValidationTest.scala @@ -30,11 +30,13 @@ class DLCValidationTest extends BitcoinSJvmTest with DLCTest { assert( offerClient.dlcTxSigner .completeFundingTx(badAcceptFundingSigs) - .isFailure) + .isFailure + ) assert( acceptClient.dlcTxSigner .completeFundingTx(badOfferFundingSigs) - .isFailure) + .isFailure + ) assert(offerVerifier.verifyRemoteFundingSigs(acceptFundingSigs)) assert(acceptVerifier.verifyRemoteFundingSigs(offerFundingSigs)) @@ -60,17 +62,26 @@ class DLCValidationTest extends BitcoinSJvmTest with DLCTest { val acceptRefundSig = acceptClient.dlcTxSigner.signRefundTx outcomes.zipWithIndex.foreach { case (outcomeUncast, index) => - val outcome = EnumOracleOutcome(Vector( - offerClient.offer.oracleInfos.head - .asInstanceOf[EnumSingleOracleInfo]), - outcomeUncast.asInstanceOf[EnumOutcome]) + val outcome = EnumOracleOutcome( + Vector( + offerClient.offer.oracleInfos.head + .asInstanceOf[EnumSingleOracleInfo] + ), + outcomeUncast.asInstanceOf[EnumOutcome] + ) assert( - offerVerifier.verifyCETSig(Indexed(outcome.sigPoint, index), - acceptCETSigs(outcome.sigPoint))) + offerVerifier.verifyCETSig( + Indexed(outcome.sigPoint, index), + acceptCETSigs(outcome.sigPoint) + ) + ) assert( - acceptVerifier.verifyCETSig(Indexed(outcome.sigPoint, index), - offerCETSigs(outcome.sigPoint))) + acceptVerifier.verifyCETSig( + Indexed(outcome.sigPoint, index), + offerCETSigs(outcome.sigPoint) + ) + ) } assert(offerVerifier.verifyRefundSig(acceptRefundSig)) assert(offerVerifier.verifyRefundSig(offerRefundSig)) @@ -109,14 +120,17 @@ class DLCValidationTest extends BitcoinSJvmTest with DLCTest { offerClient.dlcTxSigner.completeCET( oracleOutcome, badAcceptCETSigs(oracleOutcome.sigPoint), - Vector(oracleSig)) + Vector(oracleSig) + ) } assertThrows[RuntimeException] { acceptClient.dlcTxSigner - .completeCET(oracleOutcome, - badOfferCETSigs(oracleOutcome.sigPoint), - Vector(oracleSig)) + .completeCET( + oracleOutcome, + badOfferCETSigs(oracleOutcome.sigPoint), + Vector(oracleSig) + ) } } @@ -129,24 +143,39 @@ class DLCValidationTest extends BitcoinSJvmTest with DLCTest { } outcomes.zipWithIndex.foreach { case (outcomeUncast, index) => - val outcome = EnumOracleOutcome(Vector( - offerClient.offer.oracleInfos.head - .asInstanceOf[EnumSingleOracleInfo]), - outcomeUncast.asInstanceOf[EnumOutcome]) + val outcome = EnumOracleOutcome( + Vector( + offerClient.offer.oracleInfos.head + .asInstanceOf[EnumSingleOracleInfo] + ), + outcomeUncast.asInstanceOf[EnumOutcome] + ) assert( - !offerVerifier.verifyCETSig(Indexed(outcome.sigPoint, index), - badAcceptCETSigs(outcome.sigPoint))) + !offerVerifier.verifyCETSig( + Indexed(outcome.sigPoint, index), + badAcceptCETSigs(outcome.sigPoint) + ) + ) assert( - !acceptVerifier.verifyCETSig(Indexed(outcome.sigPoint, index), - badOfferCETSigs(outcome.sigPoint))) + !acceptVerifier.verifyCETSig( + Indexed(outcome.sigPoint, index), + badOfferCETSigs(outcome.sigPoint) + ) + ) assert( - !offerVerifier.verifyCETSig(Indexed(outcome.sigPoint, index), - offerCETSigs(outcome.sigPoint))) + !offerVerifier.verifyCETSig( + Indexed(outcome.sigPoint, index), + offerCETSigs(outcome.sigPoint) + ) + ) assert( - !acceptVerifier.verifyCETSig(Indexed(outcome.sigPoint, index), - acceptCETSigs(outcome.sigPoint))) + !acceptVerifier.verifyCETSig( + Indexed(outcome.sigPoint, index), + acceptCETSigs(outcome.sigPoint) + ) + ) } assert(!offerVerifier.verifyRefundSig(badAcceptRefundSig)) assert(!offerVerifier.verifyRefundSig(badOfferRefundSig)) diff --git a/core-test/src/test/scala/org/bitcoins/core/dlc/DisjointUnionDLCTest.scala b/core-test/src/test/scala/org/bitcoins/core/dlc/DisjointUnionDLCTest.scala index 8fe20ab42f..8cbb408885 100644 --- a/core-test/src/test/scala/org/bitcoins/core/dlc/DisjointUnionDLCTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/dlc/DisjointUnionDLCTest.scala @@ -27,13 +27,17 @@ class DisjointUnionDLCTest extends BitcoinSJvmTest with DLCTest { val numDisjoint = 2 val numDigits = 10 val singleParams = 0.until(numDisjoint).toVector.map { _ => - val oracleParams = OracleParamsV0TLV(maxErrorExp = 6, - minFailExp = 2, - maximizeCoverage = true) - NumericContractParams(numDigits, - oracleThreshold = 1, - numOracles = 1, - Some(oracleParams)) + val oracleParams = OracleParamsV0TLV( + maxErrorExp = 6, + minFailExp = 2, + maximizeCoverage = true + ) + NumericContractParams( + numDigits, + oracleThreshold = 1, + numOracles = 1, + Some(oracleParams) + ) } val contractParams = DisjointUnionContractParams(singleParams) val outcomes = 0.until(numDisjoint).toVector.flatMap { contractIndex => @@ -50,14 +54,18 @@ class DisjointUnionDLCTest extends BitcoinSJvmTest with DLCTest { val numDigits = 10 val enumParams = EnumContractParams(numOutcomes, oracleThreshold = 1, numOracles = 1) - val oracleParams = OracleParamsV0TLV(maxErrorExp = 6, - minFailExp = 2, - maximizeCoverage = true) + val oracleParams = OracleParamsV0TLV( + maxErrorExp = 6, + minFailExp = 2, + maximizeCoverage = true + ) val numericParams = - NumericContractParams(numDigits, - oracleThreshold = 1, - numOracles = 1, - Some(oracleParams)) + NumericContractParams( + numDigits, + oracleThreshold = 1, + numOracles = 1, + Some(oracleParams) + ) val contractParams = DisjointUnionContractParams(Vector(enumParams, numericParams)) diff --git a/core-test/src/test/scala/org/bitcoins/core/dlc/EnumDLCTest.scala b/core-test/src/test/scala/org/bitcoins/core/dlc/EnumDLCTest.scala index fb3dadd833..cdb873bae9 100644 --- a/core-test/src/test/scala/org/bitcoins/core/dlc/EnumDLCTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/dlc/EnumDLCTest.scala @@ -66,14 +66,17 @@ class EnumDLCTest extends BitcoinSJvmTest with DLCTest { dlcOffer.offer.contractInfo.contracts.head, outcomes, outcomeIndex, - paramsOpt = None) + paramsOpt = None + ) - assertCorrectSigDerivation(offerSetup = offerSetup, - dlcOffer = dlcOffer, - acceptSetup = acceptSetup, - dlcAccept = dlcAccept, - oracleSigs = sigs, - outcome = oracleOutcome) + assertCorrectSigDerivation( + offerSetup = offerSetup, + dlcOffer = dlcOffer, + acceptSetup = acceptSetup, + dlcAccept = dlcAccept, + oracleSigs = sigs, + outcome = oracleOutcome + ) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/dlc/NumericDLCTest.scala b/core-test/src/test/scala/org/bitcoins/core/dlc/NumericDLCTest.scala index ec7577eb41..4e9771db78 100644 --- a/core-test/src/test/scala/org/bitcoins/core/dlc/NumericDLCTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/dlc/NumericDLCTest.scala @@ -34,7 +34,7 @@ class NumericDLCTest extends BitcoinSJvmTest with DLCTest { val numDigits = if (EnvUtil.isNativeSecp256k1Disabled) { 12 } else { - //optimization for CI, tests are much slower when secp256k1 isnt used + // optimization for CI, tests are much slower when secp256k1 isnt used 17 } val contractParams = @@ -48,9 +48,11 @@ class NumericDLCTest extends BitcoinSJvmTest with DLCTest { val threshold = 3 val numOracles = 5 val numDigits = 8 - val params = OracleParamsV0TLV(maxErrorExp = 4, - minFailExp = 2, - maximizeCoverage = false) + val params = OracleParamsV0TLV( + maxErrorExp = 4, + minFailExp = 2, + maximizeCoverage = false + ) val contractParams = NumericContractParams(numDigits, threshold, numOracles, Some(params)) val nums = tenRandomNums(numDigits) @@ -77,11 +79,16 @@ class NumericDLCTest extends BitcoinSJvmTest with DLCTest { runTestsForParam(Vector((1, 1), (2, 2), (2, 3))) { case (threshold, numOracles) => val oracleParamOptsToTest = if (threshold > 1) { - Vector(None, - Some( - OracleParamsV0TLV(numDigits - 2, - numDigits - 4, - maximizeCoverage = false))) + Vector( + None, + Some( + OracleParamsV0TLV( + numDigits - 2, + numDigits - 4, + maximizeCoverage = false + ) + ) + ) } else Vector(None) runTestsForParam(oracleParamOptsToTest) { oracleParamsOpt => val max = (1L << numDigits) - 1 @@ -90,10 +97,12 @@ class NumericDLCTest extends BitcoinSJvmTest with DLCTest { .toVector .map(num => (max / num.toDouble).toLong) .map(num => NumberUtil.decompose(num, 2, numDigits)) - val contractParams = NumericContractParams(numDigits, - threshold, - numOracles, - oracleParamsOpt) + val contractParams = NumericContractParams( + numDigits, + threshold, + numOracles, + oracleParamsOpt + ) constructAndSetupDLC(contractParams).flatMap { case (dlcOffer, offerSetup, dlcAccept, acceptSetup, outcomes) => @@ -115,19 +124,23 @@ class NumericDLCTest extends BitcoinSJvmTest with DLCTest { .sorted val oracleOutcome = - genNumericOracleOutcome(chosenOracles, - dlcOffer.offer.contractInfo, - outcome.digits, - oracleParamsOpt) + genNumericOracleOutcome( + chosenOracles, + dlcOffer.offer.contractInfo, + outcome.digits, + oracleParamsOpt + ) val oracleSigs = genNumericOracleSignatures(oracleOutcome) - assertCorrectSigDerivation(offerSetup = offerSetup, - dlcOffer = dlcOffer, - acceptSetup = acceptSetup, - dlcAccept = dlcAccept, - oracleSigs = oracleSigs, - outcome = oracleOutcome) + assertCorrectSigDerivation( + offerSetup = offerSetup, + dlcOffer = dlcOffer, + acceptSetup = acceptSetup, + dlcAccept = dlcAccept, + oracleSigs = oracleSigs, + outcome = oracleOutcome + ) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/dlc/SetupDLCTest.scala b/core-test/src/test/scala/org/bitcoins/core/dlc/SetupDLCTest.scala index 5393d84bb1..4a3534a2ac 100644 --- a/core-test/src/test/scala/org/bitcoins/core/dlc/SetupDLCTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/dlc/SetupDLCTest.scala @@ -24,7 +24,8 @@ class SetupDLCTest extends BitcoinSJvmTest { ) val validFundingTx: WitnessTransaction = WitnessTransaction( - "02000000000102f6ec63ebf8589895147803ea2724f1cc9fbcc75077136c15af57210ab8b4342b0000000000ffffffffbfeda85fa8d2335694b3602f0e0918fa7e9d144051217330c8a0328b4d0caabd0000000000ffffffff03c8c2eb0b0000000022002060b1a927da5c8570b1280d6dd0306d6458edc1c4abb7cc3ce8f75d157e78825e1ee0f50500000000160014558979e57695d211a354b87369ae819ae720e2761ee0f50500000000160014dc93c91963fb7b42860f92caf11217ef6c28599702483045022100b9189d799cdc4845b273ff4a471fcaa36e2419609bc3e749d78668bb8c2cb1350220403cdcddf10d06b8cb36e2943d1c8d195cbc0b023d1cdaa29281dfa250a744a9012103f5413f7d813a4e1bff925fa8b1e6ce154b309d6df4433cc1c6ded5e04f4d2d6202473044022001d25acb7ad50c352604a36d20fa25426d98d9d917200b017c052954ddf97e43022005b6d6c70d029206851c5af7ac3013fda87d5536003b0eee1c29cac6903cfbbd0121039ef319718ac70f4a3e86fb4eab23adc1c41dda9109f6c700b9b06690ddb3138b00000000") + "02000000000102f6ec63ebf8589895147803ea2724f1cc9fbcc75077136c15af57210ab8b4342b0000000000ffffffffbfeda85fa8d2335694b3602f0e0918fa7e9d144051217330c8a0328b4d0caabd0000000000ffffffff03c8c2eb0b0000000022002060b1a927da5c8570b1280d6dd0306d6458edc1c4abb7cc3ce8f75d157e78825e1ee0f50500000000160014558979e57695d211a354b87369ae819ae720e2761ee0f50500000000160014dc93c91963fb7b42860f92caf11217ef6c28599702483045022100b9189d799cdc4845b273ff4a471fcaa36e2419609bc3e749d78668bb8c2cb1350220403cdcddf10d06b8cb36e2943d1c8d195cbc0b023d1cdaa29281dfa250a744a9012103f5413f7d813a4e1bff925fa8b1e6ce154b309d6df4433cc1c6ded5e04f4d2d6202473044022001d25acb7ad50c352604a36d20fa25426d98d9d917200b017c052954ddf97e43022005b6d6c70d029206851c5af7ac3013fda87d5536003b0eee1c29cac6903cfbbd0121039ef319718ac70f4a3e86fb4eab23adc1c41dda9109f6c700b9b06690ddb3138b00000000" + ) val validCET: WitnessTransaction = WitnessTransaction( "0200000000010112eb723473aa9ec2a91d82072b054feb4660389dc33ec407ff5836ff1ade73490000000000feffffff029014680300000000160014f161d1f494c1617a385f4480687b49826b5287ec70ad830800000000160014ea0f8ed8de8f6190bc67a2cf19f75bea97d0d582014752210258d139dc2f0507bd2b01794ff04530fd614a86dded69fd944da1942bcf748a7e2103eaf8df8e339381a19dfa5e37a4ce3c04ad3dc62f8d57774d92154e6d26ef06a452ae7c37265f" @@ -33,7 +34,8 @@ class SetupDLCTest extends BitcoinSJvmTest { val validCETInfo: CETInfo = CETInfo(validCET, dummyAdaptorSig) val validRefundTx: WitnessTransaction = WitnessTransaction( - "0200000000010112eb723473aa9ec2a91d82072b054feb4660389dc33ec407ff5836ff1ade73490000000000feffffff02ace0f50500000000160014f161d1f494c1617a385f4480687b49826b5287ecabe0f50500000000160014ea0f8ed8de8f6190bc67a2cf19f75bea97d0d582040047304402206e204681682139ca91abca8a090c05d335c3077bcaa801d73ade4d30cf14befc0220114da42320f563f8df7ba29bfb26549b58b4dfc40d8af3a8e352b2da180fa9f001483045022100a9aa4a45d89d936762041cc2793700c3c6228326648a66228c4e265c9938337c0220024637e716c702176bde6029342ac42118a1af774ca6fb7a8225a31b15b1c839014752210258d139dc2f0507bd2b01794ff04530fd614a86dded69fd944da1942bcf748a7e2103eaf8df8e339381a19dfa5e37a4ce3c04ad3dc62f8d57774d92154e6d26ef06a452ae7d37265f") + "0200000000010112eb723473aa9ec2a91d82072b054feb4660389dc33ec407ff5836ff1ade73490000000000feffffff02ace0f50500000000160014f161d1f494c1617a385f4480687b49826b5287ecabe0f50500000000160014ea0f8ed8de8f6190bc67a2cf19f75bea97d0d582040047304402206e204681682139ca91abca8a090c05d335c3077bcaa801d73ade4d30cf14befc0220114da42320f563f8df7ba29bfb26549b58b4dfc40d8af3a8e352b2da180fa9f001483045022100a9aa4a45d89d936762041cc2793700c3c6228326648a66228c4e265c9938337c0220024637e716c702176bde6029342ac42118a1af774ca6fb7a8225a31b15b1c839014752210258d139dc2f0507bd2b01794ff04530fd614a86dded69fd944da1942bcf748a7e2103eaf8df8e339381a19dfa5e37a4ce3c04ad3dc62f8d57774d92154e6d26ef06a452ae7d37265f" + ) // These 2 can be the same, we only need them to have 1 input so we can do the correct checks val invalidCET: WitnessTransaction = WitnessTransaction( @@ -45,19 +47,27 @@ class SetupDLCTest extends BitcoinSJvmTest { val oracleInfo: EnumSingleOracleInfo = EnumSingleOracleInfo.dummyForKeys( ECPrivateKey.freshPrivateKey, ECPublicKey.freshPublicKey.schnorrNonce, - Vector(EnumOutcome("WIN"), EnumOutcome("LOSE"))) + Vector(EnumOutcome("WIN"), EnumOutcome("LOSE")) + ) def setupDLC( fundingTx: Transaction = validFundingTx, cet0: CETInfo = validCETInfo, cet1: CETInfo = validCETInfo, - refundTx: WitnessTransaction = validRefundTx): SetupDLC = { + refundTx: WitnessTransaction = validRefundTx + ): SetupDLC = { SetupDLC( fundingTx = fundingTx, - cets = Vector(EnumOracleOutcome(Vector(oracleInfo), - EnumOutcome("WIN")).sigPoint -> cet0, - EnumOracleOutcome(Vector(oracleInfo), - EnumOutcome("LOSE")).sigPoint -> cet1), + cets = Vector( + EnumOracleOutcome( + Vector(oracleInfo), + EnumOutcome("WIN") + ).sigPoint -> cet0, + EnumOracleOutcome( + Vector(oracleInfo), + EnumOutcome("LOSE") + ).sigPoint -> cet1 + ), refundTx = refundTx ) } @@ -65,16 +75,20 @@ class SetupDLCTest extends BitcoinSJvmTest { it must "not allow an invalid number of inputs for CETs" in { // Funding tx has more than 1 input assertThrows[IllegalArgumentException]( - setupDLC(cet0 = validCETInfo.copy(tx = validFundingTx))) + setupDLC(cet0 = validCETInfo.copy(tx = validFundingTx)) + ) assertThrows[IllegalArgumentException]( - setupDLC(cet1 = validCETInfo.copy(tx = validFundingTx))) + setupDLC(cet1 = validCETInfo.copy(tx = validFundingTx)) + ) } it must "not allow an invalid input for CETs" in { assertThrows[IllegalArgumentException]( - setupDLC(cet0 = validCETInfo.copy(tx = invalidCET))) + setupDLC(cet0 = validCETInfo.copy(tx = invalidCET)) + ) assertThrows[IllegalArgumentException]( - setupDLC(cet1 = validCETInfo.copy(tx = invalidCET))) + setupDLC(cet1 = validCETInfo.copy(tx = invalidCET)) + ) } it must "not allow an invalid number of inputs for the refundTx" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/dlc/accounting/DLCAccountingTest.scala b/core-test/src/test/scala/org/bitcoins/core/dlc/accounting/DLCAccountingTest.scala index e16f989dea..999d87413e 100644 --- a/core-test/src/test/scala/org/bitcoins/core/dlc/accounting/DLCAccountingTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/dlc/accounting/DLCAccountingTest.scala @@ -9,7 +9,7 @@ class DLCAccountingTest extends BitcoinSUnitTest { it must "calculate basic pnl where we win all funds" in { val myCollateral = Satoshis(50000) - val theirCollateral = myCollateral //symmetrical collateral + val theirCollateral = myCollateral // symmetrical collateral val accounting1 = DLCAccounting( dlcId = Sha256Digest.empty, @@ -19,14 +19,14 @@ class DLCAccountingTest extends BitcoinSUnitTest { theirPayout = Satoshis.zero ) - //we make 50,000 sats (their collateral) is the profit + // we make 50,000 sats (their collateral) is the profit assert(accounting1.pnl == theirCollateral) assert(accounting1.rorPrettyPrint == "100.00%") } it must "calculate basic pnl where we lose all funds" in { val myCollateral = Satoshis(50000) - val theirCollateral = myCollateral //symmetrical collateral + val theirCollateral = myCollateral // symmetrical collateral val accounting1 = DLCAccounting( dlcId = Sha256Digest.empty, @@ -36,7 +36,7 @@ class DLCAccountingTest extends BitcoinSUnitTest { theirPayout = myCollateral + theirCollateral ) - //we lose 50,000 sats (my collateral) is the loss + // we lose 50,000 sats (my collateral) is the loss assert(accounting1.pnl == -myCollateral) assert(accounting1.rateOfReturn == -1) assert(accounting1.rorPrettyPrint == "-100.00%") @@ -44,7 +44,7 @@ class DLCAccountingTest extends BitcoinSUnitTest { it must "calculate basic pnl where funds are refunded" in { val myCollateral = Satoshis(50000) - val theirCollateral = myCollateral //symmetrical collateral + val theirCollateral = myCollateral // symmetrical collateral val accounting1 = DLCAccounting( dlcId = Sha256Digest.empty, @@ -54,7 +54,7 @@ class DLCAccountingTest extends BitcoinSUnitTest { theirPayout = theirCollateral ) - //collateral refunded, so no pnl + // collateral refunded, so no pnl assert(accounting1.pnl == Satoshis.zero) assert(accounting1.rateOfReturn == 0) assert(accounting1.rorPrettyPrint == "0.00%") diff --git a/core-test/src/test/scala/org/bitcoins/core/dlc/models/OracleInfoTest.scala b/core-test/src/test/scala/org/bitcoins/core/dlc/models/OracleInfoTest.scala index 12901ec57f..77d3dad778 100644 --- a/core-test/src/test/scala/org/bitcoins/core/dlc/models/OracleInfoTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/dlc/models/OracleInfoTest.scala @@ -16,8 +16,8 @@ class OracleInfoTest extends BitcoinSUnitTest { behavior of "OracleInfo" it must "verify a numeric oracle signature with nonces out of order" in { - //see: https://github.com/bitcoin-s/bitcoin-s/issues/4808 - //see: https://oracle.suredbits.com/announcement/10827916922327c9e13e28b1b0338a0cf5e4d067909d95a9c9aec11f7ccace8d + // see: https://github.com/bitcoin-s/bitcoin-s/issues/4808 + // see: https://oracle.suredbits.com/announcement/10827916922327c9e13e28b1b0338a0cf5e4d067909d95a9c9aec11f7ccace8d val announcementHex = "fdd824fd02d455abcf3b585c9729e92e13c9762c4adc9c6062be721ae217a8aac0ff92a73e837231809bf6f6b75192d665b301c0f4011f247bdc00c8752e524d65baeb1c3deb04ba9838623f02c940d20d7b185d410178cff7990c7fcf19186c7f58c7c4b8defdd822fd026e0012218b59ec12cb8b221e00ef6d3b88a19650b3fb99ea3b6d0f9ef8c356741347c16319d4bfa31978500f32876c6adbc18bee655f35dc97fa4824cf0775981542b96e658c9c5d257576db17d454806b6bd366c26bedf1ae358e1715377449b23c39afed7b41274028982c274bd01b799b35db36a6b31c10211dc05fe3cd3b059099361ecb7be6d7351aa516bea56a6100b4c2635da049c6252f94a0e117055314793c550569820e6687fbd5a60e80d7e026bf1d6f6afffd0d0778da023727d5f5b7aae45e2b8848539fe3485bcd64b58556d2a60d10e74e1ec541d5871f012960a669415a50ed291b4d9e50cc695ff0458573acda2881aa00f50fbe48a59f5f518416022bd073bea49df9940cbeb97fcdd2fe13957bc410950d0c9e971d6a6da197e5090d9821785e7b756ec56dc059b65d2fd3fa8f02595cd292ec10c0ca680e36ea89a62deb71fce778e0a603ed345adf03c3bc55e3d85c211aea3a15aee67fabe1e3081736280e3b54037e8ab5211bf9e8e27b61656f597843dc7be6464705e341e2a6b2fa96df10fd569c62d04dd9515cf1cf452e76c4f5147c125e0b5a5a54af141f492423370c9b41bc9259e4d9cc35553252d71fcc0c37c6f025afb1b11503499fa5f6f7dae9378ec1f8f749836e23f40326209194ab2779b6069f74cb562d1fbd83a7c7147549d866c3c71e0dade3e1d74dee457cbd3fcac11be8e71ce6039b3a9b60e3a4c707d725e2e43a456c4cdfe272ac1a63ac0cde984d81469903d9420c2902de121e9104126c89ab589698208926360bf052b84a4cb6504f4da763355080fdd80a100002000642544355534400000000001213446572696269742d4254432d32395345503232" val attestmentHex = @@ -29,8 +29,10 @@ class OracleInfoTest extends BitcoinSUnitTest { val digits = Vector(0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1) val outcome = UnsignedNumericOutcome(digits) val oracleSigs = - NumericOracleSignaturesUnsorted(numericOracleInfo, - attestment.unsortedSignatures) + NumericOracleSignaturesUnsorted( + numericOracleInfo, + attestment.unsortedSignatures + ) assert(numericOracleInfo.verifySigs(outcome, oracleSigs)) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/gcs/BlockFilterTest.scala b/core-test/src/test/scala/org/bitcoins/core/gcs/BlockFilterTest.scala index 8201c1870d..9378c8535d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/gcs/BlockFilterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/gcs/BlockFilterTest.scala @@ -26,8 +26,10 @@ class BlockFilterTest extends BitcoinSUnitTest { def runTest(): org.scalatest.Assertion = { val constructedFilter = BlockFilter(block, prevOutputScripts) - assert(constructedFilter.encodedData.bytes == filter.encodedData.bytes, - clue) + assert( + constructedFilter.encodedData.bytes == filter.encodedData.bytes, + clue + ) val matcher = new BinarySearchFilterMatcher(filter) val constructedMatcher = new BinarySearchFilterMatcher(constructedFilter) @@ -42,7 +44,7 @@ class BlockFilterTest extends BitcoinSUnitTest { object Bip158TestCase { - //["Block Height,Block Hash,Block,[Prev Output Scripts for Block],Previous Basic Header,Basic Filter,Basic Header,Notes"] + // ["Block Height,Block Hash,Block,[Prev Output Scripts for Block],Previous Basic Header,Basic Filter,Basic Header,Notes"] def fromArr(array: Arr): Bip158TestCase = { val parseResult = for { height <- array(0).numOpt.map(_.toInt) @@ -64,14 +66,16 @@ class BlockFilterTest extends BitcoinSUnitTest { header <- array(6).strOpt.map(DoubleSha256DigestBE.fromHex) notes <- array(7).strOpt - } yield Bip158TestCase(height, - blockHash, - block, - scripts, - prevHeader, - filter, - header, - notes) + } yield Bip158TestCase( + height, + blockHash, + block, + scripts, + prevHeader, + filter, + header, + notes + ) parseResult.get } diff --git a/core-test/src/test/scala/org/bitcoins/core/gcs/FilterTypeTest.scala b/core-test/src/test/scala/org/bitcoins/core/gcs/FilterTypeTest.scala index fa458374d2..5bce9caca1 100644 --- a/core-test/src/test/scala/org/bitcoins/core/gcs/FilterTypeTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/gcs/FilterTypeTest.scala @@ -16,6 +16,7 @@ class FilterTypeTest extends BitcoinSUnitTest { assert(FilterType.byCode(0) == FilterType.Basic) assertThrows[IllegalArgumentException](FilterType.byCode(1)) assertThrows[IllegalArgumentException]( - FilterType.getCode(FilterType.fromHex("ffff"))) + FilterType.getCode(FilterType.fromHex("ffff")) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/gcs/GCSTest.scala b/core-test/src/test/scala/org/bitcoins/core/gcs/GCSTest.scala index ba59fbe08b..44f9c96f48 100644 --- a/core-test/src/test/scala/org/bitcoins/core/gcs/GCSTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/gcs/GCSTest.scala @@ -11,7 +11,7 @@ import scodec.bits.{BinStringSyntax, ByteVector} class GCSTest extends BitcoinSUnitTest { behavior of "GCS" - //https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-rice-coding + // https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-rice-coding it must "encode and decode Golomb Coded Set example 1" in { val p = UInt8(2) val original = UInt64.zero @@ -145,9 +145,9 @@ class GCSTest extends BitcoinSUnitTest { it must "encode and decode an arbitrary item for an arbitrary p" in { def delta: Gen[UInt64] = { - //what is a reasonable delta? This is means the delta - //can be 1 - 16384 - //if we do a full uint64 it takes forever to encode it + // what is a reasonable delta? This is means the delta + // can be 1 - 16384 + // if we do a full uint64 it takes forever to encode it Gen .choose(1, NumberUtil.pow2(14).toInt) .map(UInt64(_)) diff --git a/core-test/src/test/scala/org/bitcoins/core/gcs/GolombFilterTest.scala b/core-test/src/test/scala/org/bitcoins/core/gcs/GolombFilterTest.scala index fbbcc4df0b..215cd62c35 100644 --- a/core-test/src/test/scala/org/bitcoins/core/gcs/GolombFilterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/gcs/GolombFilterTest.scala @@ -69,7 +69,8 @@ class GolombFilterTest extends BitcoinSUnitTest { randHashes.filterNot(hashes.contains) assert( - hashesNotInData.forall(hash => !binarySearchMatcher.matchesHash(hash))) + hashesNotInData.forall(hash => !binarySearchMatcher.matchesHash(hash)) + ) } } @@ -96,7 +97,8 @@ class GolombFilterTest extends BitcoinSUnitTest { hex"38ab2411d13f90d8a1dc0a283adb014680" val blockHash = DoubleSha256Digest.fromHex( - "73668ce5489ca6e42ec893ad406cc7853110ab2d63b52accf700000000000000") + "73668ce5489ca6e42ec893ad406cc7853110ab2d63b52accf700000000000000" + ) BlockFilter.fromBytes(filterBytes, blockHash).bytes must be(filterBytes) } @@ -104,14 +106,17 @@ class GolombFilterTest extends BitcoinSUnitTest { it must "create filer header for a Golomb filter" in { val filterBytes = hex"017fa880" val blockHash = DoubleSha256Digest.fromHex( - "73668ce5489ca6e42ec893ad406cc7853110ab2d63b52accf700000000000000") + "73668ce5489ca6e42ec893ad406cc7853110ab2d63b52accf700000000000000" + ) val filter = BlockFilter.fromBytes(filterBytes, blockHash) filter.bytes must be(filterBytes) val prevHeader = FilterHeader( DoubleSha256Digest.fromHex( - "c03705b2d6fb76a59664f1d63fe8fdbb2dc076d18175fdc51d11c43afaf78a4c"), - DoubleSha256Digest.empty) + "c03705b2d6fb76a59664f1d63fe8fdbb2dc076d18175fdc51d11c43afaf78a4c" + ), + DoubleSha256Digest.empty + ) val header = filter.getHeader(prevHeader = prevHeader) diff --git a/core-test/src/test/scala/org/bitcoins/core/hd/HDAccountTest.scala b/core-test/src/test/scala/org/bitcoins/core/hd/HDAccountTest.scala index 4cc0b955ae..c1a34b38ee 100644 --- a/core-test/src/test/scala/org/bitcoins/core/hd/HDAccountTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/hd/HDAccountTest.scala @@ -26,7 +26,8 @@ class HDAccountTest extends BitcoinSUnitTest { assert( isNotSame, - s"If we drop the last element from the defualt path, we are not in the same account anymore") + s"If we drop the last element from the defualt path, we are not in the same account anymore" + ) } it must "fail if we modify the last element in the path" in { @@ -35,8 +36,10 @@ class HDAccountTest extends BitcoinSUnitTest { val isNotSame = !HDAccount.isSameAccount(modifiedLast, defaultAcct) - assert(isNotSame, - s"We should have the same account if we modify the account index") + assert( + isNotSame, + s"We should have the same account if we modify the account index" + ) } it must "succeed if we add an arbitrary element onto the end of the path" in { @@ -46,7 +49,8 @@ class HDAccountTest extends BitcoinSUnitTest { assert( isSame, - s"If we add an extra element onto the path, we are still in the same account") + s"If we add an extra element onto the path, we are still in the same account" + ) } it must "fail with the empty path" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/hd/HDPathTest.scala b/core-test/src/test/scala/org/bitcoins/core/hd/HDPathTest.scala index 9da9e18ddc..fd481c2aa3 100644 --- a/core-test/src/test/scala/org/bitcoins/core/hd/HDPathTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/hd/HDPathTest.scala @@ -43,7 +43,8 @@ class HDPathTest extends BitcoinSUnitTest { it must "fail to make addresses with neagtives indices" in { forAll(HDGenerators.hdChain, NumberGenerator.negativeInts) { (chain, i) => assertThrows[IllegalArgumentException]( - HDAddress(chain = chain, index = i)) + HDAddress(chain = chain, index = i) + ) } } @@ -71,8 +72,10 @@ class HDPathTest extends BitcoinSUnitTest { it must "correctly represent Bitcoin and Testnet coins" in { HDCoinType.fromInt(0) must be(HDCoinType.Bitcoin) HDCoinType.fromInt(1) must be(HDCoinType.Testnet) - forAll(NumberGenerator.ints.suchThat(i => - !HDCoinType.all.map(_.toInt).contains(i))) { i => + forAll( + NumberGenerator.ints.suchThat(i => + !HDCoinType.all.map(_.toInt).contains(i)) + ) { i => HDCoinType.fromInt(i) must be(HDCoinType.UnknownCoinType(i)) HDCoinType.fromKnown(i) must be(None) } @@ -109,7 +112,8 @@ class HDPathTest extends BitcoinSUnitTest { assert(value == path.asInstanceOf[NestedSegWitHDPath]) } resultOpt.getOrElse( - fail(s"$path did not have toString/fromString symmetry")) + fail(s"$path did not have toString/fromString symmetry") + ) } } @@ -183,7 +187,8 @@ class HDPathTest extends BitcoinSUnitTest { case Success(_) => fail() case Failure(exc) => assert( - exc.getMessage.contains("address index child must not be hardened")) + exc.getMessage.contains("address index child must not be hardened") + ) } } } @@ -339,18 +344,20 @@ class HDPathTest extends BitcoinSUnitTest { // https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki#test-vectors it must "correctly parse the example from BIP84" in { - val words = Vector("abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "about") + val words = Vector( + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "about" + ) val mnemonic = MnemonicCode.fromWords(words) val seed = BIP39Seed.fromMnemonic(mnemonic) val xpriv = seed.toExtPrivateKey(ExtKeyVersion.SegWitMainNetPriv) @@ -358,9 +365,11 @@ class HDPathTest extends BitcoinSUnitTest { assert(ExtPrivateKey.fromStringT("zprvAWgYBB").isFailure) val Success(expectedXpriv) = ExtPrivateKey.fromStringT( - "zprvAWgYBBk7JR8Gjrh4UJQ2uJdG1r3WNRRfURiABBE3RvMXYSrRJL62XuezvGdPvG6GFBZduosCc1YP5wixPox7zhZLfiUm8aunE96BBa4Kei5") + "zprvAWgYBBk7JR8Gjrh4UJQ2uJdG1r3WNRRfURiABBE3RvMXYSrRJL62XuezvGdPvG6GFBZduosCc1YP5wixPox7zhZLfiUm8aunE96BBa4Kei5" + ) val Success(expectedXpub) = ExtPublicKey.fromStringT( - "zpub6jftahH18ngZxLmXaKw3GSZzZsszmt9WqedkyZdezFtWRFBZqsQH5hyUmb4pCEeZGmVfQuP5bedXTB8is6fTv19U1GQRyQUKQGUTzyHACMF") + "zpub6jftahH18ngZxLmXaKw3GSZzZsszmt9WqedkyZdezFtWRFBZqsQH5hyUmb4pCEeZGmVfQuP5bedXTB8is6fTv19U1GQRyQUKQGUTzyHACMF" + ) assert(xpriv == expectedXpriv) assert(xpub == expectedXpub) @@ -375,10 +384,12 @@ class HDPathTest extends BitcoinSUnitTest { val expectedPriv = ECPrivateKeyUtil .fromWIFToPrivateKey( - "KyZpNDKnfs94vbrwhJneDi77V6jF64PWPF8x5cdJb8ifgg2DUc9d") + "KyZpNDKnfs94vbrwhJneDi77V6jF64PWPF8x5cdJb8ifgg2DUc9d" + ) .toPrivateKey val expectedPub = ECPublicKey( - hex"0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c") + hex"0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c" + ) val expectedAddress = Bech32Address.fromString("bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu") @@ -397,10 +408,12 @@ class HDPathTest extends BitcoinSUnitTest { val expectedPriv = ECPrivateKeyUtil .fromWIFToPrivateKey( - "Kxpf5b8p3qX56DKEe5NqWbNUP9MnqoRFzZwHRtsFqhzuvUJsYZCy") + "Kxpf5b8p3qX56DKEe5NqWbNUP9MnqoRFzZwHRtsFqhzuvUJsYZCy" + ) .toPrivateKey val expectedPub = ECPublicKey( - hex"03e775fd51f0dfb8cd865d9ff1cca2a158cf651fe997fdc9fee9c1d3b5e995ea77") + hex"03e775fd51f0dfb8cd865d9ff1cca2a158cf651fe997fdc9fee9c1d3b5e995ea77" + ) val expectedAddress = Bech32Address.fromString("bc1qnjg0jd8228aq7egyzacy8cys3knf9xvrerkf9g") @@ -419,10 +432,12 @@ class HDPathTest extends BitcoinSUnitTest { val expectedPriv = ECPrivateKeyUtil .fromWIFToPrivateKey( - "KxuoxufJL5csa1Wieb2kp29VNdn92Us8CoaUG3aGtPtcF3AzeXvF") + "KxuoxufJL5csa1Wieb2kp29VNdn92Us8CoaUG3aGtPtcF3AzeXvF" + ) .toPrivateKey val expectedPub = ECPublicKey( - hex"03025324888e429ab8e3dbaf1f7802648b9cd01e9b418485c5fa4c1b9b5700e1a6") + hex"03025324888e429ab8e3dbaf1f7802648b9cd01e9b418485c5fa4c1b9b5700e1a6" + ) val expectedAddress = Bech32Address.fromString("bc1q8c6fshw2dlwun7ekn9qwf37cu2rn755upcp6el") @@ -480,7 +495,8 @@ class HDPathTest extends BitcoinSUnitTest { val path = LegacyHDPath.fromString("m/44'/0'/0'/0/0") val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(expectedXpub) = ExtPublicKey.fromStringT( - "xpub6FR8LqriB4qyPvdtZwhHW2HQP4daR2qXsYAAsfaiF8DoFJJ5AqGCpiGM3kFC4Z9AZWnReXrzp2nzhp91myPjz96e3wrJoMvgnCyMBjKz8vJ") + "xpub6FR8LqriB4qyPvdtZwhHW2HQP4daR2qXsYAAsfaiF8DoFJJ5AqGCpiGM3kFC4Z9AZWnReXrzp2nzhp91myPjz96e3wrJoMvgnCyMBjKz8vJ" + ) assert(xpub == expectedXpub) } @@ -491,7 +507,8 @@ class HDPathTest extends BitcoinSUnitTest { val path = LegacyHDPath.fromString("m/44'/0'/0'/0/0") val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(expectedXpub) = ExtPublicKey.fromStringT( - "tpubDFnks5gPtLoRfipk28gNhwcmiBjEQRLbRAkUEDdrb2ygzaxnF47Hy9wBHnKyb46QMRKLG7NsM8d3PzddAqEysaYw7YbcUtavNAZkwjM7aqi") + "tpubDFnks5gPtLoRfipk28gNhwcmiBjEQRLbRAkUEDdrb2ygzaxnF47Hy9wBHnKyb46QMRKLG7NsM8d3PzddAqEysaYw7YbcUtavNAZkwjM7aqi" + ) assert(xpub == expectedXpub) } @@ -502,19 +519,23 @@ class HDPathTest extends BitcoinSUnitTest { val path = NestedSegWitHDPath.fromString("m/49'/0'/0'/0/0") val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(expectedXpub) = ExtPublicKey.fromStringT( - "ypub6c6461WnUp9LoRskZCU3bHBJahDvtrPwCCo1WEtuhsrFGZ8Mn2YMNGab2tj5eujgsMx5U1BZz7hA1q87ZdVSXZdArxM9G5Y9iZchQFrov4q") + "ypub6c6461WnUp9LoRskZCU3bHBJahDvtrPwCCo1WEtuhsrFGZ8Mn2YMNGab2tj5eujgsMx5U1BZz7hA1q87ZdVSXZdArxM9G5Y9iZchQFrov4q" + ) assert(xpub == expectedXpub) } // nested segwit testnet { val rootXpriv = - ExtPrivateKey.fromBIP39Seed(ExtKeyVersion.NestedSegWitTestNet3Priv, - seed) + ExtPrivateKey.fromBIP39Seed( + ExtKeyVersion.NestedSegWitTestNet3Priv, + seed + ) val path = NestedSegWitHDPath.fromString("m/49'/0'/0'/0/0") val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(expectedXpub) = ExtPublicKey.fromStringT( - "upub5JkzsLq7t5yRQF7HDmKYkvoHtpe98NRwXki8NfKNBrLj49sSmPt6t1x2x4tjfH81EoUrU6oL9UGxUgfrgqqPLctmPbZSvSGCdfN7qyMHU7g") + "upub5JkzsLq7t5yRQF7HDmKYkvoHtpe98NRwXki8NfKNBrLj49sSmPt6t1x2x4tjfH81EoUrU6oL9UGxUgfrgqqPLctmPbZSvSGCdfN7qyMHU7g" + ) assert(xpub == expectedXpub) } @@ -525,7 +546,8 @@ class HDPathTest extends BitcoinSUnitTest { val path = SegWitHDPath.fromString("m/84'/0'/0'/0/0") val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(expectedXpub) = ExtPublicKey.fromStringT( - "zpub6vibtacmZKTajuFATBMJPq629qFzaonkAHzWDBEgpHnuhDBozTVWxbF4zJ1Hm4tdkAMJTg9kUqizEz4JQXGkxyotn3MCxbT92mJ8XVcNN5E") + "zpub6vibtacmZKTajuFATBMJPq629qFzaonkAHzWDBEgpHnuhDBozTVWxbF4zJ1Hm4tdkAMJTg9kUqizEz4JQXGkxyotn3MCxbT92mJ8XVcNN5E" + ) assert(xpub == expectedXpub) } @@ -536,7 +558,8 @@ class HDPathTest extends BitcoinSUnitTest { val path = SegWitHDPath.fromString("m/84'/0'/0'/0/0") val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(expectedXpub) = ExtPublicKey.fromStringT( - "vpub5dPYfuw6xbHfLiUh7kCoZUi1TxgCpKpkVqud5bf9JGHPUovtypqGULcWuUAwmSGx7bt5TmmWeCJnhqc3Xjchn35VJgZWcxBBws3Yy6zYa7G") + "vpub5dPYfuw6xbHfLiUh7kCoZUi1TxgCpKpkVqud5bf9JGHPUovtypqGULcWuUAwmSGx7bt5TmmWeCJnhqc3Xjchn35VJgZWcxBBws3Yy6zYa7G" + ) assert(xpub == expectedXpub) } @@ -547,7 +570,8 @@ class HDPathTest extends BitcoinSUnitTest { val path = MultisigHDPath.fromString("m/45'/0'/0'/0/0") val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(expectedXpub) = ExtPublicKey.fromStringT( - "xpub6GqDvL47MZ2baAovXNzG6UuZa7LR37JDG9Qt6nbns4L1q4owu8wnvkiZgTkYgbeyW6EmMjqe5B7TFKb8JvueU9T73pTW4RWf7gEoXFCqMKv") + "xpub6GqDvL47MZ2baAovXNzG6UuZa7LR37JDG9Qt6nbns4L1q4owu8wnvkiZgTkYgbeyW6EmMjqe5B7TFKb8JvueU9T73pTW4RWf7gEoXFCqMKv" + ) assert(xpub == expectedXpub) } @@ -558,7 +582,8 @@ class HDPathTest extends BitcoinSUnitTest { val path = MultisigHDPath.fromString("m/45'/0'/0'/0/0") val Success(xpub) = rootXpriv.deriveChildPubKey(path) val Success(expectedXpub) = ExtPublicKey.fromStringT( - "tpubDHCrSZso4pz3qxzmyZyMJQEvuES52VoGon1BTLewCy5uaMUeyMnt5CPPvVqLD6cDHzmfyKMWcGwVwW5jhnktMauQ7RCojxAthdqDHJNNVUx") + "tpubDHCrSZso4pz3qxzmyZyMJQEvuES52VoGon1BTLewCy5uaMUeyMnt5CPPvVqLD6cDHzmfyKMWcGwVwW5jhnktMauQ7RCojxAthdqDHJNNVUx" + ) assert(xpub == expectedXpub) } } @@ -568,18 +593,20 @@ class HDPathTest extends BitcoinSUnitTest { // implemented. Posted a SO question about this: // https://bitcoin.stackexchange.com/questions/87396/whats-the-magic-key-version-bytes-for-bip49 it must "correctly parse the example from BIP49" in { - val words = Vector("abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "about") + val words = Vector( + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "about" + ) val mnemonic = MnemonicCode.fromWords(words) val seed = BIP39Seed.fromMnemonic(mnemonic) @@ -592,21 +619,25 @@ class HDPathTest extends BitcoinSUnitTest { // from bip49 pass val rootXpriv = seed.toExtPrivateKey(ExtKeyVersion.LegacyTestNet3Priv) val Success(expectedRootXpriv) = ExtPrivateKey.fromStringT( - "tprv8ZgxMBicQKsPe5YMU9gHen4Ez3ApihUfykaqUorj9t6FDqy3nP6eoXiAo2ssvpAjoLroQxHqr3R5nE3a5dU3DHTjTgJDd7zrbniJr6nrCzd") + "tprv8ZgxMBicQKsPe5YMU9gHen4Ez3ApihUfykaqUorj9t6FDqy3nP6eoXiAo2ssvpAjoLroQxHqr3R5nE3a5dU3DHTjTgJDd7zrbniJr6nrCzd" + ) val path = NestedSegWitHDPath.fromString("m/49'/1'/0'/0/0") val firstAccount = path.account val accountXpriv = rootXpriv.deriveChildPrivKey(firstAccount) val Success(expectedAccountXpriv) = ExtPrivateKey.fromStringT( - "tprv8gRrNu65W2Msef2BdBSUgFdRTGzC8EwVXnV7UGS3faeXtuMVtGfEdidVeGbThs4ELEoayCAzZQ4uUji9DUiAs7erdVskqju7hrBcDvDsdbY") + "tprv8gRrNu65W2Msef2BdBSUgFdRTGzC8EwVXnV7UGS3faeXtuMVtGfEdidVeGbThs4ELEoayCAzZQ4uUji9DUiAs7erdVskqju7hrBcDvDsdbY" + ) assert(expectedAccountXpriv == accountXpriv) val privkeyAtPath = rootXpriv.deriveChildPrivKey(path).key val expectedPrivkeyAtPath = ECPrivateKey( - hex"0xc9bdb49cfbaedca21c4b1f3a7803c34636b1d7dc55a717132443fc3f4c5867e8") + hex"0xc9bdb49cfbaedca21c4b1f3a7803c34636b1d7dc55a717132443fc3f4c5867e8" + ) val expectedPubkeyAtPath = ECPublicKey( - hex"0x03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f") + hex"0x03a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f" + ) assert(expectedPrivkeyAtPath.publicKey == expectedPubkeyAtPath) assert(privkeyAtPath == expectedPrivkeyAtPath) assert(privkeyAtPath.publicKey == expectedPubkeyAtPath) @@ -628,18 +659,20 @@ class HDPathTest extends BitcoinSUnitTest { // https://github.com/satoshilabs/slips/blob/master/slip-0132.md#bitcoin-test-vectors it must "pass the test vector from SLIP132" in { - val words = Vector("abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "abandon", - "about") + val words = Vector( + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "abandon", + "about" + ) val mnemonic = MnemonicCode.fromWords(words) val seed = BIP39Seed.fromMnemonic(mnemonic) @@ -653,9 +686,11 @@ class HDPathTest extends BitcoinSUnitTest { val accountXpub = accountXpriv.extPublicKey val Success(expectedAccountXpriv) = ExtPrivateKey.fromStringT( - "xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb") + "xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb" + ) val Success(expectedAccountXpub) = ExtPublicKey.fromStringT( - "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj") + "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj" + ) assert(expectedAccountXpriv == accountXpriv) assert(expectedAccountXpub == accountXpub) @@ -672,9 +707,11 @@ class HDPathTest extends BitcoinSUnitTest { val accountXpub = accountXpriv.extPublicKey val Success(expectedAccountXpriv) = ExtPrivateKey.fromStringT( - "yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF") + "yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF" + ) val Success(expectedAccountXpub) = ExtPublicKey.fromStringT( - "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP") + "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP" + ) assert(expectedAccountXpriv == accountXpriv) assert(expectedAccountXpub == accountXpub) @@ -690,9 +727,11 @@ class HDPathTest extends BitcoinSUnitTest { val accountXpub = accountXpriv.extPublicKey val Success(expectedAccountXpriv) = ExtPrivateKey.fromStringT( - "zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE") + "zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE" + ) val Success(expectedAccountXpub) = ExtPublicKey.fromStringT( - "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs") + "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs" + ) assert(expectedAccountXpriv == accountXpriv) assert(expectedAccountXpub == accountXpub) diff --git a/core-test/src/test/scala/org/bitcoins/core/number/Int64Test.scala b/core-test/src/test/scala/org/bitcoins/core/number/Int64Test.scala index b0e3ea4665..eb69407254 100644 --- a/core-test/src/test/scala/org/bitcoins/core/number/Int64Test.scala +++ b/core-test/src/test/scala/org/bitcoins/core/number/Int64Test.scala @@ -25,14 +25,17 @@ class Int64Test extends BitcoinSUnitTest { it must "represent the number -1 with 8 bytes" in { val int64 = Int64( - ByteVector(0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte)) + ByteVector( + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte + ) + ) int64.toLong must be(-1) } it must "represent the Int32 max value" in { @@ -54,52 +57,64 @@ class Int64Test extends BitcoinSUnitTest { it must "represent the Int32 min value - 1" in { val int64 = Int64( - ByteVector(0xff.toByte, - 0x7f.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte)) + ByteVector( + 0xff.toByte, + 0x7f.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte + ) + ) int64.toLong must be(-2147483649L) } it must "represent the minimum value for int64" in { val int64 = Int64( - ByteVector(0x80.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte)) + ByteVector( + 0x80.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte + ) + ) int64.toLong must be(-9223372036854775808L) } it must "represent the maximum value for a int64" in { val int64 = Int64( - ByteVector(0x7f.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte)) + ByteVector( + 0x7f.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte + ) + ) int64.toLong must be(9223372036854775807L) } it must "throw an exception when trying to create a Int64 out of 9 bytes or more" in { intercept[IllegalArgumentException] { Int64( - ByteVector(0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte)) + ByteVector( + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte + ) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/number/UInt16Test.scala b/core-test/src/test/scala/org/bitcoins/core/number/UInt16Test.scala index 3f6e971365..f835dac48b 100644 --- a/core-test/src/test/scala/org/bitcoins/core/number/UInt16Test.scala +++ b/core-test/src/test/scala/org/bitcoins/core/number/UInt16Test.scala @@ -153,7 +153,8 @@ class UInt16Test extends BitcoinSUnitTest { if (bigInt1 * bigInt2 <= UInt16.max.toInt) { assert( num1 * num2 == - UInt16(num1.toInt * num2.toInt)) + UInt16(num1.toInt * num2.toInt) + ) } else { assert(Try(num1 * num2).isFailure) } diff --git a/core-test/src/test/scala/org/bitcoins/core/number/UInt32Test.scala b/core-test/src/test/scala/org/bitcoins/core/number/UInt32Test.scala index c3e2bcac7d..d711d37575 100644 --- a/core-test/src/test/scala/org/bitcoins/core/number/UInt32Test.scala +++ b/core-test/src/test/scala/org/bitcoins/core/number/UInt32Test.scala @@ -47,7 +47,7 @@ class UInt32Test extends BitcoinSUnitTest { } it must "create the number 4294967295" in { - //this is UInt32_t's max value + // this is UInt32_t's max value val uInt32 = UInt32(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte)) uInt32.toLong must be(4294967295L) diff --git a/core-test/src/test/scala/org/bitcoins/core/number/UInt64Test.scala b/core-test/src/test/scala/org/bitcoins/core/number/UInt64Test.scala index 95a4bc54b7..b85755aad7 100644 --- a/core-test/src/test/scala/org/bitcoins/core/number/UInt64Test.scala +++ b/core-test/src/test/scala/org/bitcoins/core/number/UInt64Test.scala @@ -23,7 +23,7 @@ class UInt64Test extends BitcoinSUnitTest { } it must "hold the max for a uint32_t" in { - //this is UInt32_t's max value + // this is UInt32_t's max value val uInt64 = UInt64(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte)) uInt64.toBigInt must be(4294967295L) @@ -37,14 +37,17 @@ class UInt64Test extends BitcoinSUnitTest { it must "hold the max number for uint64_t" in { val uInt64 = UInt64( - ByteVector(0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte, - 0xff.toByte)) + ByteVector( + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte, + 0xff.toByte + ) + ) uInt64.toBigInt must be(BigInt("18446744073709551615")) uInt64.hex must be("ffffffffffffffff") } @@ -52,15 +55,18 @@ class UInt64Test extends BitcoinSUnitTest { it must "throw an exception if we try and create a number larger than 8 bytes" in { intercept[IllegalArgumentException] { UInt64( - ByteVector(1.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte, - 0.toByte)) + ByteVector( + 1.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte, + 0.toByte + ) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/CompactFilterHeadersMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/CompactFilterHeadersMessageTest.scala index 64d06c97bc..9a70547986 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/CompactFilterHeadersMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/CompactFilterHeadersMessageTest.scala @@ -10,32 +10,45 @@ class CompactFilterHeadersMessageTest extends BitcoinSUnitTest { val message = CompactFilterHeadersMessage( FilterType.Basic, stopHash = DoubleSha256Digest.fromHex( - "9783ef3f32cdf84a66329c30717560e1be50e53743ef415f4c1a714a4f731831"), + "9783ef3f32cdf84a66329c30717560e1be50e53743ef415f4c1a714a4f731831" + ), previousFilterHeader = DoubleSha256Digest.fromHex( - "0000000000000000000000000000000000000000000000000000000000000000"), + "0000000000000000000000000000000000000000000000000000000000000000" + ), filterHashes = Vector( DoubleSha256Digest.fromHex( - "1f30de30fabb7892d15eb985cc5d6c34c54a11b7e4c51f3da498f16255a27bb1"), + "1f30de30fabb7892d15eb985cc5d6c34c54a11b7e4c51f3da498f16255a27bb1" + ), DoubleSha256Digest.fromHex( - "12dc878ad0dbf1570b7717916b69a3c596d2f44c3648abb205d01498076e3dc7"), + "12dc878ad0dbf1570b7717916b69a3c596d2f44c3648abb205d01498076e3dc7" + ), DoubleSha256Digest.fromHex( - "3e42e4309701bbcfa1173294c2068872557191c4197b0b6db17ad07455fd0ad2"), + "3e42e4309701bbcfa1173294c2068872557191c4197b0b6db17ad07455fd0ad2" + ), DoubleSha256Digest.fromHex( - "3632ce0c0243d3c857c06aa1514a4c55abd11c9a78a64b0ea5afe5e4454e762b"), + "3632ce0c0243d3c857c06aa1514a4c55abd11c9a78a64b0ea5afe5e4454e762b" + ), DoubleSha256Digest.fromHex( - "2780a5f5efd80f9cdb7db852b36cd8c7b10ea8af73b54875b8cb963e243ce779"), + "2780a5f5efd80f9cdb7db852b36cd8c7b10ea8af73b54875b8cb963e243ce779" + ), DoubleSha256Digest.fromHex( - "0103dd9d2485c30e58b9c70649821de58c22ac145bb61cc43295e7b282c5e25e"), + "0103dd9d2485c30e58b9c70649821de58c22ac145bb61cc43295e7b282c5e25e" + ), DoubleSha256Digest.fromHex( - "f8c60959fc3d854e2c5e19abf8581ad945f085d6b3f33e34ea441b0f0fce247d"), + "f8c60959fc3d854e2c5e19abf8581ad945f085d6b3f33e34ea441b0f0fce247d" + ), DoubleSha256Digest.fromHex( - "790a19612aaf4849261bc184a34cdd83bfd7dd2fd9fa6f2871f39cd7af4a97e4"), + "790a19612aaf4849261bc184a34cdd83bfd7dd2fd9fa6f2871f39cd7af4a97e4" + ), DoubleSha256Digest.fromHex( - "01f1be7b43e18bac1cb57232169fc2985e47261b4b369ca42c3a9dae7deb2630"), + "01f1be7b43e18bac1cb57232169fc2985e47261b4b369ca42c3a9dae7deb2630" + ), DoubleSha256Digest.fromHex( - "e9b74e7ca6ba7b4d83abd6406c7b1c0cd2f43e4f74140ac6498ae976d7b3b132"), + "e9b74e7ca6ba7b4d83abd6406c7b1c0cd2f43e4f74140ac6498ae976d7b3b132" + ), DoubleSha256Digest.fromHex( - "aeb7d751ef3bc6c65466d7962fa989ea519bd98759fdb68a7547ed70d3f7aa67") + "aeb7d751ef3bc6c65466d7962fa989ea519bd98759fdb68a7547ed70d3f7aa67" + ) ) ) @@ -44,71 +57,94 @@ class CompactFilterHeadersMessageTest extends BitcoinSUnitTest { Vector( FilterHeader( DoubleSha256Digest.fromHex( - "1f30de30fabb7892d15eb985cc5d6c34c54a11b7e4c51f3da498f16255a27bb1"), + "1f30de30fabb7892d15eb985cc5d6c34c54a11b7e4c51f3da498f16255a27bb1" + ), DoubleSha256Digest.fromHex( - "0000000000000000000000000000000000000000000000000000000000000000") + "0000000000000000000000000000000000000000000000000000000000000000" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "12dc878ad0dbf1570b7717916b69a3c596d2f44c3648abb205d01498076e3dc7"), + "12dc878ad0dbf1570b7717916b69a3c596d2f44c3648abb205d01498076e3dc7" + ), DoubleSha256Digest.fromHex( - "2b5adc66021d5c775f630efd91518cf6ce3e9f525bbf54d9f0d709451e305e48") + "2b5adc66021d5c775f630efd91518cf6ce3e9f525bbf54d9f0d709451e305e48" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "3e42e4309701bbcfa1173294c2068872557191c4197b0b6db17ad07455fd0ad2"), + "3e42e4309701bbcfa1173294c2068872557191c4197b0b6db17ad07455fd0ad2" + ), DoubleSha256Digest.fromHex( - "3d21cd4e0c683629deee1846154934beb989f671480f97329a12521e49708662") + "3d21cd4e0c683629deee1846154934beb989f671480f97329a12521e49708662" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "3632ce0c0243d3c857c06aa1514a4c55abd11c9a78a64b0ea5afe5e4454e762b"), + "3632ce0c0243d3c857c06aa1514a4c55abd11c9a78a64b0ea5afe5e4454e762b" + ), DoubleSha256Digest.fromHex( - "e236b45099e4fa8007b828fd381a44d6fe30b5fadc116dccdc3cb3055a93982d") + "e236b45099e4fa8007b828fd381a44d6fe30b5fadc116dccdc3cb3055a93982d" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "2780a5f5efd80f9cdb7db852b36cd8c7b10ea8af73b54875b8cb963e243ce779"), + "2780a5f5efd80f9cdb7db852b36cd8c7b10ea8af73b54875b8cb963e243ce779" + ), DoubleSha256Digest.fromHex( - "49b5e5af58bd0c7443bda36a5d9870321699ee01df978d16d7475606d7ff62c5") + "49b5e5af58bd0c7443bda36a5d9870321699ee01df978d16d7475606d7ff62c5" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "0103dd9d2485c30e58b9c70649821de58c22ac145bb61cc43295e7b282c5e25e"), + "0103dd9d2485c30e58b9c70649821de58c22ac145bb61cc43295e7b282c5e25e" + ), DoubleSha256Digest.fromHex( - "ee8a1b0b427e5e66eb04c4e7aab94f15e7db553df16f88a0d9a6048d4726cf6d") + "ee8a1b0b427e5e66eb04c4e7aab94f15e7db553df16f88a0d9a6048d4726cf6d" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "f8c60959fc3d854e2c5e19abf8581ad945f085d6b3f33e34ea441b0f0fce247d"), + "f8c60959fc3d854e2c5e19abf8581ad945f085d6b3f33e34ea441b0f0fce247d" + ), DoubleSha256Digest.fromHex( - "5eda6f75e5f83d686a4915b65501aceef999be16ea58fe51413f0cfb7dd6a54b") + "5eda6f75e5f83d686a4915b65501aceef999be16ea58fe51413f0cfb7dd6a54b" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "790a19612aaf4849261bc184a34cdd83bfd7dd2fd9fa6f2871f39cd7af4a97e4"), + "790a19612aaf4849261bc184a34cdd83bfd7dd2fd9fa6f2871f39cd7af4a97e4" + ), DoubleSha256Digest.fromHex( - "add1a57d8150ecffba0f9fb4f2ee74652436a330112b30f8b33e2724c356e75f") + "add1a57d8150ecffba0f9fb4f2ee74652436a330112b30f8b33e2724c356e75f" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "01f1be7b43e18bac1cb57232169fc2985e47261b4b369ca42c3a9dae7deb2630"), + "01f1be7b43e18bac1cb57232169fc2985e47261b4b369ca42c3a9dae7deb2630" + ), DoubleSha256Digest.fromHex( - "8dac8a8185608a0427f2709bd7e213a21d08c678ecfd18716572bf4e10d31ee5") + "8dac8a8185608a0427f2709bd7e213a21d08c678ecfd18716572bf4e10d31ee5" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "e9b74e7ca6ba7b4d83abd6406c7b1c0cd2f43e4f74140ac6498ae976d7b3b132"), + "e9b74e7ca6ba7b4d83abd6406c7b1c0cd2f43e4f74140ac6498ae976d7b3b132" + ), DoubleSha256Digest.fromHex( - "b43e99adb112345e2f19ed481ea8cd7a8c089b4597fd1a623f49f65a57ddc2f0") + "b43e99adb112345e2f19ed481ea8cd7a8c089b4597fd1a623f49f65a57ddc2f0" + ) ), FilterHeader( DoubleSha256Digest.fromHex( - "aeb7d751ef3bc6c65466d7962fa989ea519bd98759fdb68a7547ed70d3f7aa67"), + "aeb7d751ef3bc6c65466d7962fa989ea519bd98759fdb68a7547ed70d3f7aa67" + ), DoubleSha256Digest.fromHex( - "76d1a761ca0e2337222487873c26757a225c597044041d1426006e948618df38") + "76d1a761ca0e2337222487873c26757a225c597044041d1426006e948618df38" + ) ) - )) + ) + ) val hashes = headers.map(_.filterHash) message.filterHashes must be(hashes) diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/FilterLoadMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/FilterLoadMessageTest.scala index 4a0ec04af7..b369f3e67c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/FilterLoadMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/FilterLoadMessageTest.scala @@ -22,11 +22,13 @@ class FilterLoadMessageTest extends BitcoinSUnitTest { val hashFuncs = UInt32.one val tweak = UInt32.zero val flags = BloomUpdateAll - val bloom = BloomFilter(filterSize = size, - data = data, - hashFuncs = hashFuncs, - tweak = tweak, - flags = flags) + val bloom = BloomFilter( + filterSize = size, + data = data, + hashFuncs = hashFuncs, + tweak = tweak, + flags = flags + ) FilterLoadMessage(bloom) } } @@ -38,11 +40,13 @@ class FilterLoadMessageTest extends BitcoinSUnitTest { val hashFuncs = UInt32(51) val tweak = UInt32.zero val flags = BloomUpdateAll - val bloom = BloomFilter(filterSize = size, - data = data, - hashFuncs = hashFuncs, - tweak = tweak, - flags = flags) + val bloom = BloomFilter( + filterSize = size, + data = data, + hashFuncs = hashFuncs, + tweak = tweak, + flags = flags + ) FilterLoadMessage(bloom) } } @@ -54,11 +58,13 @@ class FilterLoadMessageTest extends BitcoinSUnitTest { val hashFuncs = UInt32.one val tweak = UInt32.zero val flags = BloomUpdateAll - val bloom = BloomFilter(filterSize = size, - data = data, - hashFuncs = hashFuncs, - tweak = tweak, - flags = flags) + val bloom = BloomFilter( + filterSize = size, + data = data, + hashFuncs = hashFuncs, + tweak = tweak, + flags = flags + ) FilterLoadMessage(bloom) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/GetHeadersMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/GetHeadersMessageTest.scala index 8b6059e4c9..cb84da67fd 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/GetHeadersMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/GetHeadersMessageTest.scala @@ -17,7 +17,8 @@ class GetHeadersMessageTest extends BitcoinSUnitTest { it must "be constructable from just hashes" in { forAll(DataMessageGenerator.getHeaderDefaultProtocolMessage) { getHeader => assert( - GetHeadersMessage(getHeader.hashes, getHeader.hashStop) == getHeader) + GetHeadersMessage(getHeader.hashes, getHeader.hashStop) == getHeader + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/MerkleBlockMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/MerkleBlockMessageTest.scala index d70195eb49..a376f3d5a1 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/MerkleBlockMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/MerkleBlockMessageTest.scala @@ -27,13 +27,17 @@ class MerkleBlockMessageTest extends BitcoinSUnitTest { val Seq(first, second, third, fourth) = merkle.hashes val expectedFirst = DoubleSha256Digest.fromHex( - "3612262624047ee87660be1a707519a443b1c1ce3d248cbfc6c15870f6c5daa2") + "3612262624047ee87660be1a707519a443b1c1ce3d248cbfc6c15870f6c5daa2" + ) val expectedSecond = DoubleSha256Digest.fromHex( - "019f5b01d4195ecbc9398fbf3c3b1fa9bb3183301d7a1fb3bd174fcfa40a2b65") + "019f5b01d4195ecbc9398fbf3c3b1fa9bb3183301d7a1fb3bd174fcfa40a2b65" + ) val expectedThird = DoubleSha256Digest.fromHex( - "41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068") + "41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068" + ) val expectedFourth = DoubleSha256Digest.fromHex( - "20d2a7bc994987302e5b1ac80fc425fe25f8b63169ea78e68fbaaefa59379bbf") + "20d2a7bc994987302e5b1ac80fc425fe25f8b63169ea78e68fbaaefa59379bbf" + ) assert(first == expectedFirst) assert(second == expectedSecond) diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkHeaderTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkHeaderTest.scala index 6904b1f369..2e6453d07b 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkHeaderTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkHeaderTest.scala @@ -17,14 +17,17 @@ class NetworkHeaderTest extends BitcoinSUnitTest { NetworkHeader(TestNet3, P2PMessageTestUtil.versionMessage) messageHeader.network must be(TestNet3) messageHeader.commandName must be( - P2PMessageTestUtil.versionMessage.commandName) + P2PMessageTestUtil.versionMessage.commandName + ) messageHeader.payloadSize must be( - UInt32(P2PMessageTestUtil.versionMessage.bytes.size)) + UInt32(P2PMessageTestUtil.versionMessage.bytes.size) + ) messageHeader.checksum must be( CryptoUtil .doubleSHA256(P2PMessageTestUtil.versionMessage.bytes) .bytes - .take(4)) + .take(4) + ) } it must "build the correct message header for a verack message" in { @@ -38,10 +41,12 @@ class NetworkHeaderTest extends BitcoinSUnitTest { it must "throw on messages of bad length" in { intercept[IllegalArgumentException] { val commandName = Random.shuffle(NetworkPayload.commandNames).head - NetworkHeader(MainNet, - commandName, - payloadSize = UInt32.one, - checksum = ByteVector.empty) + NetworkHeader( + MainNet, + commandName, + payloadSize = UInt32.one, + checksum = ByteVector.empty + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkMessageTest.scala index 911a2713b2..297a5b3f6c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkMessageTest.scala @@ -7,17 +7,18 @@ class NetworkMessageTest extends BitcoinSUnitTest { "NetworkMessage" must "be able to serialize then deserialize a message and get the original hex back" in { NetworkMessage(P2PMessageTestUtil.rawNetworkMessage).hex must be( - P2PMessageTestUtil.rawNetworkMessage) + P2PMessageTestUtil.rawNetworkMessage + ) } it must "serialize and deserialize a version message example from the bitcoin wiki" in { val hex = { - //taken from here with slight modifications - //https://en.bitcoin.it/wiki/Protocol_documentation#Message_structure - //this example uses an old protocol version WITHOUT the relay flag on the version message - //since we only support protocol version > 7, i added it manually - //this means the payload size is bumped by 1 byte in the NetworkHeader from 100 -> 101 - //and a relay byte "00" is appended to the end of the payload + // taken from here with slight modifications + // https://en.bitcoin.it/wiki/Protocol_documentation#Message_structure + // this example uses an old protocol version WITHOUT the relay flag on the version message + // since we only support protocol version > 7, i added it manually + // this means the payload size is bumped by 1 byte in the NetworkHeader from 100 -> 101 + // and a relay byte "00" is appended to the end of the payload "F9BEB4D976657273696F6E000000000065000000358d4932" + "62EA0000010000000000000011B2D05000000000010000000000000000000000000000000000FFFF000000000000010000000000000000000000000000000000FFFF0000000000003B2EB35D8CE617650F2F5361746F7368693A302E372E322FC03E0300" + "00" diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkPayloadTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkPayloadTest.scala index 177feeddd4..df94cac72e 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkPayloadTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/NetworkPayloadTest.scala @@ -18,9 +18,11 @@ class NetworkPayloadTest extends BitcoinSUnitTest { val inet = InetAddress(ipArr) val testVersionMessage = VersionMessage(TestNet3, inet, inet, relay = false) payload.asInstanceOf[VersionMessage].addressReceiveIpAddress must be( - testVersionMessage.addressReceiveIpAddress) + testVersionMessage.addressReceiveIpAddress + ) payload.asInstanceOf[VersionMessage].addressReceivePort must be( - testVersionMessage.addressReceivePort) + testVersionMessage.addressReceivePort + ) } // this tests has a bunch of messages to choose between, so we set a high config value diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/ServiceIdentifierTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/ServiceIdentifierTest.scala index af043d5877..85e15ff00b 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/ServiceIdentifierTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/ServiceIdentifierTest.scala @@ -40,21 +40,31 @@ class ServiceIdentifierTest extends BitcoinSUnitTest { it must "correctly get a ServiceIdentifier from string" in { assert( - ServiceIdentifier.fromString("NETWORK") == ServiceIdentifier.NODE_NETWORK) - assert(ServiceIdentifier - .fromString("NETWORK_LIMITED") == ServiceIdentifier.NODE_NETWORK_LIMITED) - assert( - ServiceIdentifier.fromString("WITNESS") == ServiceIdentifier.NODE_WITNESS) - assert( - ServiceIdentifier.fromString("BLOOM") == ServiceIdentifier.NODE_BLOOM) + ServiceIdentifier.fromString("NETWORK") == ServiceIdentifier.NODE_NETWORK + ) assert( ServiceIdentifier - .fromString("GETUTXO") == ServiceIdentifier.NODE_GET_UTXO) - assert(ServiceIdentifier - .fromString("COMPACT_FILTERS") == ServiceIdentifier.NODE_COMPACT_FILTERS) + .fromString("NETWORK_LIMITED") == ServiceIdentifier.NODE_NETWORK_LIMITED + ) assert( - ServiceIdentifier.fromString("XTHIN") == ServiceIdentifier.NODE_XTHIN) + ServiceIdentifier.fromString("WITNESS") == ServiceIdentifier.NODE_WITNESS + ) + assert( + ServiceIdentifier.fromString("BLOOM") == ServiceIdentifier.NODE_BLOOM + ) + assert( + ServiceIdentifier + .fromString("GETUTXO") == ServiceIdentifier.NODE_GET_UTXO + ) + assert( + ServiceIdentifier + .fromString("COMPACT_FILTERS") == ServiceIdentifier.NODE_COMPACT_FILTERS + ) + assert( + ServiceIdentifier.fromString("XTHIN") == ServiceIdentifier.NODE_XTHIN + ) assertThrows[IllegalArgumentException]( - ServiceIdentifier.fromString("this is invalid")) + ServiceIdentifier.fromString("this is invalid") + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/TypeIdentifierTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/TypeIdentifierTest.scala index effb3d32d0..2e3561d06c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/TypeIdentifierTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/TypeIdentifierTest.scala @@ -38,7 +38,9 @@ class TypeIdentifierTest extends BitcoinSUnitTest { MsgFilteredWitnessBlock.hex must be("03000040") assert( TypeIdentifier.fromBytes( - MsgFilteredWitnessBlock.bytes) == MsgFilteredWitnessBlock) + MsgFilteredWitnessBlock.bytes + ) == MsgFilteredWitnessBlock + ) } "MsgCompactBlock" must "serialize to 04000000" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/p2p/VersionMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/p2p/VersionMessageTest.scala index e1d31fe006..f1bed76e6b 100644 --- a/core-test/src/test/scala/org/bitcoins/core/p2p/VersionMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/p2p/VersionMessageTest.scala @@ -38,7 +38,8 @@ class VersionMessageTest extends BitcoinSUnitTest { versionMessage.nonce must be(UInt64.zero) versionMessage.startHeight must be(Int32.zero) versionMessage.timestamp.toLong must be( - Instant.now().getEpochSecond +- 1000) + Instant.now().getEpochSecond +- 1000 + ) } it must "correctly deduce service flags" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/AddressTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/AddressTest.scala index 022892ee86..6ac886312d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/AddressTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/AddressTest.scala @@ -38,7 +38,8 @@ class AddressTest extends BitcoinSUnitTest { it must "serialize a bech32 address correctly" in { TestUtil.bech32Address.toString must be( - "bcrt1qq6w6pu6zq90az9krn53zlkvgyzkyeglzukyepf") + "bcrt1qq6w6pu6zq90az9krn53zlkvgyzkyeglzukyepf" + ) } it must "calculate the correct descriptor" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/Bech32Test.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/Bech32Test.scala index bece2c88d2..e0904eed59 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/Bech32Test.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/Bech32Test.scala @@ -41,14 +41,15 @@ class Bech32Test extends BitcoinSUnitTest { } it must "follow the example in BIP173" in { - //https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#examples + // https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#examples val key = ECPublicKey( - "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798".toLowerCase) + "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798".toLowerCase + ) val p2wpkh = P2WPKHWitnessSPKV0(key) val addr = Bech32Address(p2wpkh, TestNet3) addr.value must be("tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx") - //decode + // decode val decoded = Bech32Address.fromStringToWitSPK(addr.value) decoded must be(Success(p2wpkh)) @@ -62,36 +63,43 @@ class Bech32Test extends BitcoinSUnitTest { val p2wsh = P2WSHWitnessSPKV0(p2pk) val addr1 = Bech32Address(p2wsh, TestNet3) addr1.value must be( - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7") + "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7" + ) - //decode + // decode val decoded1 = Bech32Address.fromStringToWitSPK(addr1.value) decoded1 must be(Success(p2wsh)) val p2wshMain = Bech32Address(p2wsh, MainNet) p2wshMain.value must be( - "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3") + "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3" + ) val mp2wshDecoded = Bech32Address.fromStringToWitSPK(p2wshMain.value) mp2wshDecoded must be(Success(p2wsh)) } it must "expand the human readable part correctly - BTC" in { BtcHumanReadablePart.bc.expand must be( - Vector(UInt5(3), UInt5(3), UInt5(0), UInt5(2), UInt5(3))) + Vector(UInt5(3), UInt5(3), UInt5(0), UInt5(2), UInt5(3)) + ) BtcHumanReadablePart.tb.expand must be( - Vector(UInt5(3), UInt5(3), UInt5(0), UInt5(20), UInt5(2))) + Vector(UInt5(3), UInt5(3), UInt5(0), UInt5(20), UInt5(2)) + ) BtcHumanReadablePart.bcrt.expand must be( - Vector(UInt5(3), - UInt5(3), - UInt5(3), - UInt5(3), - UInt5(0), - UInt5(2), - UInt5(3), - UInt5(18), - UInt5(20))) + Vector( + UInt5(3), + UInt5(3), + UInt5(3), + UInt5(3), + UInt5(0), + UInt5(2), + UInt5(3), + UInt5(18), + UInt5(20) + ) + ) } it must "expand the human readable part correctly - LN no amount" in { @@ -106,7 +114,8 @@ class Bech32Test extends BitcoinSUnitTest { UInt5(14), UInt5(2), UInt5(3) - )) + ) + ) LnHumanReadablePart.lntb(None).expand must be( Vector( @@ -119,7 +128,8 @@ class Bech32Test extends BitcoinSUnitTest { UInt5(14), UInt5(20), UInt5(2) - )) + ) + ) LnHumanReadablePart.lnbcrt(None).expand must be( Vector( @@ -136,7 +146,8 @@ class Bech32Test extends BitcoinSUnitTest { UInt5(3), UInt5(18), UInt5(20) - )) + ) + ) } it must "expand the human readable part correctly - LN with amount" in { @@ -161,7 +172,8 @@ class Bech32Test extends BitcoinSUnitTest { UInt5(18), UInt5(20), UInt5(16) - )) + ) + ) } it must "encode 0 byte correctly" in { @@ -192,30 +204,35 @@ class Bech32Test extends BitcoinSUnitTest { val encoded1 = Bech32.from8bitTo5bit(Vector(z, UInt8.one)) encoded1 must be(Seq(fz, fz, fz, UInt5(16.toByte))) - //130.toByte == -126 + // 130.toByte == -126 val encoded2 = Bech32.from8bitTo5bit(Vector(130).map(i => UInt8(i.toShort))) encoded2 must be(Seq(16, 8).map(i => UInt5(i.toByte))) - //130.toByte == -126 + // 130.toByte == -126 val encoded3 = Bech32.from8bitTo5bit(Vector(255, 255).map(i => UInt8(i.toShort))) encoded3 must be(Seq(31, 31, 31, 16).map(i => UInt5(i.toByte))) val encoded4 = Bech32.from8bitTo5bit( - Vector(255, 255, 255, 255).map(i => UInt8(i.toShort))) + Vector(255, 255, 255, 255).map(i => UInt8(i.toShort)) + ) encoded4 must be(Seq(31, 31, 31, 31, 31, 31, 24).map(i => UInt5(i.toByte))) val encoded5 = Bech32.from8bitTo5bit( - Vector(255, 255, 255, 255, 255).map(i => UInt8(i.toShort))) + Vector(255, 255, 255, 255, 255).map(i => UInt8(i.toShort)) + ) encoded5 must be( - Seq(31, 31, 31, 31, 31, 31, 31, 31).map(i => UInt5(i.toByte))) + Seq(31, 31, 31, 31, 31, 31, 31, 31).map(i => UInt5(i.toByte)) + ) val encoded6 = Bech32.from8bitTo5bit( - Vector(255, 255, 255, 255, 255, 255).map(i => UInt8(i.toByte))) + Vector(255, 255, 255, 255, 255, 255).map(i => UInt8(i.toByte)) + ) encoded6 must be( - Seq(31, 31, 31, 31, 31, 31, 31, 31, 31, 28).map(i => UInt5(i.toByte))) + Seq(31, 31, 31, 31, 31, 31, 31, 31, 31, 28).map(i => UInt5(i.toByte)) + ) } it must "encode from 8 bit to 5 bit and back" in { @@ -249,21 +266,26 @@ class Bech32Test extends BitcoinSUnitTest { assert( Bech32 .checkDataValidity("bcrt1qq6w6pu6zq90az9krn53zlkvgyzkyeglzukyepf") - .isFailure) + .isFailure + ) } it must "fail to read a segwitV1 bech32 address" in { assert( Bech32Address .fromStringT( - "tb1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7") - .isFailure) + "tb1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7" + ) + .isFailure + ) assert( Bech32Address .fromStringT( - "bc1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7") - .isFailure) + "bc1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7" + ) + .isFailure + ) } it must "fail to read a bech32m address" in { @@ -289,8 +311,10 @@ class Bech32Test extends BitcoinSUnitTest { } it must "serialization symmetry" in { - forAll(ScriptGenerators.witnessScriptPubKeyV0, - ChainParamsGenerator.networkParams) { case ((witSPK, _), network) => + forAll( + ScriptGenerators.witnessScriptPubKeyV0, + ChainParamsGenerator.networkParams + ) { case ((witSPK, _), network) => val addr = Bech32Address(witSPK, network) val spk = Bech32Address.fromStringToWitSPK(addr.value) assert(spk == Success(witSPK)) @@ -305,7 +329,7 @@ class Bech32Test extends BitcoinSUnitTest { val (f, l) = old.splitAt(idx) val replacementChar = pickReplacementChar(l.head) val replaced = s"$f$replacementChar${l.tail}" - //should fail because we replaced a char in the addr, so checksum invalid + // should fail because we replaced a char in the addr, so checksum invalid assert(Bech32Address.fromStringT(replaced).isFailure) } } @@ -314,7 +338,7 @@ class Bech32Test extends BitcoinSUnitTest { forAll(AddressGenerator.bech32Address) { addr: Bech32Address => val old = addr.value val replaced = switchCaseRandChar(old) - //should fail because we we switched the case of a random char + // should fail because we we switched the case of a random char val actual = Bech32Address.fromStringT(replaced) assert(actual.isFailure) } @@ -324,7 +348,7 @@ class Bech32Test extends BitcoinSUnitTest { private def pickReplacementChar(oldChar: Char): Char = { val rand = Math.abs(Random.nextInt()) val newChar = Bech32.charset(rand % Bech32.charset.size) - //make sure we don't pick the same char we are replacing in the bech32 address + // make sure we don't pick the same char we are replacing in the bech32 address if (oldChar == newChar) pickReplacementChar(oldChar) else newChar } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/Bech32mTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/Bech32mTest.scala index 3b208f180e..a19781ed35 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/Bech32mTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/Bech32mTest.scala @@ -26,9 +26,12 @@ class Bech32mTest extends BitcoinSUnitTest { } it must "serialization symmetry" in { - forAll(ScriptGenerators.witnessScriptPubKey.suchThat( - _._1.witnessVersion != WitnessVersion0), - ChainParamsGenerator.networkParams) { case ((witSPK, _), network) => + forAll( + ScriptGenerators.witnessScriptPubKey.suchThat( + _._1.witnessVersion != WitnessVersion0 + ), + ChainParamsGenerator.networkParams + ) { case ((witSPK, _), network) => val addr = Bech32mAddress(witSPK, network) val spk = Bech32mAddress.fromStringToWitSPK(addr.value) spk == Success(witSPK) @@ -39,7 +42,7 @@ class Bech32mTest extends BitcoinSUnitTest { forAll(AddressGenerator.bech32mAddress) { addr: Bech32mAddress => val old = addr.value val replaced = switchCaseRandChar(old) - //should fail because we we switched the case of a random char + // should fail because we we switched the case of a random char val actual = Bech32mAddress.fromStringT(replaced) actual.isFailure } @@ -52,14 +55,18 @@ class Bech32mTest extends BitcoinSUnitTest { Bech32 .splitToHrpAndData( "an83characterlonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11sg7hg6", - Bech32m) - .isSuccess) + Bech32m + ) + .isSuccess + ) assert( Bech32 .splitToHrpAndData( "11llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllludsr8", - Bech32m) - .isSuccess) + Bech32m + ) + .isSuccess + ) assert(Bech32.splitToHrpAndData("?1v759aa", Bech32m).isSuccess) } @@ -68,8 +75,10 @@ class Bech32mTest extends BitcoinSUnitTest { Bech32 .splitToHrpAndData( "an84characterslonghumanreadablepartthatcontainsthetheexcludedcharactersbioandnumber11d6pts4", - Bech32m) - .isFailure) + Bech32m + ) + .isFailure + ) assert(Bech32.splitToHrpAndData("qyrz8wqd2c9m", Bech32m).isFailure) assert(Bech32.splitToHrpAndData("1qyrz8wqd2c9m", Bech32m).isFailure) assert(Bech32.splitToHrpAndData("y1b0jsk6g", Bech32m).isFailure) @@ -86,94 +95,131 @@ class Bech32mTest extends BitcoinSUnitTest { Bech32mAddress .fromString("BC1PW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KJ9WKRU") .scriptPubKey == WitnessScriptPubKey.fromAsmHex( - "5114751e76e8199196d454941c45d1b3a323f1433bd6")) + "5114751e76e8199196d454941c45d1b3a323f1433bd6" + ) + ) assert( Bech32mAddress .fromString( - "tb1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q98lawz") + "tb1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q98lawz" + ) .scriptPubKey == WitnessScriptPubKey.fromAsmHex( - "51201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262")) + "51201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262" + ) + ) assert( Bech32mAddress .fromString( - "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y") + "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y" + ) .scriptPubKey == WitnessScriptPubKey.fromAsmHex( - "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6")) + "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6" + ) + ) assert( Bech32mAddress .fromString("BC1SW50QGDZ25J") - .scriptPubKey == WitnessScriptPubKey.fromAsmHex("6002751e")) + .scriptPubKey == WitnessScriptPubKey.fromAsmHex("6002751e") + ) assert( Bech32mAddress .fromString("bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs") .scriptPubKey == WitnessScriptPubKey.fromAsmHex( - "5210751e76e8199196d454941c45d1b3a323")) + "5210751e76e8199196d454941c45d1b3a323" + ) + ) assert( Bech32mAddress .fromString( - "tb1gqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsescs2hvq") + "tb1gqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsescs2hvq" + ) .scriptPubKey == WitnessScriptPubKey.fromAsmHex( - "5820000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433")) + "5820000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433" + ) + ) assert( Bech32mAddress .fromString( - "tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c") + "tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c" + ) .scriptPubKey == WitnessScriptPubKey.fromAsmHex( - "5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433")) + "5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433" + ) + ) assert( Bech32mAddress .fromString( - "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0") + "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0" + ) .scriptPubKey == WitnessScriptPubKey.fromAsmHex( - "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")) + "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" + ) + ) } it must "fail to read invalid bech32m addresses" in { assert( Bech32mAddress .fromStringT( - "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut") - .isFailure) + "tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut" + ) + .isFailure + ) assert( Bech32mAddress .fromStringT( - "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd") - .isFailure) + "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd" + ) + .isFailure + ) assert( Bech32mAddress .fromStringT( - "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf") - .isFailure) + "tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf" + ) + .isFailure + ) assert( Bech32mAddress .fromStringT( - "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL") - .isFailure) + "BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL" + ) + .isFailure + ) assert( Bech32mAddress .fromStringT( - "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4") - .isFailure) + "bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4" + ) + .isFailure + ) assert( Bech32mAddress .fromStringT( - "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R") - .isFailure) + "BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R" + ) + .isFailure + ) assert(Bech32mAddress.fromStringT("bc1pw5dgrnzv").isFailure) assert( Bech32mAddress .fromStringT( - "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav") - .isFailure) + "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav" + ) + .isFailure + ) assert( Bech32mAddress .fromStringT("BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P") - .isFailure) + .isFailure + ) assert( Bech32mAddress .fromStringT( - "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq") - .isFailure) + "tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq" + ) + .isFailure + ) assert(Bech32mAddress.fromStringT("bc1gmk9yu").isFailure) } @@ -185,8 +231,10 @@ class Bech32mTest extends BitcoinSUnitTest { } it must "fail to read a segwitV0 spk as a bech32m address" in { - forAll(ScriptGenerators.witnessScriptPubKeyV0, - ChainParamsGenerator.networkParams) { case (witSpkV0, np) => + forAll( + ScriptGenerators.witnessScriptPubKeyV0, + ChainParamsGenerator.networkParams + ) { case (witSpkV0, np) => assert(Bech32mAddress.fromScriptPubKeyT(witSpkV0._1, np).isFailure) } } @@ -202,14 +250,17 @@ class Bech32mTest extends BitcoinSUnitTest { assert( !Bech32mAddress .fromString( - "bc1pvkpqgqe7g6sl4rxwhpqp8nlz6dmv5uk47k2nr9yhh9ds32ny49cqdcghmx") - .isStandard) + "bc1pvkpqgqe7g6sl4rxwhpqp8nlz6dmv5uk47k2nr9yhh9ds32ny49cqdcghmx" + ) + .isStandard + ) // segwit v2 address assert( !Bech32mAddress .fromString("bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs") - .isStandard) + .isStandard + ) } it must "checksum must not work if we modify a char" in { @@ -220,7 +271,7 @@ class Bech32mTest extends BitcoinSUnitTest { val (f, l) = old.splitAt(idx) val replacementChar = pickReplacementChar(l.head) val replaced = s"$f$replacementChar${l.tail}" - //should fail because we replaced a char in the addr, so checksum invalid + // should fail because we replaced a char in the addr, so checksum invalid assert(Bech32mAddress.fromStringT(replaced).isFailure) } } @@ -229,7 +280,7 @@ class Bech32mTest extends BitcoinSUnitTest { forAll(AddressGenerator.bech32mAddress) { addr: Bech32mAddress => val old = addr.value val replaced = switchCaseRandChar(old) - //should fail because we we switched the case of a random char + // should fail because we we switched the case of a random char val actual = Bech32mAddress.fromStringT(replaced) assert(actual.isFailure) } @@ -239,7 +290,7 @@ class Bech32mTest extends BitcoinSUnitTest { private def pickReplacementChar(oldChar: Char): Char = { val rand = Math.abs(Random.nextInt()) val newChar = Bech32.charset(rand % Bech32.charset.size) - //make sure we don't pick the same char we are replacing in the bech32m address + // make sure we don't pick the same char we are replacing in the bech32m address if (oldChar == newChar) pickReplacementChar(oldChar) else newChar } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/BigSizeUIntTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/BigSizeUIntTest.scala index d43c790ee3..b212c4beef 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/BigSizeUIntTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/BigSizeUIntTest.scala @@ -40,8 +40,10 @@ class BigSizeUIntTest extends BitcoinSUnitTest { val tests = read[Vector[DecodeTestVector]](BigSizeJsonTestVectors.decode) tests.foreach { test => if (test.value.nonEmpty) { - assert(BigSizeUInt(test.bytes).num == UInt64(BigInt(test.value)), - test.name) + assert( + BigSizeUInt(test.bytes).num == UInt64(BigInt(test.value)), + test.name + ) } else { Try { assertThrows[IllegalArgumentException] { @@ -60,14 +62,14 @@ object BigSizeJsonTestVectors { case class EncodeTestVector(name: String, value: BigInt, bytes: ByteVector) - implicit - val encodeTestVectorR: Reader[EncodeTestVector] = reader[Value].map { value => - val obj = value.obj - val name = obj("name").str - val num = BigInt(obj("value").str) - val bytes = ByteVector.fromValidHex(obj("bytes").str) + implicit val encodeTestVectorR: Reader[EncodeTestVector] = reader[Value].map { + value => + val obj = value.obj + val name = obj("name").str + val num = BigInt(obj("value").str) + val bytes = ByteVector.fromValidHex(obj("bytes").str) - EncodeTestVector(name, num, bytes) + EncodeTestVector(name, num, bytes) } val encode: String = """[ @@ -117,17 +119,18 @@ object BigSizeJsonTestVectors { name: String, value: String, bytes: ByteVector, - expectedErrorOpt: Option[String]) + expectedErrorOpt: Option[String] + ) - implicit - val decodeTestVectorR: Reader[DecodeTestVector] = reader[Value].map { value => - val obj = value.obj - val name = obj("name").str - val num = obj("value").str - val bytes = ByteVector.fromValidHex(obj("bytes").str) - val expectedErrorOpt = Try(obj("exp_error").str).toOption + implicit val decodeTestVectorR: Reader[DecodeTestVector] = reader[Value].map { + value => + val obj = value.obj + val name = obj("name").str + val num = obj("value").str + val bytes = ByteVector.fromValidHex(obj("bytes").str) + val expectedErrorOpt = Try(obj("exp_error").str).toOption - DecodeTestVector(name, num, bytes, expectedErrorOpt) + DecodeTestVector(name, num, bytes, expectedErrorOpt) } val decode: String = """[ diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/BitcoinAddressTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/BitcoinAddressTest.scala index 59ba2dc885..c4420f39d2 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/BitcoinAddressTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/BitcoinAddressTest.scala @@ -81,14 +81,14 @@ class BitcoinAddressTest extends BitcoinSUnitTest { } it must "encode a pubKeyHash to an address" in { - //from https://stackoverflow.com/questions/19233053/hashing-from-a-public-key-to-a-bitcoin-address-in-php + // from https://stackoverflow.com/questions/19233053/hashing-from-a-public-key-to-a-bitcoin-address-in-php val hash = Sha256Hash160Digest("010966776006953d5567439e5e39f86a0d273bee") val address = Address("16UwLL9Risc3QfPqBUvKofHmBQ7wMtjvM") P2PKHAddress(hash, MainNet) must be(address) } it must "encode a scriptPubKey to an address" in { - //redeemScript from https://en.bitcoin.it/wiki/Pay_to_script_hash + // redeemScript from https://en.bitcoin.it/wiki/Pay_to_script_hash val hex = "455141042f90074d7a5bf30c72cf3a8dfd1381bdbd30407010e878f3a11269d5f74a58788505cdca22ea6eab7cfb40dc0e07aba200424ab0d79122a653ad0c7ec9896bdf51ae" val scriptPubKey = ScriptPubKey(hex) @@ -103,7 +103,8 @@ class BitcoinAddressTest extends BitcoinSUnitTest { it must "fail to create a bech32 address from an invalid ScriptPubKey" in { assert( - Bech32Address.fromScriptPubKeyT(EmptyScriptPubKey, RegTest).isFailure) + Bech32Address.fromScriptPubKeyT(EmptyScriptPubKey, RegTest).isFailure + ) } it must "create an address from a P2PKHScriptPubKey" in { @@ -132,18 +133,21 @@ class BitcoinAddressTest extends BitcoinSUnitTest { it must "get the same p2sh address no matter what factory function we use" in { forAll(ScriptGenerators.randomNonP2SHScriptPubKey) { case (scriptPubKey, _) => - //we should get the same address no matter which factory function we use + // we should get the same address no matter which factory function we use val p2shScriptPubKey = P2SHScriptPubKey(scriptPubKey) assert( - P2SHAddress(scriptPubKey, TestNet3) == P2SHAddress(p2shScriptPubKey, - TestNet3)) + P2SHAddress(scriptPubKey, TestNet3) == P2SHAddress( + p2shScriptPubKey, + TestNet3 + ) + ) } } it must "All p2sh addresses created from factory functions must be valid" in { forAll(ScriptGenerators.randomNonP2SHScriptPubKey) { case (scriptPubKey, _) => - //we should get the same address no matter which factory function we use + // we should get the same address no matter which factory function we use val addr = P2SHAddress(scriptPubKey, TestNet3) assert(P2SHAddress.isValid(addr.toString)) } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/CompactSizeUIntTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/CompactSizeUIntTest.scala index e19893a85e..e38306cc5e 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/CompactSizeUIntTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/CompactSizeUIntTest.scala @@ -29,17 +29,19 @@ class CompactSizeUIntTest extends BitcoinSUnitTest { it must "calculate the varint for the following hex string" in { CompactSizeUInt.calculateCompactSizeUInt("00") must be( - CompactSizeUInt(UInt64.one, 1)) + CompactSizeUInt(UInt64.one, 1) + ) - //for a string that is 256 bytes long + // for a string that is 256 bytes long val byteSeq256Size = ByteVector(Array.fill(256)(0.toByte)) CompactSizeUInt.calculateCompactSizeUInt(byteSeq256Size) must be( - CompactSizeUInt(UInt64(256), 3)) + CompactSizeUInt(UInt64(256), 3) + ) } it must "calculate the correct compact size uint for a number 515 bytes long" in { - //from the bitcoin developer reference - //https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers + // from the bitcoin developer reference + // https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers val byteSeq515Size = ByteVector(Array.fill(515)(0.toByte)) val compactSizeUInt = CompactSizeUInt.calculateCompactSizeUInt(byteSeq515Size) @@ -64,30 +66,35 @@ class CompactSizeUIntTest extends BitcoinSUnitTest { it must "parse a variable length integer (VarInt)" in { val str = "fdfd00" CompactSizeUInt.parseCompactSizeUInt(str) must be( - CompactSizeUInt(UInt64(253), 3)) + CompactSizeUInt(UInt64(253), 3) + ) val str1 = "00" CompactSizeUInt.parseCompactSizeUInt(str1) must be( - CompactSizeUInt(UInt64.zero, 1)) + CompactSizeUInt(UInt64.zero, 1) + ) val str2 = "fe20a10700" CompactSizeUInt.parseCompactSizeUInt(str2) must be( - CompactSizeUInt(UInt64(500000))) + CompactSizeUInt(UInt64(500000)) + ) val str3 = "ffffffffff" CompactSizeUInt.parseCompactSizeUInt(str3) must be( - CompactSizeUInt(UInt64(4294967295L), 9)) + CompactSizeUInt(UInt64(4294967295L), 9) + ) } it must "parse a variable length integer the same from a tx input and a script sig" in { CompactSizeUInt.parseCompactSizeUInt( - TestUtil.txInput.scriptSignature.bytes) must be( - TestUtil.txInput.scriptSignature.compactSizeUInt) + TestUtil.txInput.scriptSignature.bytes + ) must be(TestUtil.txInput.scriptSignature.compactSizeUInt) } it must "parse the variable length integer of the empty script" in { CompactSizeUInt.parseCompactSizeUInt(ScriptSignature.empty) must be( - CompactSizeUInt(UInt64.one, 1)) + CompactSizeUInt(UInt64.one, 1) + ) } it must "parse variable length integer of script sig at least 0xffff bytes in length, and greater than 0xffffffff" in { @@ -97,9 +104,11 @@ class CompactSizeUIntTest extends BitcoinSUnitTest { val s1 = c(s1NoCmpct).hex + s1NoCmpct val s2 = c(s2NoCmpct).hex + s2NoCmpct CompactSizeUInt.parseCompactSizeUInt(ScriptSignature(s1)) must be( - CompactSizeUInt(UInt64(30453), 3)) + CompactSizeUInt(UInt64(30453), 3) + ) CompactSizeUInt.parseCompactSizeUInt(ScriptSignature(s2)) must be( - CompactSizeUInt(UInt64(73085), 5)) + CompactSizeUInt(UInt64(73085), 5) + ) } it must "parse 8 bit, 16 bit, 32 bit number and 64 bit number as compactsizeuints" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/ChainParamsTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/ChainParamsTest.scala index ebbe925ada..3dfcc9cace 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/ChainParamsTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/ChainParamsTest.scala @@ -21,13 +21,15 @@ class ChainParamsTest extends BitcoinSUnitTest { val expectedGenesisScriptSig = ScriptSignature( "4D04FFFF001D0104455468652054696D65732030332F4A616E2F32303039204368616E63656C6C6F72206F6E206272696E6B206F66207365636F6E64206261696C6F757420666F722062616E6B73" - .toLowerCase()) + .toLowerCase() + ) val expectedGenesisInput = CoinbaseInput(expectedGenesisScriptSig, TransactionConstants.sequence) val expectedGenesisScriptPubKey = ScriptPubKey( - "434104678AFDB0FE5548271967F1A67130B7105CD6A828E03909A67962E0EA1F61DEB649F6BC3F4CEF38C4F35504E51EC112DE5C384DF7BA0B8D578A4C702B6BF11D5FAC".toLowerCase) + "434104678AFDB0FE5548271967F1A67130B7105CD6A828E03909A67962E0EA1F61DEB649F6BC3F4CEF38C4F35504E51EC112DE5C384DF7BA0B8D578A4C702B6BF11D5FAC".toLowerCase + ) val expectedGenesisOutput = TransactionOutput(Satoshis(5000000000L), expectedGenesisScriptPubKey) @@ -42,7 +44,8 @@ class ChainParamsTest extends BitcoinSUnitTest { } it must "hash the bitcoin genesis block" in { genesisBlock.blockHeader.hash.hex must be( - "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000") + "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" + ) } it must "compute the script signature for the coinbase tx in the mainnet genesis block" in { @@ -55,7 +58,8 @@ class ChainParamsTest extends BitcoinSUnitTest { input must be(expectedGenesisInput) input.hex must be( "0000000000000000000000000000000000000000000000000000000000000000FFFFFFFF".toLowerCase - + expectedGenesisScriptSig.hex + "FFFFFFFF".toLowerCase) + + expectedGenesisScriptSig.hex + "FFFFFFFF".toLowerCase + ) } it must "generate the correct scriptPubKey for the genesis transaction's output" in { @@ -68,7 +72,8 @@ class ChainParamsTest extends BitcoinSUnitTest { output.value must be(Satoshis(5000000000L)) output.scriptPubKey.hex must be(expectedGenesisScriptPubKey.hex) output.hex must be( - "00F2052A01000000".toLowerCase + expectedGenesisScriptPubKey.hex) + "00F2052A01000000".toLowerCase + expectedGenesisScriptPubKey.hex + ) } it must "generate the correct txid for the genesis transaction" in { @@ -79,48 +84,64 @@ class ChainParamsTest extends BitcoinSUnitTest { genesisTransaction.txId.hex must be( BytesUtil.flipEndianness( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")) + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ) + ) } it must "generate the correct merkle root for the testnet genesis block" in { TestNetChainParams.genesisBlock.blockHeader.merkleRootHash.hex must be( BytesUtil.flipEndianness( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")) + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ) + ) } it must "generate the correct block hash for the testnet genesis block" in { TestNetChainParams.genesisBlock.blockHeader.hash.hex must be( BytesUtil.flipEndianness( - "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")) + "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" + ) + ) } it must "generate the correct merkle root for the regtest genesis block" in { RegTestNetChainParams.genesisBlock.blockHeader.merkleRootHash.hex must be( BytesUtil.flipEndianness( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")) + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ) + ) } it must "generate the correct merkle root for the signet genesis block" in { SigNetChainParams().genesisBlock.blockHeader.merkleRootHashBE.hex must be( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b") + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ) } it must "generate the correct merkle root for the signet genesis block with different challenge spks" in { val default = ScriptPubKey.fromAsmHex( - "512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae") + "512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae" + ) SigNetChainParams( - default).genesisBlock.blockHeader.merkleRootHashBE.hex must be( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b") + default + ).genesisBlock.blockHeader.merkleRootHashBE.hex must be( + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ) val p2pkh = P2PKHScriptPubKey(ECPublicKey.freshPublicKey) SigNetChainParams( - p2pkh).genesisBlock.blockHeader.merkleRootHashBE.hex must be( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b") + p2pkh + ).genesisBlock.blockHeader.merkleRootHashBE.hex must be( + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ) val trivialTrue = ScriptPubKey.fromAsm(Seq(OP_TRUE)) SigNetChainParams( - trivialTrue).genesisBlock.blockHeader.merkleRootHashBE.hex must be( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b") + trivialTrue + ).genesisBlock.blockHeader.merkleRootHashBE.hex must be( + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ) } it must "generate the correct block header hex for the regtest genesis block" in { @@ -128,7 +149,8 @@ class ChainParamsTest extends BitcoinSUnitTest { "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f20020000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000" val expectedHeaderHex = regtestGenesisBlockHex.slice(0, 160) RegTestNetChainParams.genesisBlock.blockHeader.hex must be( - expectedHeaderHex) + expectedHeaderHex + ) } it must "generate the correct block hex for the regtest genesis block" in { val expectedHex = @@ -138,72 +160,86 @@ class ChainParamsTest extends BitcoinSUnitTest { it must "generate the correct blockheader hash for the genesis block on regtest" in { RegTestNetChainParams.genesisBlock.blockHeader.hash.hex must be( BytesUtil.flipEndianness( - "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")) + "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206" + ) + ) } it must "have the correct base58 prefix for MainNet" in { import Base58Type._ - //correct answers taken from https://en.bitcoin.it/wiki/List_of_address_prefixes + // correct answers taken from https://en.bitcoin.it/wiki/List_of_address_prefixes BytesUtil.encodeHex( - MainNetChainParams.base58Prefixes(PubKeyAddress)) must be("00") + MainNetChainParams.base58Prefixes(PubKeyAddress) + ) must be("00") BytesUtil.encodeHex( - MainNetChainParams.base58Prefixes(ScriptAddress)) must be("05") + MainNetChainParams.base58Prefixes(ScriptAddress) + ) must be("05") BytesUtil.encodeHex(MainNetChainParams.base58Prefixes(SecretKey)) must be( - "80") + "80" + ) BytesUtil.encodeHex( - MainNetChainParams.base58Prefixes(ExtPublicKey)) must be( - "0488B21E".toLowerCase) + MainNetChainParams.base58Prefixes(ExtPublicKey) + ) must be("0488B21E".toLowerCase) BytesUtil.encodeHex( - MainNetChainParams.base58Prefixes(ExtSecretKey)) must be( - "0488ADE4".toLowerCase) + MainNetChainParams.base58Prefixes(ExtSecretKey) + ) must be("0488ADE4".toLowerCase) } it must "have the correct base58 prefix for TestNet" in { import Base58Type._ BytesUtil.encodeHex( - TestNetChainParams.base58Prefixes(PubKeyAddress)) must be("6f") + TestNetChainParams.base58Prefixes(PubKeyAddress) + ) must be("6f") BytesUtil.encodeHex( - TestNetChainParams.base58Prefixes(ScriptAddress)) must be("c4") + TestNetChainParams.base58Prefixes(ScriptAddress) + ) must be("c4") BytesUtil.encodeHex(TestNetChainParams.base58Prefixes(SecretKey)) must be( - "ef") + "ef" + ) BytesUtil.encodeHex( - TestNetChainParams.base58Prefixes(ExtPublicKey)) must be( - "043587CF".toLowerCase) + TestNetChainParams.base58Prefixes(ExtPublicKey) + ) must be("043587CF".toLowerCase) BytesUtil.encodeHex( - TestNetChainParams.base58Prefixes(ExtSecretKey)) must be( - "04358394".toLowerCase) + TestNetChainParams.base58Prefixes(ExtSecretKey) + ) must be("04358394".toLowerCase) } it must "have the correct base58 prefix for RegTest" in { import Base58Type._ BytesUtil.encodeHex( - RegTestNetChainParams.base58Prefixes(PubKeyAddress)) must be("6f") + RegTestNetChainParams.base58Prefixes(PubKeyAddress) + ) must be("6f") BytesUtil.encodeHex( - RegTestNetChainParams.base58Prefixes(ScriptAddress)) must be("c4") + RegTestNetChainParams.base58Prefixes(ScriptAddress) + ) must be("c4") BytesUtil.encodeHex( - RegTestNetChainParams.base58Prefixes(SecretKey)) must be("ef") + RegTestNetChainParams.base58Prefixes(SecretKey) + ) must be("ef") BytesUtil.encodeHex( - RegTestNetChainParams.base58Prefixes(ExtPublicKey)) must be( - "043587CF".toLowerCase) + RegTestNetChainParams.base58Prefixes(ExtPublicKey) + ) must be("043587CF".toLowerCase) BytesUtil.encodeHex( - RegTestNetChainParams.base58Prefixes(ExtSecretKey)) must be( - "04358394".toLowerCase) + RegTestNetChainParams.base58Prefixes(ExtSecretKey) + ) must be("04358394".toLowerCase) } it must "have the correct base58 prefix for SigNet" in { import Base58Type._ BytesUtil.encodeHex( - SigNetChainParams().base58Prefixes(PubKeyAddress)) must be("6f") + SigNetChainParams().base58Prefixes(PubKeyAddress) + ) must be("6f") BytesUtil.encodeHex( - SigNetChainParams().base58Prefixes(ScriptAddress)) must be("c4") + SigNetChainParams().base58Prefixes(ScriptAddress) + ) must be("c4") BytesUtil.encodeHex(SigNetChainParams().base58Prefixes(SecretKey)) must be( - "ef") + "ef" + ) BytesUtil.encodeHex( - SigNetChainParams().base58Prefixes(ExtPublicKey)) must be( - "043587CF".toLowerCase) + SigNetChainParams().base58Prefixes(ExtPublicKey) + ) must be("043587CF".toLowerCase) BytesUtil.encodeHex( - SigNetChainParams().base58Prefixes(ExtSecretKey)) must be( - "04358394".toLowerCase) + SigNetChainParams().base58Prefixes(ExtSecretKey) + ) must be("04358394".toLowerCase) } it must "determine the correct POW intervals for bitcoin networks" in { @@ -231,9 +267,11 @@ class ChainParamsTest extends BitcoinSUnitTest { val challenge = SigNetChainParams().signetChallenge val pubKeys = Vector( ECPublicKey( - "03ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430"), + "03ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430" + ), ECPublicKey( - "0x0359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c4") + "0x0359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c4" + ) ) val expected = MultiSignatureScriptPubKey(1, pubKeys) @@ -243,11 +281,13 @@ class ChainParamsTest extends BitcoinSUnitTest { it must "compute the correct pow limits" in { val expectedTestMain = new BigInteger( "26959946667150639794667015087019630673637144422540572481103610249215", - 10) + 10 + ) val expectedRegTest = new BigInteger( "57896044618658097711785492504343953926634992332820282019728792003956564819967", - 10) + 10 + ) MainNetChainParams.powLimit must be(expectedTestMain) TestNetChainParams.powLimit must be(expectedTestMain) RegTestNetChainParams.powLimit must be(expectedRegTest) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/MerkleBlockTests.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/MerkleBlockTests.scala index fd9847e2dc..0854e48358 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/MerkleBlockTests.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/MerkleBlockTests.scala @@ -14,10 +14,13 @@ class MerkleBlockTests extends BitcoinSUnitTest { "MerkleBlocks" must "create merkle block from a block and a bloom filter" in { val block = Block( - "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000") + "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000" + ) val hash = DoubleSha256Digest( BytesUtil.flipEndianness( - "74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")) + "74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20" + ) + ) val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll).insert(hash) @@ -62,14 +65,19 @@ class MerkleBlockTests extends BitcoinSUnitTest { "7c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad9" + "2acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb4" + "6cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000" + - "001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000") + "001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000" + ) val hash1 = DoubleSha256Digest( BytesUtil.flipEndianness( - "74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")) + "74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20" + ) + ) val hash2 = DoubleSha256Digest( BytesUtil.flipEndianness( - "dd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")) + "dd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053" + ) + ) val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) .insert(hash1) @@ -80,13 +88,16 @@ class MerkleBlockTests extends BitcoinSUnitTest { } it must "match a pubkey on an output for a transaction inside of a block" in { - //mimics this test case inside of bitcoin core - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L231 + // mimics this test case inside of bitcoin core + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L231 val block = Block( - "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000") + "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000" + ) val firstTxId = DoubleSha256Digest( BytesUtil.flipEndianness( - "e980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")) + "e980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70" + ) + ) val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll).insert(firstTxId) @@ -100,33 +111,45 @@ class MerkleBlockTests extends BitcoinSUnitTest { val filterWithPubKey = filter.insert( BytesUtil.decodeHex( "044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141" + - "d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af")) + "d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af" + ) + ) val (merkleBlockWithPubKey, _) = MerkleBlock(block, filterWithPubKey) val hash1 = DoubleSha256Digest( BytesUtil.flipEndianness( - "28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f")) + "28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f" + ) + ) val hash2 = DoubleSha256Digest( BytesUtil.flipEndianness( - "6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df21bea5f4e27e2")) + "6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df21bea5f4e27e2" + ) + ) val hash3 = DoubleSha256Digest( BytesUtil.flipEndianness( - "3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")) + "3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23" + ) + ) merkleBlockWithPubKey.partialMerkleTree.extractMatches must be( - Seq(firstTxId, hash1, hash2, hash3)) + Seq(firstTxId, hash1, hash2, hash3) + ) } it must "match a transaction properly with bloom_update_none is set on the bloom filter" in { - //mimics this test case inside of core - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L286 + // mimics this test case inside of core + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L286 val block = Block( - "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000") - //first txid in the block + "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000" + ) + // first txid in the block val hash = DoubleSha256Digest( BytesUtil.flipEndianness( - "e980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")) + "e980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70" + ) + ) val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateNone).insert(hash) @@ -138,31 +161,40 @@ class MerkleBlockTests extends BitcoinSUnitTest { // This should not match the third transaction though it spends the output matched // It will match the fourth transaction, which has another pay-to-pubkey output to the same address val pubKey = ECPublicKeyBytes( - "044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af") + "044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45af" + ) val filterWithPubKey = filter.insert(pubKey.bytes) val (merkleBlockWithPubKey, _) = MerkleBlock(block, filterWithPubKey) val hash1 = DoubleSha256Digest( BytesUtil.flipEndianness( - "28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f")) + "28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f" + ) + ) val hash2 = DoubleSha256Digest( BytesUtil.flipEndianness( - "3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23")) + "3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d7007663ace63cddb23" + ) + ) merkleBlockWithPubKey.partialMerkleTree.extractMatches must be( - Seq(hash, hash1, hash2)) + Seq(hash, hash1, hash2) + ) } it must "serialize a merkle block that has a matched transaction inside of it" in { - //mimics this test case from bitcoin core - //https://github.com/bitcoin/bitcoin/blob/f17032f703288d43a76cffe8fa89b87ade9e3074/src/test/bloom_tests.cpp#L338 + // mimics this test case from bitcoin core + // https://github.com/bitcoin/bitcoin/blob/f17032f703288d43a76cffe8fa89b87ade9e3074/src/test/bloom_tests.cpp#L338 val block = Block( - "0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac00000000") - //only tx in the block + "0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b0571c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f64868137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac00000000" + ) + // only tx in the block val hash = DoubleSha256Digest( BytesUtil.flipEndianness( - "63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")) + "63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5" + ) + ) val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll).insert(hash) val (merkleBlock, _) = MerkleBlock(block, filter) @@ -179,13 +211,16 @@ class MerkleBlockTests extends BitcoinSUnitTest { } it must "mimic the merkle_block_4 test case inside of bitcoin core" in { - //mimics this test case inside of bitcoin core - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L377 + // mimics this test case inside of bitcoin core + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L377 val block = Block( - "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000") + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000" + ) val hash = DoubleSha256Digest( BytesUtil.flipEndianness( - "0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")) + "0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154" + ) + ) val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll).insert(hash) @@ -194,7 +229,9 @@ class MerkleBlockTests extends BitcoinSUnitTest { val hash2 = DoubleSha256Digest( BytesUtil.flipEndianness( - "02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")) + "02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041" + ) + ) val filter2 = filter.insert(hash2) val (merkleBlock2, _) = MerkleBlock(block, filter2) @@ -202,13 +239,15 @@ class MerkleBlockTests extends BitcoinSUnitTest { } it must "update only p2pk constants in the bloom filter when the BloomUpdateP2PKOnly flag is set" in { - //mimics this test case inside of core - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L423 + // mimics this test case inside of core + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L423 val block = Block( - "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000") + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000" + ) // the generation pubkey val pubKey = BytesUtil.decodeHex( - "04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91") + "04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91" + ) // ...and the output address of the 4th transaction val output = BytesUtil.decodeHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21") @@ -218,31 +257,39 @@ class MerkleBlockTests extends BitcoinSUnitTest { val (_, loadedFilter) = MerkleBlock(block, filter) - //this outpoint is matched because the scriptPubKey contstants match the filter + // this outpoint is matched because the scriptPubKey contstants match the filter val outPoint = TransactionOutPoint( DoubleSha256Digest( BytesUtil.flipEndianness( - "147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b")), - UInt32.zero) + "147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b" + ) + ), + UInt32.zero + ) loadedFilter.contains(outPoint) must be(true) - //this one does not match since the 4th transaction's output is not pay-to-pubkey + // this one does not match since the 4th transaction's output is not pay-to-pubkey val outPoint2 = TransactionOutPoint( DoubleSha256Digest( BytesUtil.flipEndianness( - "02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")), - UInt32.zero) + "02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041" + ) + ), + UInt32.zero + ) loadedFilter.contains(outPoint2) must be(false) } it must "update none of the constants in the bloom filter when the BloomUpdateNone flag is set" in { - //mimics this test case inside of core - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L446 + // mimics this test case inside of core + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L446 val block = Block( - "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000") + "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc880670100000000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9728776381b4d4c86041b554b85290701000000010000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0136ffffffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea10221009253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58ccb3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf49e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fcad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff309e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af83000000004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb5428f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c810ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff0100714460030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d2253d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a473044022078124c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e930220691d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a3601410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95fffffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4dafdaa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab023abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e00847147cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd701410462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffffffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c385d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758df616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11eeb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac00000000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1ac1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f00000000001976a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f00000000001976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e280007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a33ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf80125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff0100093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888ac00000000" + ) val pubKey = BytesUtil.decodeHex( "04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f134c876f2c01ec" + - "0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91") + "0f0dd5b2e86e7168cefe0d81113c3807420ce13ad1357231a2252247d97a46a91" + ) val output = BytesUtil.decodeHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21") @@ -252,26 +299,33 @@ class MerkleBlockTests extends BitcoinSUnitTest { val (_, loadedFilter) = MerkleBlock(block, filter) - //neither of these outpoints match because the BloomUpdateNone flag is set + // neither of these outpoints match because the BloomUpdateNone flag is set val outPoint = TransactionOutPoint( DoubleSha256Digest( BytesUtil.flipEndianness( - "147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b")), - UInt32.zero) + "147caa76786596590baa4e98f5d9f48b86c7765e489f7a6ff3360fe5c674360b" + ) + ), + UInt32.zero + ) loadedFilter.contains(outPoint) must be(false) val outPoint2 = TransactionOutPoint( DoubleSha256Digest( BytesUtil.flipEndianness( - "02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")), - UInt32.zero) + "02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041" + ) + ), + UInt32.zero + ) loadedFilter.contains(outPoint2) must be(false) } it must "build a merkle block with zero matches, then extract zero matches from the partial merkle tree" in { val block = Block( - "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000") - //note that there was nothing inserted into this filter + "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f0ae1d4d26e49ffff001d00f0a4410401000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d029105ffffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a6294078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc5719aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df1501ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8bbe9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c2028010000004a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391fa3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376aaa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a493046022100b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb9005c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000" + ) + // note that there was nothing inserted into this filter val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateNone) val (merkleBlock, _) = MerkleBlock(block, filter) @@ -281,20 +335,33 @@ class MerkleBlockTests extends BitcoinSUnitTest { it must "create equivalent merkle blocks if it created from a bloom filter or a sequence of txids" in { val block = Block( - "3262b4625df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456c7a266cac8e35450e0423b93743b6c84d7ceed95b888df512161c58c267042f824e234e53d85c450f52ee0ad04277aa2b104712aaa3359831e66c59bcef05d142a5fb39eca656fa8e5c56d7a84ef4523f8b36a8525e584473045022100fa3f875dc56ca67d750a98480dd62091ba5db306aa83938e221ce6893bc78f6f022041bcc644cab1a3fef3e20f30c45ebf02fbc559fa24183848d04f69613c13267e210282f8769261e6d41b92a2c0f5da838d945cf83443a500ffb6634890cc35b5af3c1976a91474afccd8daaf8002a3fe47fa38e32b18a3f3f96888ac864dd1e73dddd261dbbf721696f8a0806c8773a25791c09e2edcde3edb42d305c33ab17996bcafdafdae0100473045022100eec444dbf21c6b4666aff7988712cb453ab4b9e88339580a201e51c1f5948d5e02207609abbf8dbc5bd9e535e943ae4af288a04a289f3379f15101d3d9ae0d52585446304402203d53759c6495fdea3c35e3bb1aa54607ea33d8157412012cfa169c53fa725cc4022072762d6e12f29841a98f6621f0d41d8289fc59e01f5d2ff6b3e4c713555003b9463044022017bf9500d4365a291977ed2df6ed2ab05e5cf7362e9756b92c5fe813f6cee8f702201f130c151fdcae134954e453698b67ad84a610142584fece6d001fff6ac4eedd46304402202d273ec35117afcab9968a7ac663bc1d4548d6b5eb210307f2ac6f301d421f5802202a605ffb7d74199590f50d6fc16c57c2a97f3c27a5b68e59c014751d53a15f3e473045022100f23eb041b56f7d698814e081e4e0b8c0b80b9a073c912670c1f6528ceee1f06602202548608aaffe99a7431b0e294391cd494f490b3e0ee548eeea8db26d6ba344cd473045022100b1ef53e4924122c9dbab896207c735adcef072872551dff3b5c82f23a9f886b70220125f81b2b4cb0d5b7b5d39d4e54bb721d7984e35daa786937c5a978bf579778fc595c1506eb8b138422b7b030f333597d376cae48a2a162f8fcdb34d1367c17edac692475202893c84473045022100cf5692b94fdf9cf045627247d318ba8eb83bdaee2d86954026abf53987b64b3402206f7966290b24419dd47e630d7db7232e6ec7a4b298c9352ab4cfa20910adc3612102f0af5aa92439faf2abd642ab8303a49c227fc0e8f95deef0c04864784fce25961976a9142c24720ab39f3b158b5fd738b8f042f7fbe9648788ac0e54bb33e4688947c6b0ea2f32525f0848208590cbcd4cfa4b8e4f1ddad807ac0b12978952da44c8fd84020046304402200229543e423ee9a2f5158a3aa8f7780d16ecd45dd39d38104785be45744971a402205493995c294fbe777e757a49cd6b95a4822a2660b63fed65a4bf8ff08338e0ad463044022076cd3b02b9587a8adb4148ea950a537f20b91e0b7fe6c8bea5d2a10eda09e2370220502d0ab082222eb0115d1b55a423cc1ff873118c1a249c97e165239fd4ff2cd7473045022100f250569e6d29168dfcfb757bd71dcd9f1a72907f8d98903bb386252fd566d09202206702e8b001d424ffd0b6d924834b5f7af593f6c44a8dbd2e78e74fce07bf553746304402203cb61bc7732ae7d0f20db32c9887c1d3df8f9edb28ebbaeb5a8e879e1a17668e022000ce8c2b08fb319ce510fa86f5fcad674dfed27628c0c588ea3107760e5cfcbc473045022100ad09f0be69bf082be9507eb3e88a4bd00f2a57505cd379a31d38bafff0048133022070a224625a3035d974fa92d48aa492d1d6d71d9c5e6827b89fdcccfbccac9dd24730450221008609f7288c3e73ece5a63db8f10e52dddb549f6a6ea36bfb685466f17af91e0f022047d813a34138d871f3a2448c2e6a707b072b55d37f8628664dc5e8d6c9f87e6b4630440220098e44a7f30f423406ff10dc548a8b984cf4b51855cd3570c13b727508251383022032f253f9d34f3bd0a26ef457de5b4e7f9e0aa08efbe9644fe68ca682748b52514730450221008ab3a20a3b3314a904d02e336c8da91a0b8ae6996ac21a4dcb6a3d4cb3b757480220391bf3ce204a931ef33f64f9d50dbbdd272786e99832baa2a2454387e40e9a3146304402204f37424df7bb35aa2c60647453e9a12648c882163dc4af82f1ad6520b2daba3802207544a3efd891aff255f09e52e7805776758d63059bbdfa89def9aa54691d7b7919a460630a6a4477d3827237e6fd79015b2102a8b919462279783f36643d97d0f47289ddf1668a38351006193ef84b9c2d2d972103b5baca2b10f51b082e503bc0551d0e8aeddf7bedcdb0e41355224a4ce8d17d13210233685151ed8abafe6cb2886cd0570e1760173aa60f5f8428d68946f016e9d48b2103df9b579dde97467b32db940840130928350404bf62534e5420389bca85314fa321032c853e57d8f5071cc39bb06613646c393ee02aa8c19e04ffce61bcca6eb915e0210307305d027285bfb6e9e99ea934f2e382f5f21d9f4fe0881dee9024fc1ab6a8c82103ce8763ab2f397e1de5786bd630afa12a01c89724657fddc266dacc719bc82f962102f8b0a65653af2bf736982081021b6873b490305a9debd46c56aa568d7f905de5210301876498e73cb0fe1961610224fd900c2d9e91aec60da5966d0ecf2168d6981b2103965d912ccb7bac36628b803e3418994e43ef6eb1f68a30e7310df77fb3f519b421033513389f53d369567a7f4ae233c2b8f4d844f90313cefd6c6aa84db4321d11c45bae1b8c364b6e2f8be9fd57015821025a6d95bf4413228e74001f5384f40f3b3fbc1118e1a7864e54468f9cbf2007632102eb9f559cea1d00faad07d9a1d6d00e3fe1ab8d831f3128aa7e5733435eb46e522102c91658ba2977200559acf512eacb12287c55e189d12d402e26d0ef46d50100712103cfe92e548f583f08c90ae789d6d7f715042457a11d520ec55c4c2b25bf298f612103b949061060d317746576c1a15bb4666b5db1ee577be9b4fffd0ace3dfbff0aad2103b1bfe0d7b36744666eefbac4219ff8971e74d99c23b438566f04de6cbc8e1d9721020de7fc20e62610d39b74e695800590a0dd31f8867341dbb89b71e80ae90e660e2103f8886c1481c19819a6893e0ec7e744f0b11c07af791f980c7ef9118965450653210287dc2f87e960a2f74c5341d13ebd03bf083201d5143c9c6b47fa17c043a6eb322103317ae2c088ab99c377d8452416ef437def9faef950de5242f974461752919e785aaea9c486b9e1fff2ecfddf015e2102b1c3b280aabb6a0dc6d2316b468de14be4a1172b6886f248fbaf614990fb85252103e57dfbb3a3098efd15269c869386925ac173cd924a97a33d11384eb6553279b121039297348016892ad6f389b98d8d3e947c677e627a98493a22268ca29a6588c39d2102ad13539a531671f108a03185156b49bdc93d89d40c5bcb9d3c6d9d81ab55d5712102d5eb07a7cac45ad3562855eca2f748d6dca4381ae0b167c0d7b273bdeeadcc502102a94c7e9ad50a8c8c36ee801e4f724bbcdcd826244a1a3413d1fb7461c27daff621039688270efc35a955c0bb6a8cda0cc00646e79f98631c93b6003bafa79036b4de2103eb9de4bd49ede0107d8f53616fe1286233bcf22d8f8097c6812b24479cc4fb062102d45bdbebc933d9945a95e170ad00c2e563eea9514ac17fdde5d806e7ec15a91a210218aa00f864e6d5b198fcb2056f10ce8d5f3d851a141758191682e739c8a90e9c21020ace0019a1b9f8ef090c2c6ddb35796f907b24e5c3705af45dd238475597e69d210292a97a52e1913073e089ed29c3e5254d665a07884a39ed557badbcb948c4e7a9210213459a210153d67b4af2ed02fe228e9951572a3b383325f2f047429e89514b49210384c4ca5b44b52e26ac21ea4c7b98e79ae57f75bd528fe756aa06e5dbc8d105485eae709e07efc011445f1976a914ad7ca68463c1b3e3280698d10c4dc6e899fa992988ac92c5476f3a9507fc232103c0c90e4386820c7823f696944cb09e2417bed2797bfa80c9e8eb0e2b1a859266ac8416a4a2c219d4f91976a9140f755179ba239f8367e282cf0fa264be3a137f8388acfcbac8e89aa85170008de2412982f2458a0078d45932adb7fa51fd3501592102b7ed45c6ae164de9d8366e725d2eddcc2103c298dcc9f56b983a7189867d368a21033488822f69644d2f0e4f84753872ea7312c0b0ef4bab5019c9821da1837fbd3e21020f391cabe366c3e84a3b0f87ad9ec00d440ccb56ce88b74a1fc547ce20a1f68321022f98a0076e100eeae175b879f39bf4fb04a90b80f7dc5173e619264324c1d9e52102702c0f2ac79c62703993e1a555201a2e6197feb274e6c029f283525dad99165b210310e26b0191b3656a02fe28f84ced3ce9754bc0023744c49d17351f0a8a65b5f92103fef91df37cd5712ee3321ff8d426eb8329ec9cf894ec84e3413a7caabd96c65121034b73420408275b709690abdacbb4e52d5748272d9a09a35967de637f33427ade21034522c6680e4caf1450fc78de6220c42918cac60c478e514aa43a0c009ab52f3e59ae950dda81c8d61834232103715774fa3d6b7097d7278398a48801468c209b2310b5e33b7418358bfaf8fe36ac420ce9cd0b1672df0a6f4b273a91b36b53de0c31fff4cd2418a86ebfb1398852fe72a15e6c3cba3336431bc1df48473045022100842cf1218c0670afc5ce734b5c09e71dd7c5a6e926797fc7feca60f764a1ed330220795dcb61f0ebd50bce4080f54396a3b95e6bb954301f370106728085092d6e5460a5016987676d67d10fdde46e17a8b322d87de498cf2036840f822b2cfb8260d10dd74adcdca2bb001f398a7fc3f5e1ccc8797ec354587e81a8d799bc693b2cce90ae0460488c9d989c6b4fc3b6b109aa4746304402202ae7fe809db978c16436aabbcba866cd1cb57bed1e5e4bc673846f9fc4c8d69402202680cc0bcbc2db4eeb68e1f6ad97dc6ad4e29971e7f35a19d904adea923b996c667e25480000000000000000000000000000000000000000000000000000000000000000fffffffffd76040046304402201ad637b92394c2214c0b3e58e640bd30c5af9da5326374da54378846858edba70220014bb70fca2b610a691a97e9f317a42589e42e87ab50fc606eaa5173d8fdefc9473045022100f11ecd9d25eafac37a349e2f360f2e60c37531c5a81e477d3dc2b28d7ba81fa302202e2af213c51175d574595db73291e0eedf0c7cb52f12422d99e23428e4430ca6473045022100ff24451a87989940e582863fe837598fd4ab2832cdc797a98b6c7a42410bcb0f0220050b6b46bd0f1e5509365d697aa2f822384e9766eaa5099554a2d0e723416877463044022047c1b511c270a6464585500a7ed849405ec415e09e44c8964243c46aaa41f6f50220051a2f426d2aac9cd23a5891de2c59e3a0beb5d24c8b07ec887b80980429ae8e473045022100cff833b776c1bb01ef0a3f652b9463ed58556bd2f8a9fe8ab7fe885d35864f1802205204bed5da1cb014bc654dd5364dbb07a7773d8a91767f998b636d55d4a31f284630440220497eebd4f101899499f799709759826c58dfa9fe8be311d2d9ae828f0ab7ec2d02201c8e2233096133ba48946fe7339aa6f2d1808d8956fc833b5dc1ea3ee0848274463044022028254f4659c715a5c1e49266f6d98a04e4f65adcfe2ff75af3c6b80a9669f76b0220596f7f94c90c115e9f6b9e25c8415cccd5cb04cab02470671549b5593c6126794630440220343eebbdb960ff1c06e1d254dd0f6bf4904d5713ea54cdc818a86d33ae9faa530220138e2bc37569e590d90cc24793e3b8218f2220c15be33be5cafb8727ccaa88424630440220762aac3f639e796fa2b42341850b9255f5499cfb0ba84e61f26f137262399b5002200c994617ef82a7f33700eccd1870bd391729bb05298e8a1ab58c21259f93280b473045022100fdd74fb4ad8093c202c97fafc37e6a9859b010e337ecff804fdcd81fdc3434bd02203039317dd55ec657505a2e6ed216fa00d53403cbaa20d27214f03821b6b17ae2463044022026d4ec27f83981073cbd1af448afb31769de40a60b64e93bff395838f52fc81502201b5d0ea59f6122df641f21abf3766bc37c487af49a16f8fc2f2a1f540768e26046304402200cbe2871b0aa440073965a413d084734ef8072fe36e26757605cf834ac743789022078b7a019e0fc349c0f4c4f491a5aecf637381b24045b4740142e0f435e89daaa46304402210098d2844d368d274eeb1011ff3d0cd1a3ee708d41ec7e71876a101251f68cc1b6021f3bc0bbf056d601ad4021b82f184bbea010a6f567d6bd793300f02498ecdf8e4730450221009cab565e927f774bbfe8a3555b4a6d867d69812c1788f848f27cff97acfa640f02204902037e8f9d043d2f244da86c418706057a3ba119db5c3fbc8f8d6bf9b1705c46304402200f62a03d3cde68fce4962b4335075d6b32f35218a92237ced6c9fa0b66b2fe1e0220196ed3ff219f62dbb22dd10b3ad91c5196f634446b81267370b908a912e6c17f4630440220639e6c511c7d38a9a6366de655c00603ca5a130fc14fdff14d2d1a7432abb885022044a26760f2a07f4bf1a309e721191292f542f9d9546d911a157fef0027bccd35ffffffff9c2403ae59c02e9110817ed29c5f4cf91d57ec1d3414d122f460c21f2adb9297bf55f3ea0025057e6088f78c1046639b63b4ed955562e77f7f629cbaf4b1d4be2e2ced0b018d1e975a8bc5c9af0041c11829795d9d02bdaf081a379b384b49a9c1a893dac768a53f603f4743833baefe7cb88edd787dfd79040046304402206fc6242d402599354978ecb37941fdb4b14a8a9b2c3c9f782730e71e1cea53260220635dbadc58f8b023d5b80905bf76e9cacb9a3e3a895921c7dc22c6e2aa3a69dc4630440220325b128c5820546683fa4171b8f4415b7637106ab131f8b703e8fe59ef32245302203719a06c3ec4527e761f07ff689f776225ffeb84bd1992723275a8e08d6b459b473045022100d21b7d7df64809782fcad9e9b76f77a8f548aaf82dc6d3b9fc54991e3df85322022062f38e37ac33ba7ecc0253744a4a0ff2af9d52062b9fa721a7e13c7a7cc5f69b473045022100ecc5fe7c94253fce3acf55203333576c7bcbb2035429743fcef95ef47f24291c02207b61b895bf2cdba31f277d0dfc5abc6554a6b3dee2e7de79ae0eff1668f0c43546304402206a4c04a06b2ba0fa4d72da30d0d73f87331ce4329499819498b981604cd43fe10220561fd67cd3dbcff2b775f552ef42de8a33065f930870fe55f336d6f428c189d946304402205f2af81c4fa965b8240f2d002f181780c5c8c38f77a943676fc2233dae0bdb2102204ab3da81e6a530995ab7599b754a92458c9fff3cc839f7665bfb5831e035a5a7473045022100c526c14acf0e99d0f1c23c4b88611690005e368e462b2b89fe36e9abd735bbcf022009199362249693a9d2d8bc1a60620eb3bded8204af001ca32c1e583d23e131ca473045022100afa7986936b8c75c55cd82936af06e4d6a02ec6293af889c75e1a6ca3c404c4002205da582888215825f04f03a88050f04290460edd9e4443882cf4af152209aaa2a473045022100c395bf025a3bd5d185485e80153d4a71c90baea44db5bb8fc6a5f6f32d8f08b102202d7cda0394082da379aaab471185c83fe8c4dfd1ef846632a0ab9c3d27723f8c463044022003ae2a17e20d90bfe258ec025622d3197b08647f4633e3cfd54b66379dedf76d0220553450ca976ebc057c6ecb788bc5eb8e010098ada6c4ffe583dbee37ca99975a46304402205795d2c37ea3b7b5b9b92e5c0e418995a6fe75717072842ba25f3656bad4c7f802204d9f6a023a182345345c8ae26ff1e1e11263a815cc9ea58e73601c61c230dfc7473045022100ad73e4ccd1a8ff563bfd7634618e4d68888a586aca6a128159371f78b69673d20220426737e88fe253ea9a85d2fbb12fe3ad9d082490e4a36ea542349c2238761af147304502210095411a30a1fbd6ef0b10ab4687f76fbbfc0f6001697504843a5124edf057f92f02203e1d45eaa45b56ee23bf7d83ab81685975b4490c0d49e738c96baeff148a2e6246304402205abc0ac643fa364f7f255db235804157d124205af82e2fa473d8bb4a7905443a02200d89fc0dda126eab8cd527efa6db5b6477bf82eb01c51e79e43a10d90c907f77473045022100f63be62ca0b94516daa56a183a08c880b37519a94ff21f8b626ec24aa921009302201cd4f1f51a500a07302ebe2feceac9173f923877d1141beae3bc4bf73d375ca94630440220417157dd09ea28643e22fb6b5163a84bc2e6bd43d155c528726600d241694fca0220299a89d6c3ec259e44b973400f6db255f18a52e42a6c62d9359fba0d2184a9cb54fb9e99311f221faba429b29f400f2fdb3c1833b3514baf686c3f1427544ad01c7f276c2414f20a8346304402200128b2bd914502e18cc63e6765573b8105302e76b07e7374ce48c4f0356974e0022053f7324e6eb3bb17f7a6c9441956f87ce0e391bcc7c3fa3fbb39723b80d941ea21024e50dee9358f0df3f21b80f29e0d1bde93f606da2715adfc1af46d8aedde443b1976a914e98e951bdc4590b669d22229ec4ce022d4ab3d8088acdfb81de16a2f64140877ae666028d1d3e6af44c1f0d069b2a47621f9a92ffa285c1d153da1bdfe0afd750400473045022100c74d067d87097f5b9cca436f522ba06b01b6f0e4193a9769df5f7358d78b3156022045de7c6f8f698567c6d6d91e3aca468bb14e2db320d7a7f182efcc4bd4876154463044022048b42559b5072f8bb35fa8000c863d685d5a8c7a5e0396d482930a816540530902201ed5d6a0b01aa6a1cdd27ec247f97c850ec9b0547eadf052d4de16055bec151d46304402203cd4b099a12c13b38e8fc80843c13571180170cfd1eac8812e7ccbd5d2c76a35022015f88503c2dd1f7e433a064db7b4fba81d0bf43ee592c669b43ba3b82eb7d0234630440220215c758518fcb78449522404ad529b688aab3d8e7c7ade095bf9c5cbf96d290c02202d0f02fcd89687bea70e2e7ca49b7d780a0785560a3198ed7df6c933f444520b4630440220360e163ab8412823a5253b1c08536f2838dac8b2a80fe3cc2e2b3e1f5df2aba402203639d70befaa16a4032f7b23e683fab9a22dff834f69a75e701880d9bb59c98b463044022015bab54156dc146bf5a1e0663034730319b446196486f92fc81477ecd303f72a022010d637cc7678a534dbc95fdeaf0641afdb68e82c5113f88e462a3604a8434050473045022100ae91d38077c2859d9c3cee7bb15689b48358b39c4cf0eff3624a15a93161a8390220441c02b87634818c5378e8d515c1a06a7bd6f97a616d71e82995f7267ce4b0a546304402206a6f43abdd26c615693220f3576010bfc85c667f83c7921846fe369883d99e910220570137eedc2344cd65e76551bb872feb6e4adeb218594e8d54f02cc93307613d463044022044e7176554d1f760e40852e5d1cbeac7bfdb9a805e2d8c013b385b02e4a4813b02205bc1b86e0a8604c63a096e5f87b7c04c7af0586a56d251eff676a531a4033fb84630440220063bf6ff87a5508a57e2d2c20dad19e270b1ab7264aa517738e21d3c5dc1964002201d24f476cbef0adbd89c74d1ddf7e72980a171e2b32c32ea66dedb01e49b4ff7463044022029741e5fefb4fab7bb7fbe3084f4d6887aa72d7a40ccb613652678ff880abaaa022026eb6a412d6d946da6724c78b951959616e50343ab92f2d1c722bf54b7278f65473045022100ed5b418a85e154525ad9d0dc8d27b98c00ce215ea13960f696322fa863e9833002205302c11b9116006ce59353659ab24c5cf7e666128c97d714455b17f1cb89bf114630440220316925877b29c00c876e35cc99d76eea2e0b3dfc8bd06abdccc3bdcbd6fd0e24022043ed0bd6681e1a4ba7d187c45b1a59383e137242baaafaff8ab601c38747d1d647304502210087b711b70e09f6ef6004461d9c688909d179a4be3a9574d63e1991afa7e22c3e022021e7ca60dcb515e677bd88319289a001abe26b07415ba7dfa00e70f95be8c6cb46304402201c8eff9a5051a60649ce671d6d31c54c9759c806e157e459962551884e7ea4af02203931cbf9f333f3443701c647afe58d3c06cbb26b141db7477e79c96e4d4d34a346304402201068eaf8e6f39c0a4625ba9349222bff0df0758bcf6313b37468cedeb94de7fd02206fe06ac2de1071e46439f558a35ebf6bf8875f1a518f5ce02dc6fc3e5f611a27665f47e94672c8145cb3e2213531615df2c0aa0c686e19798d215d8597bf59bcc5c9e794a0d6048afd0d0300473045022100810e6dd7464311e36fd702e892cd12581456651281829990fa9b692ed6f175a2022043e793b1da6d5820a3ebea0a22d0f07eaed3c0900314595f34df3e850bbb628c463044022059951b253a3ef907fb29d730442f8575396f041134c9ebcc0904feca33c640ed02207402c95e35eb2c1e2d9e6d6bd4accdf6620be3695bdf3d8212cb2c8bd1f7bc7246304402204e85f8b5a378073eba40f7ff3bb3734cc2a046ea7f060bc76baf65b0e3537faf0220607b544ce22b012d88161ab8083721d6b432badeed1aa93003787d5c76b69d4b473045022100c0abae23c4ba81796792accbaa00197aa97f14d52550a2b82f3fffe30cbd134c02200798af13740a9e3c2ea4137e272cea437398c9175b4d793cb45302ba6743ca0e47304502210091ac09a00ba09ed52c8f18169a84c88ae1e029f7c20bc47c222ebd59dd016f8e02200123051d8191675b1e63c48d223ddc0d38e1fea08358b576423b721c4dc27862463044022043875a601c2e98bc00d121f9dd7618050ac94e766bf8d3a927260221abbbcc6a02204e06c2bf529a9a1b75b160bd55fd73f345d9d40ee3d4f15f984cbb01d267fa19463044022040df323c538e4c9e10cb826507cd3f83aabb0983be818313a66392e82e801a5302200a718775ac7957a9350442df421b3f6059bd6c0a32f7776bdfc6edb1da98993b463044022040f84d8d0305b8164f0a91b7b9d6f2642714bce5fda5faee5ca4ea52720f7de9022054ef4dcedfed2882de7bfdcc2613da52d6aedaec29b84aabe135d663d90b62d84ccf542102db9d09b60d6fcf50d3290e3078173af5b6cdb2454746770d6c86b3677270c6732102089b8ac6727336a8343f140b65d76c8710364b89fae5669dcd8c6aac91904e142102ac196a356bb731f225d7d0005f32b864fb3b35836a3e28460af1a622f1c383f72102efc7bef0150752d1da515c7341b645f59292cdaccc4b7a17e87edf654ac5a4d72103ff059a385cc46d299a24bc5c7737a0c9b083247919062c317bc09d77974faec72102655ff6ff38151e48e7d40ed57bed7b6573e00044c4e159bc25f5c2ac6eab31dd56ae171fbd8c07f06ded9974d5f5c7232102312239452b357f9baa50043c7256211476f9f232e18df78a6b4abadae902a5dbac88dc9ef6847a8f73fd9b01582102aa962262b31bfb5274e57ab580d86fcc0e7cf354d1d6b42cbc9f41a8b79d69ba2103713031e5678adba942aebb965a0888d287390ad48ed0397bc0f8cf60160cd4342102c22bb3c125d0d421b842c41a8c8771def88e2cf26bba157e98b7bf18e74520b82103f0122c7d62fd18a596723a2c0887f680486ca1c1953560fb9a2c6c24a1ee8cf72103a02b0b5714a30150e5ae2024d2756cace2f10f9b33d26b80885ebc30933d090921021ee25cb3f0d378b0afee856d81bbcbca63cfea35bc983b38f8e7648410aecfac210379c09f5bff3d2b7fd6217b4f0dd3772eac005ea4b95a2bbe6c321486628b72ea2102aa4aefb79b03e19dcc6a1841b22bb5c226bf9f4c28902d4bcf4a348135912a7c2102af4252f121827a5d6b5d0f8273521a25cce2e7974519e09076cb796d2d3963052102a73c8370d07ac353040bac2f5e7ee27801190192c8a3e0dac5d0a2b19a72138b210225b5ec15c1a7361ce5a1cd91ce0b302db4c5a50b38e892612054c145717c263f2102fcc0ef0d7b132d3676b8249e4419d98e51dfe63581e6cdbfb751e8fbe7d2e32b5cae6e1b9954fc0fdb2500dcf34b9a5d23f7e70069bee40d9059b48500657a120783c184161976a9147e73483c1f4136c86417440e8d72f4e1fc58d1ea88ac6bedb17b05ed790800558d11f3f42f4acb01c875118efaebb41a2f98d618ec1106e05da749ff89685db0b7d5f8b72341d20df36e04e248473045022100f6dd02d1279300343dcd8db112457f03c15c89c11daa4193428ac2a80cc51d1d022037c66ebf834afdd2cf93e15825a20b64707d7cca329bd8fe10f7a8a207b23810e137ccc003894e32f597b20a381976a914d79d883b0301f03e486a74fa01f336fd0d1faef788ac59609e26c208c8b81976a9141d321f045a5c01d5f55b68fdb12ac95330cee8ae88ac600dbecc141508d2fddf015a2102d6f03e10197ab2369668a655814412f6f5e4303c9d0fbc3bea1407c221f900c6210376ef46775288543df061dd2a2f803e9d85989e6d2dc2429580c05c459c868e842103ca600d30d649b5a750fa3a3dfe3a09f80787b6e9744eba58b87e53103e5ba09821031cefc7bb608359a0ef7422e051c7e19cea0a78e97e15c43dd13ddaf8742298b9210267c31b11df0cdd357200d1cb38c4ab39817de7da3d51b83e844f7e4cf893acdf2103c2f607a37cfea2fe5bf5710d86de41650a8b0eb8f75384b1b2c9609c0f8a06582103b82e19cdfe141147ba7f66e66f720ded742e918dba294c4d198be46db83dcbef2102df6877eb91b595f31e5af9f344a565a0a85cf35ac9c2c752893d3375471ebd9121027d8fb6d39be0d5129030a4af6170d7fd257bc6dd205e14fbfd63754aaed8855f210290218d5c8429cf03fc75f51aaa0f6fb37a22be7ff881655c8fe49a666349b6402102f86b90764a47df66c7942543c0c19ac415c8695189dd01914a427ecf870ee8bb2102431bd4bc4ae39da048b5b568b1aebb5d15809a5b892f78139a8add08cfb199932102591002d24cba0cd4cad2fd0adaa0e02713df5e8a7a6ca96b9795a6210ead17e6210276897ef141aa27ac1f97ba3d56a773f5a7db8c8fc5e29fbbaa8aa356898275015eae48105e8beb94f6ae0a87af253f805370636b637b7d2ef1d6957302107b100a42bb8c917faccf36bd87c70f0ede834630440220127371362c7136deb9e37aeec538d250d67917a22968388ff7790eebd0324632022002aaa8abc49f6b6dbcfda2d57ffebb55cfc05297379294711100a70b9279ea7a21024739035107202fdcb2792f64e50ef6dd9abfd9a25f7028a00f1300e0c54070b81976a914424ec434327e9f08eb8858f2ec81ec2caa10b32e88ac9f81580ce09e2f7de808acc88137777047f886a379cd0ae303c0d4cfbcf816e8c669e56f899962aa6b46304402204b5e43ac0637c47c8e99dec1fdd491e05b26112cca3c47d80bb04262af24527f0220336aa40ea836770e4f132e8f2219d49db0c2d671814f6c07dd1fc82494ab4b0a232102bd252e706d7105578d124c96b252c182fc9682ca94af11fb507878803f8bf7e8ace688407aa930a1f025eccf5aae0e7f640770de99d4f9aab8221b1f8d06fdb11a5d15a891ca0e8c2b48473045022100b396358637f5408a6ddf71a0a8ec64a133ee090db161898b35d14a1d20691513022062823453959072b3970fa2d8563932174bf5dea14d31aa300d2c5369780537a7c523cad80b9e72fb038694a6f4923ac38314a36b334ff0b715e2ae182a35f719640a97ab525700d7fd5a0400473045022100aea47d8bfc8f53b6d936599472382ae1bcfeafd34bac7399770e581bb7a326ad022002ef9626ec3a42d101624e77f2af34720d47cbdf73f38ec2006d93d7396f9a7b473045022100edafc6336a7b0e16124c3a7039211229e2eacb3f7ac57eeea2d5d750859b29c302206f8f8643f10cee515b43a80f6747910051d3a507e244a39513c7907306caa961463044022035ac15c56678d3efc89a36ee35d29813ee777f74c85be23d83e9739727b6334f02202acd3f036b9dd29cd530adc674250afbcdccb0bfbce5fbe9d1ae77472a6fad4e473045022100eb6d5b1f8fbbe70f99ed977eec50ded19301d501d9a3f4b4a06e6649455beb580220024d02fe5ceaa330c8bca15aaa3126e1c6590e4e714b421aa379dc2f1cbbfe2b46304402206a06d6179946eb1cddb36c456228deee4ee28ef8e9e7df5e05ef47350c73d8d202200de03f0f60ed4681f8439432917face05bc4887761a5737c5e2a8bbf97e265d6473045022100ca68aacca09a252ff295548a5ef0a8839658db1ab690f1b259e390f94e32855e02202b9fc600b03dbfb0b76dd625921f6e5bc39656467fa1d9687c0d3deb55aaa363473045022100ac7f77fbd54003c0be2abfe6454aa11d9ae6db998ee5564ca9bcae8775af00aa02206295fe0ed3f83839d2b54850d9bfbf9b938a955c33a23b71fdfda5d56f1b84d9473045022100e30e09b8889f1e281507d12ea7723a8a5a25ce5fe6ec73929e4a94506fa076bc022022ecb49151eba458dedf02c7f1bf0251240ac83c6ccf3df618a9509e6fd082f84730450221009ecdbc46eb636fb73ab81b14d439f22444a5193bdbbf38a807fca677c87de0ec02200d3e3f726a45909359cf4b585ebb86363981e68c8cce9b6deb8d669787a256d646304402206db58aaddbfba5552702f7c44308b1aea9dd494fda54848b35ff84c2c71c8a7002200379ab9584a6de6101a17a4eebdc57961e91a3dbc4ae90b9a73819b073f68f4a463044022030afd384a182a7a8641c37fd673bfe93a74819249e54dbbf6c02e93de0ab6c2f022075512e27ccac64fe2e74fc35c7e351c8db3831fab9866af1904906c4bc03ecf947304502210084cf143e0023124dc27762baa8028293a4f4f60c980e62e9a199abf572fb903a02200e3e60f4f7eef39bea41db931203581ee3ddedfc299721c8dbf2907a241fef46473045022100ca1fb3621ea238721fc6965f7efc3165c30e28fb990c3a5e76d0917eab7f22c202202135d4425f9216007818ec3e9dc05624d31c1bb2d56624f09702e682ae63b79b4630440220273a91a355ac5900f4348f18c60def28232461122831ed1161497403c972446f022044d59600632e5bbc0a5cc843f1a5d7913a75f6629085cc8b5b39f1ba81f5324c473045022100e341c40ea77d26a2da37fad74ae0927e78be3db2bec832317a0b0e4ff516e66d02200f2a39d6a9ae1f343a67c1d1c6f58466731c227dee067514049cef7418476a2125002102d64327814f691a42d3755e238919ed191f2788f7a6ce6c2dcb23139930b8c97951aefae0d75723e1503282b725d3ea2fb64bd7a8564f9b9097dca0040072c3f21221b2f208bcdece988400e113070726646c0f5bd618a638ea5ffdeed8af3e3fd9f1ed0e66f5fe7daad18600961545733cb6c248473045022100d047a5b6bb5f02ee9147fea5ad516e360aa875fd3b58f252051fd442d20b7056022050531b945683cb12e2cf99e2b74a11506905d290b377cf03cc16dc381941aa11ed4e43d41d5dc7a0042f8c5b0c0e217550498552b4d14024cb406c92f41dcedb4f07e6ab71f6ab5f6c473045022100e0500858f38ad3ec59c6271997d54a0f7679661d129c188495d08fc695e587c20220708bfc9ccb872105f6c5aa7d8586dfe9ec82145a61edf38d5ab47760869d644023210291373b7b1a1ae01203ba5ac465ab47ad2975dd46feb0c6827d38bec670d79d14ace63a901a81919b3da3bbdf48602f94df63d0ccfcc8203bb1412e88212b533350f813f9822de75420fd3b02004630440220792d4365a4b433737a83cf75f47073e5266ab28e21758fa5994f7adbe92373bd022061a9def9ce44be09c934469a771ddb0eec559f2e257da0e733f5c05cdc1af78c46304402203a5b0294c6820e652a157a9f241658c632563594e4aaf3937f5f1fd2b7e94df60220625d6dee041dcc48c15927db2a4981c7854dbad62feda43ac084948cb4c37a72473045022100f8c67a99c36a2a73a0edc5defc063a51e426d8fa08b49a709fd96e39700fc2ed02204b0aa14dd4c6000ce9554812afa6c02a5765c41c214f908201328885d25fc3f14630440220784b4d20f4c85bf4b1a68a2683d8cfb7d798909399783005e42c856bd7aebe12022071b66e455d812e13171b675dcd3bbff559a7db42b09fea12a8531f75217b474f46304402200899bb9940e1180c55fba8400fb011ac6e47f52faa54b1d818eda651f6ccb27d02202dedac2049ff98bc142f183b4129a0617f351d8e7224a8ab7a70d6e8fcd982bc473045022100a0e3d8d0848e75d89871199b6b1ecdb5ebbded25cd84b31426a3bcb911852f2b022014eb50f2c2615d825c35c29a05dcef06550b755a47a27f5bddf199312bf432f246304402200ddc04324f0a6bbd1a066477aa6d07af95f2f815cd45fa58c59858af6b525f16022034797d1d71c08dbeba4792cc0cbc9ac55d17fe114cfff1ccd3c4e2cb41610100463044022055331ce180b06b6f79c73c7a41fff0365ea2504aaaa9b9f142be7854f91d2eb002206db67280ff22164606c70a79905eb917247eaf9d5eb5cfec5343b9dd4f6aba8a2b345573014aad6f4ccf7805ae1aed6e5dfd2757458b4d3b4da52f344afbbe0ed076784cf55e17a2484730450221009bfef877e07c3ce100208dd7d522071b364df4270a5734742804e9ac2c2426740220298f95eac3d3e78e71c2cc4e6d8647acf6c53df205eab3e44aa807a7e4daf6a3cf98bc760000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff036c30f9dc1d730fa017a91476326fdefe3eb33c3fd2888e7fa809bfdc53423a8761de5c33e996eaaf232103533dc3a1bc0452280cf1f581ef4653716c02d2c709e51d2107f7a96ad68edae0ac2f54e7b569135c7dfd3501002102486f9c0dd1895e81be684a01390943457416dab4f8ee7f13cb6e342c8b0d5f692102ddb8a7ead021bf99170557d9e91787b7d6da90d51a84de5215cf48b0ff16944221037876edc52e51fa062caa4e7954d4407bb5abb5525e720a401a0524a1f4e128672102494e028fe6cde1e42309a83d8fc1e9f7aa23c683647dba1c8902b04f8ab250c42102632bdad1832f3094a27011598434b6dfd3ad5c0e324343548955b9e47699ef202102c179afe6d0a8c7ad74977ba93a31d02b3339a4fa9eaf6f594418b748fda075dd21036d1d97c281eb12ff31d4a3d6967ab5ca70f7debea1541fd827e0b7afe8a93c2c21033f0fadba950ce670f916fd98329295be45de5e3e45f21df9568e9648462d84df21033de867cc52ae1833d035de009b0d2ae72415e51aa33572f751dacdfbc264800b59ae01c3d5a4") + "3262b4625df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456c7a266cac8e35450e0423b93743b6c84d7ceed95b888df512161c58c267042f824e234e53d85c450f52ee0ad04277aa2b104712aaa3359831e66c59bcef05d142a5fb39eca656fa8e5c56d7a84ef4523f8b36a8525e584473045022100fa3f875dc56ca67d750a98480dd62091ba5db306aa83938e221ce6893bc78f6f022041bcc644cab1a3fef3e20f30c45ebf02fbc559fa24183848d04f69613c13267e210282f8769261e6d41b92a2c0f5da838d945cf83443a500ffb6634890cc35b5af3c1976a91474afccd8daaf8002a3fe47fa38e32b18a3f3f96888ac864dd1e73dddd261dbbf721696f8a0806c8773a25791c09e2edcde3edb42d305c33ab17996bcafdafdae0100473045022100eec444dbf21c6b4666aff7988712cb453ab4b9e88339580a201e51c1f5948d5e02207609abbf8dbc5bd9e535e943ae4af288a04a289f3379f15101d3d9ae0d52585446304402203d53759c6495fdea3c35e3bb1aa54607ea33d8157412012cfa169c53fa725cc4022072762d6e12f29841a98f6621f0d41d8289fc59e01f5d2ff6b3e4c713555003b9463044022017bf9500d4365a291977ed2df6ed2ab05e5cf7362e9756b92c5fe813f6cee8f702201f130c151fdcae134954e453698b67ad84a610142584fece6d001fff6ac4eedd46304402202d273ec35117afcab9968a7ac663bc1d4548d6b5eb210307f2ac6f301d421f5802202a605ffb7d74199590f50d6fc16c57c2a97f3c27a5b68e59c014751d53a15f3e473045022100f23eb041b56f7d698814e081e4e0b8c0b80b9a073c912670c1f6528ceee1f06602202548608aaffe99a7431b0e294391cd494f490b3e0ee548eeea8db26d6ba344cd473045022100b1ef53e4924122c9dbab896207c735adcef072872551dff3b5c82f23a9f886b70220125f81b2b4cb0d5b7b5d39d4e54bb721d7984e35daa786937c5a978bf579778fc595c1506eb8b138422b7b030f333597d376cae48a2a162f8fcdb34d1367c17edac692475202893c84473045022100cf5692b94fdf9cf045627247d318ba8eb83bdaee2d86954026abf53987b64b3402206f7966290b24419dd47e630d7db7232e6ec7a4b298c9352ab4cfa20910adc3612102f0af5aa92439faf2abd642ab8303a49c227fc0e8f95deef0c04864784fce25961976a9142c24720ab39f3b158b5fd738b8f042f7fbe9648788ac0e54bb33e4688947c6b0ea2f32525f0848208590cbcd4cfa4b8e4f1ddad807ac0b12978952da44c8fd84020046304402200229543e423ee9a2f5158a3aa8f7780d16ecd45dd39d38104785be45744971a402205493995c294fbe777e757a49cd6b95a4822a2660b63fed65a4bf8ff08338e0ad463044022076cd3b02b9587a8adb4148ea950a537f20b91e0b7fe6c8bea5d2a10eda09e2370220502d0ab082222eb0115d1b55a423cc1ff873118c1a249c97e165239fd4ff2cd7473045022100f250569e6d29168dfcfb757bd71dcd9f1a72907f8d98903bb386252fd566d09202206702e8b001d424ffd0b6d924834b5f7af593f6c44a8dbd2e78e74fce07bf553746304402203cb61bc7732ae7d0f20db32c9887c1d3df8f9edb28ebbaeb5a8e879e1a17668e022000ce8c2b08fb319ce510fa86f5fcad674dfed27628c0c588ea3107760e5cfcbc473045022100ad09f0be69bf082be9507eb3e88a4bd00f2a57505cd379a31d38bafff0048133022070a224625a3035d974fa92d48aa492d1d6d71d9c5e6827b89fdcccfbccac9dd24730450221008609f7288c3e73ece5a63db8f10e52dddb549f6a6ea36bfb685466f17af91e0f022047d813a34138d871f3a2448c2e6a707b072b55d37f8628664dc5e8d6c9f87e6b4630440220098e44a7f30f423406ff10dc548a8b984cf4b51855cd3570c13b727508251383022032f253f9d34f3bd0a26ef457de5b4e7f9e0aa08efbe9644fe68ca682748b52514730450221008ab3a20a3b3314a904d02e336c8da91a0b8ae6996ac21a4dcb6a3d4cb3b757480220391bf3ce204a931ef33f64f9d50dbbdd272786e99832baa2a2454387e40e9a3146304402204f37424df7bb35aa2c60647453e9a12648c882163dc4af82f1ad6520b2daba3802207544a3efd891aff255f09e52e7805776758d63059bbdfa89def9aa54691d7b7919a460630a6a4477d3827237e6fd79015b2102a8b919462279783f36643d97d0f47289ddf1668a38351006193ef84b9c2d2d972103b5baca2b10f51b082e503bc0551d0e8aeddf7bedcdb0e41355224a4ce8d17d13210233685151ed8abafe6cb2886cd0570e1760173aa60f5f8428d68946f016e9d48b2103df9b579dde97467b32db940840130928350404bf62534e5420389bca85314fa321032c853e57d8f5071cc39bb06613646c393ee02aa8c19e04ffce61bcca6eb915e0210307305d027285bfb6e9e99ea934f2e382f5f21d9f4fe0881dee9024fc1ab6a8c82103ce8763ab2f397e1de5786bd630afa12a01c89724657fddc266dacc719bc82f962102f8b0a65653af2bf736982081021b6873b490305a9debd46c56aa568d7f905de5210301876498e73cb0fe1961610224fd900c2d9e91aec60da5966d0ecf2168d6981b2103965d912ccb7bac36628b803e3418994e43ef6eb1f68a30e7310df77fb3f519b421033513389f53d369567a7f4ae233c2b8f4d844f90313cefd6c6aa84db4321d11c45bae1b8c364b6e2f8be9fd57015821025a6d95bf4413228e74001f5384f40f3b3fbc1118e1a7864e54468f9cbf2007632102eb9f559cea1d00faad07d9a1d6d00e3fe1ab8d831f3128aa7e5733435eb46e522102c91658ba2977200559acf512eacb12287c55e189d12d402e26d0ef46d50100712103cfe92e548f583f08c90ae789d6d7f715042457a11d520ec55c4c2b25bf298f612103b949061060d317746576c1a15bb4666b5db1ee577be9b4fffd0ace3dfbff0aad2103b1bfe0d7b36744666eefbac4219ff8971e74d99c23b438566f04de6cbc8e1d9721020de7fc20e62610d39b74e695800590a0dd31f8867341dbb89b71e80ae90e660e2103f8886c1481c19819a6893e0ec7e744f0b11c07af791f980c7ef9118965450653210287dc2f87e960a2f74c5341d13ebd03bf083201d5143c9c6b47fa17c043a6eb322103317ae2c088ab99c377d8452416ef437def9faef950de5242f974461752919e785aaea9c486b9e1fff2ecfddf015e2102b1c3b280aabb6a0dc6d2316b468de14be4a1172b6886f248fbaf614990fb85252103e57dfbb3a3098efd15269c869386925ac173cd924a97a33d11384eb6553279b121039297348016892ad6f389b98d8d3e947c677e627a98493a22268ca29a6588c39d2102ad13539a531671f108a03185156b49bdc93d89d40c5bcb9d3c6d9d81ab55d5712102d5eb07a7cac45ad3562855eca2f748d6dca4381ae0b167c0d7b273bdeeadcc502102a94c7e9ad50a8c8c36ee801e4f724bbcdcd826244a1a3413d1fb7461c27daff621039688270efc35a955c0bb6a8cda0cc00646e79f98631c93b6003bafa79036b4de2103eb9de4bd49ede0107d8f53616fe1286233bcf22d8f8097c6812b24479cc4fb062102d45bdbebc933d9945a95e170ad00c2e563eea9514ac17fdde5d806e7ec15a91a210218aa00f864e6d5b198fcb2056f10ce8d5f3d851a141758191682e739c8a90e9c21020ace0019a1b9f8ef090c2c6ddb35796f907b24e5c3705af45dd238475597e69d210292a97a52e1913073e089ed29c3e5254d665a07884a39ed557badbcb948c4e7a9210213459a210153d67b4af2ed02fe228e9951572a3b383325f2f047429e89514b49210384c4ca5b44b52e26ac21ea4c7b98e79ae57f75bd528fe756aa06e5dbc8d105485eae709e07efc011445f1976a914ad7ca68463c1b3e3280698d10c4dc6e899fa992988ac92c5476f3a9507fc232103c0c90e4386820c7823f696944cb09e2417bed2797bfa80c9e8eb0e2b1a859266ac8416a4a2c219d4f91976a9140f755179ba239f8367e282cf0fa264be3a137f8388acfcbac8e89aa85170008de2412982f2458a0078d45932adb7fa51fd3501592102b7ed45c6ae164de9d8366e725d2eddcc2103c298dcc9f56b983a7189867d368a21033488822f69644d2f0e4f84753872ea7312c0b0ef4bab5019c9821da1837fbd3e21020f391cabe366c3e84a3b0f87ad9ec00d440ccb56ce88b74a1fc547ce20a1f68321022f98a0076e100eeae175b879f39bf4fb04a90b80f7dc5173e619264324c1d9e52102702c0f2ac79c62703993e1a555201a2e6197feb274e6c029f283525dad99165b210310e26b0191b3656a02fe28f84ced3ce9754bc0023744c49d17351f0a8a65b5f92103fef91df37cd5712ee3321ff8d426eb8329ec9cf894ec84e3413a7caabd96c65121034b73420408275b709690abdacbb4e52d5748272d9a09a35967de637f33427ade21034522c6680e4caf1450fc78de6220c42918cac60c478e514aa43a0c009ab52f3e59ae950dda81c8d61834232103715774fa3d6b7097d7278398a48801468c209b2310b5e33b7418358bfaf8fe36ac420ce9cd0b1672df0a6f4b273a91b36b53de0c31fff4cd2418a86ebfb1398852fe72a15e6c3cba3336431bc1df48473045022100842cf1218c0670afc5ce734b5c09e71dd7c5a6e926797fc7feca60f764a1ed330220795dcb61f0ebd50bce4080f54396a3b95e6bb954301f370106728085092d6e5460a5016987676d67d10fdde46e17a8b322d87de498cf2036840f822b2cfb8260d10dd74adcdca2bb001f398a7fc3f5e1ccc8797ec354587e81a8d799bc693b2cce90ae0460488c9d989c6b4fc3b6b109aa4746304402202ae7fe809db978c16436aabbcba866cd1cb57bed1e5e4bc673846f9fc4c8d69402202680cc0bcbc2db4eeb68e1f6ad97dc6ad4e29971e7f35a19d904adea923b996c667e25480000000000000000000000000000000000000000000000000000000000000000fffffffffd76040046304402201ad637b92394c2214c0b3e58e640bd30c5af9da5326374da54378846858edba70220014bb70fca2b610a691a97e9f317a42589e42e87ab50fc606eaa5173d8fdefc9473045022100f11ecd9d25eafac37a349e2f360f2e60c37531c5a81e477d3dc2b28d7ba81fa302202e2af213c51175d574595db73291e0eedf0c7cb52f12422d99e23428e4430ca6473045022100ff24451a87989940e582863fe837598fd4ab2832cdc797a98b6c7a42410bcb0f0220050b6b46bd0f1e5509365d697aa2f822384e9766eaa5099554a2d0e723416877463044022047c1b511c270a6464585500a7ed849405ec415e09e44c8964243c46aaa41f6f50220051a2f426d2aac9cd23a5891de2c59e3a0beb5d24c8b07ec887b80980429ae8e473045022100cff833b776c1bb01ef0a3f652b9463ed58556bd2f8a9fe8ab7fe885d35864f1802205204bed5da1cb014bc654dd5364dbb07a7773d8a91767f998b636d55d4a31f284630440220497eebd4f101899499f799709759826c58dfa9fe8be311d2d9ae828f0ab7ec2d02201c8e2233096133ba48946fe7339aa6f2d1808d8956fc833b5dc1ea3ee0848274463044022028254f4659c715a5c1e49266f6d98a04e4f65adcfe2ff75af3c6b80a9669f76b0220596f7f94c90c115e9f6b9e25c8415cccd5cb04cab02470671549b5593c6126794630440220343eebbdb960ff1c06e1d254dd0f6bf4904d5713ea54cdc818a86d33ae9faa530220138e2bc37569e590d90cc24793e3b8218f2220c15be33be5cafb8727ccaa88424630440220762aac3f639e796fa2b42341850b9255f5499cfb0ba84e61f26f137262399b5002200c994617ef82a7f33700eccd1870bd391729bb05298e8a1ab58c21259f93280b473045022100fdd74fb4ad8093c202c97fafc37e6a9859b010e337ecff804fdcd81fdc3434bd02203039317dd55ec657505a2e6ed216fa00d53403cbaa20d27214f03821b6b17ae2463044022026d4ec27f83981073cbd1af448afb31769de40a60b64e93bff395838f52fc81502201b5d0ea59f6122df641f21abf3766bc37c487af49a16f8fc2f2a1f540768e26046304402200cbe2871b0aa440073965a413d084734ef8072fe36e26757605cf834ac743789022078b7a019e0fc349c0f4c4f491a5aecf637381b24045b4740142e0f435e89daaa46304402210098d2844d368d274eeb1011ff3d0cd1a3ee708d41ec7e71876a101251f68cc1b6021f3bc0bbf056d601ad4021b82f184bbea010a6f567d6bd793300f02498ecdf8e4730450221009cab565e927f774bbfe8a3555b4a6d867d69812c1788f848f27cff97acfa640f02204902037e8f9d043d2f244da86c418706057a3ba119db5c3fbc8f8d6bf9b1705c46304402200f62a03d3cde68fce4962b4335075d6b32f35218a92237ced6c9fa0b66b2fe1e0220196ed3ff219f62dbb22dd10b3ad91c5196f634446b81267370b908a912e6c17f4630440220639e6c511c7d38a9a6366de655c00603ca5a130fc14fdff14d2d1a7432abb885022044a26760f2a07f4bf1a309e721191292f542f9d9546d911a157fef0027bccd35ffffffff9c2403ae59c02e9110817ed29c5f4cf91d57ec1d3414d122f460c21f2adb9297bf55f3ea0025057e6088f78c1046639b63b4ed955562e77f7f629cbaf4b1d4be2e2ced0b018d1e975a8bc5c9af0041c11829795d9d02bdaf081a379b384b49a9c1a893dac768a53f603f4743833baefe7cb88edd787dfd79040046304402206fc6242d402599354978ecb37941fdb4b14a8a9b2c3c9f782730e71e1cea53260220635dbadc58f8b023d5b80905bf76e9cacb9a3e3a895921c7dc22c6e2aa3a69dc4630440220325b128c5820546683fa4171b8f4415b7637106ab131f8b703e8fe59ef32245302203719a06c3ec4527e761f07ff689f776225ffeb84bd1992723275a8e08d6b459b473045022100d21b7d7df64809782fcad9e9b76f77a8f548aaf82dc6d3b9fc54991e3df85322022062f38e37ac33ba7ecc0253744a4a0ff2af9d52062b9fa721a7e13c7a7cc5f69b473045022100ecc5fe7c94253fce3acf55203333576c7bcbb2035429743fcef95ef47f24291c02207b61b895bf2cdba31f277d0dfc5abc6554a6b3dee2e7de79ae0eff1668f0c43546304402206a4c04a06b2ba0fa4d72da30d0d73f87331ce4329499819498b981604cd43fe10220561fd67cd3dbcff2b775f552ef42de8a33065f930870fe55f336d6f428c189d946304402205f2af81c4fa965b8240f2d002f181780c5c8c38f77a943676fc2233dae0bdb2102204ab3da81e6a530995ab7599b754a92458c9fff3cc839f7665bfb5831e035a5a7473045022100c526c14acf0e99d0f1c23c4b88611690005e368e462b2b89fe36e9abd735bbcf022009199362249693a9d2d8bc1a60620eb3bded8204af001ca32c1e583d23e131ca473045022100afa7986936b8c75c55cd82936af06e4d6a02ec6293af889c75e1a6ca3c404c4002205da582888215825f04f03a88050f04290460edd9e4443882cf4af152209aaa2a473045022100c395bf025a3bd5d185485e80153d4a71c90baea44db5bb8fc6a5f6f32d8f08b102202d7cda0394082da379aaab471185c83fe8c4dfd1ef846632a0ab9c3d27723f8c463044022003ae2a17e20d90bfe258ec025622d3197b08647f4633e3cfd54b66379dedf76d0220553450ca976ebc057c6ecb788bc5eb8e010098ada6c4ffe583dbee37ca99975a46304402205795d2c37ea3b7b5b9b92e5c0e418995a6fe75717072842ba25f3656bad4c7f802204d9f6a023a182345345c8ae26ff1e1e11263a815cc9ea58e73601c61c230dfc7473045022100ad73e4ccd1a8ff563bfd7634618e4d68888a586aca6a128159371f78b69673d20220426737e88fe253ea9a85d2fbb12fe3ad9d082490e4a36ea542349c2238761af147304502210095411a30a1fbd6ef0b10ab4687f76fbbfc0f6001697504843a5124edf057f92f02203e1d45eaa45b56ee23bf7d83ab81685975b4490c0d49e738c96baeff148a2e6246304402205abc0ac643fa364f7f255db235804157d124205af82e2fa473d8bb4a7905443a02200d89fc0dda126eab8cd527efa6db5b6477bf82eb01c51e79e43a10d90c907f77473045022100f63be62ca0b94516daa56a183a08c880b37519a94ff21f8b626ec24aa921009302201cd4f1f51a500a07302ebe2feceac9173f923877d1141beae3bc4bf73d375ca94630440220417157dd09ea28643e22fb6b5163a84bc2e6bd43d155c528726600d241694fca0220299a89d6c3ec259e44b973400f6db255f18a52e42a6c62d9359fba0d2184a9cb54fb9e99311f221faba429b29f400f2fdb3c1833b3514baf686c3f1427544ad01c7f276c2414f20a8346304402200128b2bd914502e18cc63e6765573b8105302e76b07e7374ce48c4f0356974e0022053f7324e6eb3bb17f7a6c9441956f87ce0e391bcc7c3fa3fbb39723b80d941ea21024e50dee9358f0df3f21b80f29e0d1bde93f606da2715adfc1af46d8aedde443b1976a914e98e951bdc4590b669d22229ec4ce022d4ab3d8088acdfb81de16a2f64140877ae666028d1d3e6af44c1f0d069b2a47621f9a92ffa285c1d153da1bdfe0afd750400473045022100c74d067d87097f5b9cca436f522ba06b01b6f0e4193a9769df5f7358d78b3156022045de7c6f8f698567c6d6d91e3aca468bb14e2db320d7a7f182efcc4bd4876154463044022048b42559b5072f8bb35fa8000c863d685d5a8c7a5e0396d482930a816540530902201ed5d6a0b01aa6a1cdd27ec247f97c850ec9b0547eadf052d4de16055bec151d46304402203cd4b099a12c13b38e8fc80843c13571180170cfd1eac8812e7ccbd5d2c76a35022015f88503c2dd1f7e433a064db7b4fba81d0bf43ee592c669b43ba3b82eb7d0234630440220215c758518fcb78449522404ad529b688aab3d8e7c7ade095bf9c5cbf96d290c02202d0f02fcd89687bea70e2e7ca49b7d780a0785560a3198ed7df6c933f444520b4630440220360e163ab8412823a5253b1c08536f2838dac8b2a80fe3cc2e2b3e1f5df2aba402203639d70befaa16a4032f7b23e683fab9a22dff834f69a75e701880d9bb59c98b463044022015bab54156dc146bf5a1e0663034730319b446196486f92fc81477ecd303f72a022010d637cc7678a534dbc95fdeaf0641afdb68e82c5113f88e462a3604a8434050473045022100ae91d38077c2859d9c3cee7bb15689b48358b39c4cf0eff3624a15a93161a8390220441c02b87634818c5378e8d515c1a06a7bd6f97a616d71e82995f7267ce4b0a546304402206a6f43abdd26c615693220f3576010bfc85c667f83c7921846fe369883d99e910220570137eedc2344cd65e76551bb872feb6e4adeb218594e8d54f02cc93307613d463044022044e7176554d1f760e40852e5d1cbeac7bfdb9a805e2d8c013b385b02e4a4813b02205bc1b86e0a8604c63a096e5f87b7c04c7af0586a56d251eff676a531a4033fb84630440220063bf6ff87a5508a57e2d2c20dad19e270b1ab7264aa517738e21d3c5dc1964002201d24f476cbef0adbd89c74d1ddf7e72980a171e2b32c32ea66dedb01e49b4ff7463044022029741e5fefb4fab7bb7fbe3084f4d6887aa72d7a40ccb613652678ff880abaaa022026eb6a412d6d946da6724c78b951959616e50343ab92f2d1c722bf54b7278f65473045022100ed5b418a85e154525ad9d0dc8d27b98c00ce215ea13960f696322fa863e9833002205302c11b9116006ce59353659ab24c5cf7e666128c97d714455b17f1cb89bf114630440220316925877b29c00c876e35cc99d76eea2e0b3dfc8bd06abdccc3bdcbd6fd0e24022043ed0bd6681e1a4ba7d187c45b1a59383e137242baaafaff8ab601c38747d1d647304502210087b711b70e09f6ef6004461d9c688909d179a4be3a9574d63e1991afa7e22c3e022021e7ca60dcb515e677bd88319289a001abe26b07415ba7dfa00e70f95be8c6cb46304402201c8eff9a5051a60649ce671d6d31c54c9759c806e157e459962551884e7ea4af02203931cbf9f333f3443701c647afe58d3c06cbb26b141db7477e79c96e4d4d34a346304402201068eaf8e6f39c0a4625ba9349222bff0df0758bcf6313b37468cedeb94de7fd02206fe06ac2de1071e46439f558a35ebf6bf8875f1a518f5ce02dc6fc3e5f611a27665f47e94672c8145cb3e2213531615df2c0aa0c686e19798d215d8597bf59bcc5c9e794a0d6048afd0d0300473045022100810e6dd7464311e36fd702e892cd12581456651281829990fa9b692ed6f175a2022043e793b1da6d5820a3ebea0a22d0f07eaed3c0900314595f34df3e850bbb628c463044022059951b253a3ef907fb29d730442f8575396f041134c9ebcc0904feca33c640ed02207402c95e35eb2c1e2d9e6d6bd4accdf6620be3695bdf3d8212cb2c8bd1f7bc7246304402204e85f8b5a378073eba40f7ff3bb3734cc2a046ea7f060bc76baf65b0e3537faf0220607b544ce22b012d88161ab8083721d6b432badeed1aa93003787d5c76b69d4b473045022100c0abae23c4ba81796792accbaa00197aa97f14d52550a2b82f3fffe30cbd134c02200798af13740a9e3c2ea4137e272cea437398c9175b4d793cb45302ba6743ca0e47304502210091ac09a00ba09ed52c8f18169a84c88ae1e029f7c20bc47c222ebd59dd016f8e02200123051d8191675b1e63c48d223ddc0d38e1fea08358b576423b721c4dc27862463044022043875a601c2e98bc00d121f9dd7618050ac94e766bf8d3a927260221abbbcc6a02204e06c2bf529a9a1b75b160bd55fd73f345d9d40ee3d4f15f984cbb01d267fa19463044022040df323c538e4c9e10cb826507cd3f83aabb0983be818313a66392e82e801a5302200a718775ac7957a9350442df421b3f6059bd6c0a32f7776bdfc6edb1da98993b463044022040f84d8d0305b8164f0a91b7b9d6f2642714bce5fda5faee5ca4ea52720f7de9022054ef4dcedfed2882de7bfdcc2613da52d6aedaec29b84aabe135d663d90b62d84ccf542102db9d09b60d6fcf50d3290e3078173af5b6cdb2454746770d6c86b3677270c6732102089b8ac6727336a8343f140b65d76c8710364b89fae5669dcd8c6aac91904e142102ac196a356bb731f225d7d0005f32b864fb3b35836a3e28460af1a622f1c383f72102efc7bef0150752d1da515c7341b645f59292cdaccc4b7a17e87edf654ac5a4d72103ff059a385cc46d299a24bc5c7737a0c9b083247919062c317bc09d77974faec72102655ff6ff38151e48e7d40ed57bed7b6573e00044c4e159bc25f5c2ac6eab31dd56ae171fbd8c07f06ded9974d5f5c7232102312239452b357f9baa50043c7256211476f9f232e18df78a6b4abadae902a5dbac88dc9ef6847a8f73fd9b01582102aa962262b31bfb5274e57ab580d86fcc0e7cf354d1d6b42cbc9f41a8b79d69ba2103713031e5678adba942aebb965a0888d287390ad48ed0397bc0f8cf60160cd4342102c22bb3c125d0d421b842c41a8c8771def88e2cf26bba157e98b7bf18e74520b82103f0122c7d62fd18a596723a2c0887f680486ca1c1953560fb9a2c6c24a1ee8cf72103a02b0b5714a30150e5ae2024d2756cace2f10f9b33d26b80885ebc30933d090921021ee25cb3f0d378b0afee856d81bbcbca63cfea35bc983b38f8e7648410aecfac210379c09f5bff3d2b7fd6217b4f0dd3772eac005ea4b95a2bbe6c321486628b72ea2102aa4aefb79b03e19dcc6a1841b22bb5c226bf9f4c28902d4bcf4a348135912a7c2102af4252f121827a5d6b5d0f8273521a25cce2e7974519e09076cb796d2d3963052102a73c8370d07ac353040bac2f5e7ee27801190192c8a3e0dac5d0a2b19a72138b210225b5ec15c1a7361ce5a1cd91ce0b302db4c5a50b38e892612054c145717c263f2102fcc0ef0d7b132d3676b8249e4419d98e51dfe63581e6cdbfb751e8fbe7d2e32b5cae6e1b9954fc0fdb2500dcf34b9a5d23f7e70069bee40d9059b48500657a120783c184161976a9147e73483c1f4136c86417440e8d72f4e1fc58d1ea88ac6bedb17b05ed790800558d11f3f42f4acb01c875118efaebb41a2f98d618ec1106e05da749ff89685db0b7d5f8b72341d20df36e04e248473045022100f6dd02d1279300343dcd8db112457f03c15c89c11daa4193428ac2a80cc51d1d022037c66ebf834afdd2cf93e15825a20b64707d7cca329bd8fe10f7a8a207b23810e137ccc003894e32f597b20a381976a914d79d883b0301f03e486a74fa01f336fd0d1faef788ac59609e26c208c8b81976a9141d321f045a5c01d5f55b68fdb12ac95330cee8ae88ac600dbecc141508d2fddf015a2102d6f03e10197ab2369668a655814412f6f5e4303c9d0fbc3bea1407c221f900c6210376ef46775288543df061dd2a2f803e9d85989e6d2dc2429580c05c459c868e842103ca600d30d649b5a750fa3a3dfe3a09f80787b6e9744eba58b87e53103e5ba09821031cefc7bb608359a0ef7422e051c7e19cea0a78e97e15c43dd13ddaf8742298b9210267c31b11df0cdd357200d1cb38c4ab39817de7da3d51b83e844f7e4cf893acdf2103c2f607a37cfea2fe5bf5710d86de41650a8b0eb8f75384b1b2c9609c0f8a06582103b82e19cdfe141147ba7f66e66f720ded742e918dba294c4d198be46db83dcbef2102df6877eb91b595f31e5af9f344a565a0a85cf35ac9c2c752893d3375471ebd9121027d8fb6d39be0d5129030a4af6170d7fd257bc6dd205e14fbfd63754aaed8855f210290218d5c8429cf03fc75f51aaa0f6fb37a22be7ff881655c8fe49a666349b6402102f86b90764a47df66c7942543c0c19ac415c8695189dd01914a427ecf870ee8bb2102431bd4bc4ae39da048b5b568b1aebb5d15809a5b892f78139a8add08cfb199932102591002d24cba0cd4cad2fd0adaa0e02713df5e8a7a6ca96b9795a6210ead17e6210276897ef141aa27ac1f97ba3d56a773f5a7db8c8fc5e29fbbaa8aa356898275015eae48105e8beb94f6ae0a87af253f805370636b637b7d2ef1d6957302107b100a42bb8c917faccf36bd87c70f0ede834630440220127371362c7136deb9e37aeec538d250d67917a22968388ff7790eebd0324632022002aaa8abc49f6b6dbcfda2d57ffebb55cfc05297379294711100a70b9279ea7a21024739035107202fdcb2792f64e50ef6dd9abfd9a25f7028a00f1300e0c54070b81976a914424ec434327e9f08eb8858f2ec81ec2caa10b32e88ac9f81580ce09e2f7de808acc88137777047f886a379cd0ae303c0d4cfbcf816e8c669e56f899962aa6b46304402204b5e43ac0637c47c8e99dec1fdd491e05b26112cca3c47d80bb04262af24527f0220336aa40ea836770e4f132e8f2219d49db0c2d671814f6c07dd1fc82494ab4b0a232102bd252e706d7105578d124c96b252c182fc9682ca94af11fb507878803f8bf7e8ace688407aa930a1f025eccf5aae0e7f640770de99d4f9aab8221b1f8d06fdb11a5d15a891ca0e8c2b48473045022100b396358637f5408a6ddf71a0a8ec64a133ee090db161898b35d14a1d20691513022062823453959072b3970fa2d8563932174bf5dea14d31aa300d2c5369780537a7c523cad80b9e72fb038694a6f4923ac38314a36b334ff0b715e2ae182a35f719640a97ab525700d7fd5a0400473045022100aea47d8bfc8f53b6d936599472382ae1bcfeafd34bac7399770e581bb7a326ad022002ef9626ec3a42d101624e77f2af34720d47cbdf73f38ec2006d93d7396f9a7b473045022100edafc6336a7b0e16124c3a7039211229e2eacb3f7ac57eeea2d5d750859b29c302206f8f8643f10cee515b43a80f6747910051d3a507e244a39513c7907306caa961463044022035ac15c56678d3efc89a36ee35d29813ee777f74c85be23d83e9739727b6334f02202acd3f036b9dd29cd530adc674250afbcdccb0bfbce5fbe9d1ae77472a6fad4e473045022100eb6d5b1f8fbbe70f99ed977eec50ded19301d501d9a3f4b4a06e6649455beb580220024d02fe5ceaa330c8bca15aaa3126e1c6590e4e714b421aa379dc2f1cbbfe2b46304402206a06d6179946eb1cddb36c456228deee4ee28ef8e9e7df5e05ef47350c73d8d202200de03f0f60ed4681f8439432917face05bc4887761a5737c5e2a8bbf97e265d6473045022100ca68aacca09a252ff295548a5ef0a8839658db1ab690f1b259e390f94e32855e02202b9fc600b03dbfb0b76dd625921f6e5bc39656467fa1d9687c0d3deb55aaa363473045022100ac7f77fbd54003c0be2abfe6454aa11d9ae6db998ee5564ca9bcae8775af00aa02206295fe0ed3f83839d2b54850d9bfbf9b938a955c33a23b71fdfda5d56f1b84d9473045022100e30e09b8889f1e281507d12ea7723a8a5a25ce5fe6ec73929e4a94506fa076bc022022ecb49151eba458dedf02c7f1bf0251240ac83c6ccf3df618a9509e6fd082f84730450221009ecdbc46eb636fb73ab81b14d439f22444a5193bdbbf38a807fca677c87de0ec02200d3e3f726a45909359cf4b585ebb86363981e68c8cce9b6deb8d669787a256d646304402206db58aaddbfba5552702f7c44308b1aea9dd494fda54848b35ff84c2c71c8a7002200379ab9584a6de6101a17a4eebdc57961e91a3dbc4ae90b9a73819b073f68f4a463044022030afd384a182a7a8641c37fd673bfe93a74819249e54dbbf6c02e93de0ab6c2f022075512e27ccac64fe2e74fc35c7e351c8db3831fab9866af1904906c4bc03ecf947304502210084cf143e0023124dc27762baa8028293a4f4f60c980e62e9a199abf572fb903a02200e3e60f4f7eef39bea41db931203581ee3ddedfc299721c8dbf2907a241fef46473045022100ca1fb3621ea238721fc6965f7efc3165c30e28fb990c3a5e76d0917eab7f22c202202135d4425f9216007818ec3e9dc05624d31c1bb2d56624f09702e682ae63b79b4630440220273a91a355ac5900f4348f18c60def28232461122831ed1161497403c972446f022044d59600632e5bbc0a5cc843f1a5d7913a75f6629085cc8b5b39f1ba81f5324c473045022100e341c40ea77d26a2da37fad74ae0927e78be3db2bec832317a0b0e4ff516e66d02200f2a39d6a9ae1f343a67c1d1c6f58466731c227dee067514049cef7418476a2125002102d64327814f691a42d3755e238919ed191f2788f7a6ce6c2dcb23139930b8c97951aefae0d75723e1503282b725d3ea2fb64bd7a8564f9b9097dca0040072c3f21221b2f208bcdece988400e113070726646c0f5bd618a638ea5ffdeed8af3e3fd9f1ed0e66f5fe7daad18600961545733cb6c248473045022100d047a5b6bb5f02ee9147fea5ad516e360aa875fd3b58f252051fd442d20b7056022050531b945683cb12e2cf99e2b74a11506905d290b377cf03cc16dc381941aa11ed4e43d41d5dc7a0042f8c5b0c0e217550498552b4d14024cb406c92f41dcedb4f07e6ab71f6ab5f6c473045022100e0500858f38ad3ec59c6271997d54a0f7679661d129c188495d08fc695e587c20220708bfc9ccb872105f6c5aa7d8586dfe9ec82145a61edf38d5ab47760869d644023210291373b7b1a1ae01203ba5ac465ab47ad2975dd46feb0c6827d38bec670d79d14ace63a901a81919b3da3bbdf48602f94df63d0ccfcc8203bb1412e88212b533350f813f9822de75420fd3b02004630440220792d4365a4b433737a83cf75f47073e5266ab28e21758fa5994f7adbe92373bd022061a9def9ce44be09c934469a771ddb0eec559f2e257da0e733f5c05cdc1af78c46304402203a5b0294c6820e652a157a9f241658c632563594e4aaf3937f5f1fd2b7e94df60220625d6dee041dcc48c15927db2a4981c7854dbad62feda43ac084948cb4c37a72473045022100f8c67a99c36a2a73a0edc5defc063a51e426d8fa08b49a709fd96e39700fc2ed02204b0aa14dd4c6000ce9554812afa6c02a5765c41c214f908201328885d25fc3f14630440220784b4d20f4c85bf4b1a68a2683d8cfb7d798909399783005e42c856bd7aebe12022071b66e455d812e13171b675dcd3bbff559a7db42b09fea12a8531f75217b474f46304402200899bb9940e1180c55fba8400fb011ac6e47f52faa54b1d818eda651f6ccb27d02202dedac2049ff98bc142f183b4129a0617f351d8e7224a8ab7a70d6e8fcd982bc473045022100a0e3d8d0848e75d89871199b6b1ecdb5ebbded25cd84b31426a3bcb911852f2b022014eb50f2c2615d825c35c29a05dcef06550b755a47a27f5bddf199312bf432f246304402200ddc04324f0a6bbd1a066477aa6d07af95f2f815cd45fa58c59858af6b525f16022034797d1d71c08dbeba4792cc0cbc9ac55d17fe114cfff1ccd3c4e2cb41610100463044022055331ce180b06b6f79c73c7a41fff0365ea2504aaaa9b9f142be7854f91d2eb002206db67280ff22164606c70a79905eb917247eaf9d5eb5cfec5343b9dd4f6aba8a2b345573014aad6f4ccf7805ae1aed6e5dfd2757458b4d3b4da52f344afbbe0ed076784cf55e17a2484730450221009bfef877e07c3ce100208dd7d522071b364df4270a5734742804e9ac2c2426740220298f95eac3d3e78e71c2cc4e6d8647acf6c53df205eab3e44aa807a7e4daf6a3cf98bc760000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff036c30f9dc1d730fa017a91476326fdefe3eb33c3fd2888e7fa809bfdc53423a8761de5c33e996eaaf232103533dc3a1bc0452280cf1f581ef4653716c02d2c709e51d2107f7a96ad68edae0ac2f54e7b569135c7dfd3501002102486f9c0dd1895e81be684a01390943457416dab4f8ee7f13cb6e342c8b0d5f692102ddb8a7ead021bf99170557d9e91787b7d6da90d51a84de5215cf48b0ff16944221037876edc52e51fa062caa4e7954d4407bb5abb5525e720a401a0524a1f4e128672102494e028fe6cde1e42309a83d8fc1e9f7aa23c683647dba1c8902b04f8ab250c42102632bdad1832f3094a27011598434b6dfd3ad5c0e324343548955b9e47699ef202102c179afe6d0a8c7ad74977ba93a31d02b3339a4fa9eaf6f594418b748fda075dd21036d1d97c281eb12ff31d4a3d6967ab5ca70f7debea1541fd827e0b7afe8a93c2c21033f0fadba950ce670f916fd98329295be45de5e3e45f21df9568e9648462d84df21033de867cc52ae1833d035de009b0d2ae72415e51aa33572f751dacdfbc264800b59ae01c3d5a4" + ) val txMatches = List( - (true, - DoubleSha256Digest( - "635f69962abb6e75cc3a94b6c604ad86f33f514eef12a33fefb8ea15389b1fd9")), - (true, - DoubleSha256Digest( - "62e40ece65cff821b739f2cf310a9917c97e7475153df8a55fde1ea151731f7f")), - (true, - DoubleSha256Digest( - "889d7ede4ca91fddc32498ff1b7400526419863af3a84da2dcd24cf487fd881d")), - (true, - DoubleSha256Digest( - "dab811210e8000ac63166d032cc2347a149b2796e10b0292c249f61486e416a8")) + ( + true, + DoubleSha256Digest( + "635f69962abb6e75cc3a94b6c604ad86f33f514eef12a33fefb8ea15389b1fd9" + ) + ), + ( + true, + DoubleSha256Digest( + "62e40ece65cff821b739f2cf310a9917c97e7475153df8a55fde1ea151731f7f" + ) + ), + ( + true, + DoubleSha256Digest( + "889d7ede4ca91fddc32498ff1b7400526419863af3a84da2dcd24cf487fd881d" + ) + ), + ( + true, + DoubleSha256Digest( + "dab811210e8000ac63166d032cc2347a149b2796e10b0292c249f61486e416a8" + ) + ) ) val txIds = txMatches.map(_._2) @@ -309,43 +376,62 @@ class MerkleBlockTests extends BitcoinSUnitTest { it must "create the exact same partial merkle tree from the info stored in the merkle block" in { val block = Block( - "3262b4625df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456c7a266cac8e35450e0423b93743b6c84d7ceed95b888df512161c58c267042f824e234e53d85c450f52ee0ad04277aa2b104712aaa3359831e66c59bcef05d142a5fb39eca656fa8e5c56d7a84ef4523f8b36a8525e584473045022100fa3f875dc56ca67d750a98480dd62091ba5db306aa83938e221ce6893bc78f6f022041bcc644cab1a3fef3e20f30c45ebf02fbc559fa24183848d04f69613c13267e210282f8769261e6d41b92a2c0f5da838d945cf83443a500ffb6634890cc35b5af3c1976a91474afccd8daaf8002a3fe47fa38e32b18a3f3f96888ac864dd1e73dddd261dbbf721696f8a0806c8773a25791c09e2edcde3edb42d305c33ab17996bcafdafdae0100473045022100eec444dbf21c6b4666aff7988712cb453ab4b9e88339580a201e51c1f5948d5e02207609abbf8dbc5bd9e535e943ae4af288a04a289f3379f15101d3d9ae0d52585446304402203d53759c6495fdea3c35e3bb1aa54607ea33d8157412012cfa169c53fa725cc4022072762d6e12f29841a98f6621f0d41d8289fc59e01f5d2ff6b3e4c713555003b9463044022017bf9500d4365a291977ed2df6ed2ab05e5cf7362e9756b92c5fe813f6cee8f702201f130c151fdcae134954e453698b67ad84a610142584fece6d001fff6ac4eedd46304402202d273ec35117afcab9968a7ac663bc1d4548d6b5eb210307f2ac6f301d421f5802202a605ffb7d74199590f50d6fc16c57c2a97f3c27a5b68e59c014751d53a15f3e473045022100f23eb041b56f7d698814e081e4e0b8c0b80b9a073c912670c1f6528ceee1f06602202548608aaffe99a7431b0e294391cd494f490b3e0ee548eeea8db26d6ba344cd473045022100b1ef53e4924122c9dbab896207c735adcef072872551dff3b5c82f23a9f886b70220125f81b2b4cb0d5b7b5d39d4e54bb721d7984e35daa786937c5a978bf579778fc595c1506eb8b138422b7b030f333597d376cae48a2a162f8fcdb34d1367c17edac692475202893c84473045022100cf5692b94fdf9cf045627247d318ba8eb83bdaee2d86954026abf53987b64b3402206f7966290b24419dd47e630d7db7232e6ec7a4b298c9352ab4cfa20910adc3612102f0af5aa92439faf2abd642ab8303a49c227fc0e8f95deef0c04864784fce25961976a9142c24720ab39f3b158b5fd738b8f042f7fbe9648788ac0e54bb33e4688947c6b0ea2f32525f0848208590cbcd4cfa4b8e4f1ddad807ac0b12978952da44c8fd84020046304402200229543e423ee9a2f5158a3aa8f7780d16ecd45dd39d38104785be45744971a402205493995c294fbe777e757a49cd6b95a4822a2660b63fed65a4bf8ff08338e0ad463044022076cd3b02b9587a8adb4148ea950a537f20b91e0b7fe6c8bea5d2a10eda09e2370220502d0ab082222eb0115d1b55a423cc1ff873118c1a249c97e165239fd4ff2cd7473045022100f250569e6d29168dfcfb757bd71dcd9f1a72907f8d98903bb386252fd566d09202206702e8b001d424ffd0b6d924834b5f7af593f6c44a8dbd2e78e74fce07bf553746304402203cb61bc7732ae7d0f20db32c9887c1d3df8f9edb28ebbaeb5a8e879e1a17668e022000ce8c2b08fb319ce510fa86f5fcad674dfed27628c0c588ea3107760e5cfcbc473045022100ad09f0be69bf082be9507eb3e88a4bd00f2a57505cd379a31d38bafff0048133022070a224625a3035d974fa92d48aa492d1d6d71d9c5e6827b89fdcccfbccac9dd24730450221008609f7288c3e73ece5a63db8f10e52dddb549f6a6ea36bfb685466f17af91e0f022047d813a34138d871f3a2448c2e6a707b072b55d37f8628664dc5e8d6c9f87e6b4630440220098e44a7f30f423406ff10dc548a8b984cf4b51855cd3570c13b727508251383022032f253f9d34f3bd0a26ef457de5b4e7f9e0aa08efbe9644fe68ca682748b52514730450221008ab3a20a3b3314a904d02e336c8da91a0b8ae6996ac21a4dcb6a3d4cb3b757480220391bf3ce204a931ef33f64f9d50dbbdd272786e99832baa2a2454387e40e9a3146304402204f37424df7bb35aa2c60647453e9a12648c882163dc4af82f1ad6520b2daba3802207544a3efd891aff255f09e52e7805776758d63059bbdfa89def9aa54691d7b7919a460630a6a4477d3827237e6fd79015b2102a8b919462279783f36643d97d0f47289ddf1668a38351006193ef84b9c2d2d972103b5baca2b10f51b082e503bc0551d0e8aeddf7bedcdb0e41355224a4ce8d17d13210233685151ed8abafe6cb2886cd0570e1760173aa60f5f8428d68946f016e9d48b2103df9b579dde97467b32db940840130928350404bf62534e5420389bca85314fa321032c853e57d8f5071cc39bb06613646c393ee02aa8c19e04ffce61bcca6eb915e0210307305d027285bfb6e9e99ea934f2e382f5f21d9f4fe0881dee9024fc1ab6a8c82103ce8763ab2f397e1de5786bd630afa12a01c89724657fddc266dacc719bc82f962102f8b0a65653af2bf736982081021b6873b490305a9debd46c56aa568d7f905de5210301876498e73cb0fe1961610224fd900c2d9e91aec60da5966d0ecf2168d6981b2103965d912ccb7bac36628b803e3418994e43ef6eb1f68a30e7310df77fb3f519b421033513389f53d369567a7f4ae233c2b8f4d844f90313cefd6c6aa84db4321d11c45bae1b8c364b6e2f8be9fd57015821025a6d95bf4413228e74001f5384f40f3b3fbc1118e1a7864e54468f9cbf2007632102eb9f559cea1d00faad07d9a1d6d00e3fe1ab8d831f3128aa7e5733435eb46e522102c91658ba2977200559acf512eacb12287c55e189d12d402e26d0ef46d50100712103cfe92e548f583f08c90ae789d6d7f715042457a11d520ec55c4c2b25bf298f612103b949061060d317746576c1a15bb4666b5db1ee577be9b4fffd0ace3dfbff0aad2103b1bfe0d7b36744666eefbac4219ff8971e74d99c23b438566f04de6cbc8e1d9721020de7fc20e62610d39b74e695800590a0dd31f8867341dbb89b71e80ae90e660e2103f8886c1481c19819a6893e0ec7e744f0b11c07af791f980c7ef9118965450653210287dc2f87e960a2f74c5341d13ebd03bf083201d5143c9c6b47fa17c043a6eb322103317ae2c088ab99c377d8452416ef437def9faef950de5242f974461752919e785aaea9c486b9e1fff2ecfddf015e2102b1c3b280aabb6a0dc6d2316b468de14be4a1172b6886f248fbaf614990fb85252103e57dfbb3a3098efd15269c869386925ac173cd924a97a33d11384eb6553279b121039297348016892ad6f389b98d8d3e947c677e627a98493a22268ca29a6588c39d2102ad13539a531671f108a03185156b49bdc93d89d40c5bcb9d3c6d9d81ab55d5712102d5eb07a7cac45ad3562855eca2f748d6dca4381ae0b167c0d7b273bdeeadcc502102a94c7e9ad50a8c8c36ee801e4f724bbcdcd826244a1a3413d1fb7461c27daff621039688270efc35a955c0bb6a8cda0cc00646e79f98631c93b6003bafa79036b4de2103eb9de4bd49ede0107d8f53616fe1286233bcf22d8f8097c6812b24479cc4fb062102d45bdbebc933d9945a95e170ad00c2e563eea9514ac17fdde5d806e7ec15a91a210218aa00f864e6d5b198fcb2056f10ce8d5f3d851a141758191682e739c8a90e9c21020ace0019a1b9f8ef090c2c6ddb35796f907b24e5c3705af45dd238475597e69d210292a97a52e1913073e089ed29c3e5254d665a07884a39ed557badbcb948c4e7a9210213459a210153d67b4af2ed02fe228e9951572a3b383325f2f047429e89514b49210384c4ca5b44b52e26ac21ea4c7b98e79ae57f75bd528fe756aa06e5dbc8d105485eae709e07efc011445f1976a914ad7ca68463c1b3e3280698d10c4dc6e899fa992988ac92c5476f3a9507fc232103c0c90e4386820c7823f696944cb09e2417bed2797bfa80c9e8eb0e2b1a859266ac8416a4a2c219d4f91976a9140f755179ba239f8367e282cf0fa264be3a137f8388acfcbac8e89aa85170008de2412982f2458a0078d45932adb7fa51fd3501592102b7ed45c6ae164de9d8366e725d2eddcc2103c298dcc9f56b983a7189867d368a21033488822f69644d2f0e4f84753872ea7312c0b0ef4bab5019c9821da1837fbd3e21020f391cabe366c3e84a3b0f87ad9ec00d440ccb56ce88b74a1fc547ce20a1f68321022f98a0076e100eeae175b879f39bf4fb04a90b80f7dc5173e619264324c1d9e52102702c0f2ac79c62703993e1a555201a2e6197feb274e6c029f283525dad99165b210310e26b0191b3656a02fe28f84ced3ce9754bc0023744c49d17351f0a8a65b5f92103fef91df37cd5712ee3321ff8d426eb8329ec9cf894ec84e3413a7caabd96c65121034b73420408275b709690abdacbb4e52d5748272d9a09a35967de637f33427ade21034522c6680e4caf1450fc78de6220c42918cac60c478e514aa43a0c009ab52f3e59ae950dda81c8d61834232103715774fa3d6b7097d7278398a48801468c209b2310b5e33b7418358bfaf8fe36ac420ce9cd0b1672df0a6f4b273a91b36b53de0c31fff4cd2418a86ebfb1398852fe72a15e6c3cba3336431bc1df48473045022100842cf1218c0670afc5ce734b5c09e71dd7c5a6e926797fc7feca60f764a1ed330220795dcb61f0ebd50bce4080f54396a3b95e6bb954301f370106728085092d6e5460a5016987676d67d10fdde46e17a8b322d87de498cf2036840f822b2cfb8260d10dd74adcdca2bb001f398a7fc3f5e1ccc8797ec354587e81a8d799bc693b2cce90ae0460488c9d989c6b4fc3b6b109aa4746304402202ae7fe809db978c16436aabbcba866cd1cb57bed1e5e4bc673846f9fc4c8d69402202680cc0bcbc2db4eeb68e1f6ad97dc6ad4e29971e7f35a19d904adea923b996c667e25480000000000000000000000000000000000000000000000000000000000000000fffffffffd76040046304402201ad637b92394c2214c0b3e58e640bd30c5af9da5326374da54378846858edba70220014bb70fca2b610a691a97e9f317a42589e42e87ab50fc606eaa5173d8fdefc9473045022100f11ecd9d25eafac37a349e2f360f2e60c37531c5a81e477d3dc2b28d7ba81fa302202e2af213c51175d574595db73291e0eedf0c7cb52f12422d99e23428e4430ca6473045022100ff24451a87989940e582863fe837598fd4ab2832cdc797a98b6c7a42410bcb0f0220050b6b46bd0f1e5509365d697aa2f822384e9766eaa5099554a2d0e723416877463044022047c1b511c270a6464585500a7ed849405ec415e09e44c8964243c46aaa41f6f50220051a2f426d2aac9cd23a5891de2c59e3a0beb5d24c8b07ec887b80980429ae8e473045022100cff833b776c1bb01ef0a3f652b9463ed58556bd2f8a9fe8ab7fe885d35864f1802205204bed5da1cb014bc654dd5364dbb07a7773d8a91767f998b636d55d4a31f284630440220497eebd4f101899499f799709759826c58dfa9fe8be311d2d9ae828f0ab7ec2d02201c8e2233096133ba48946fe7339aa6f2d1808d8956fc833b5dc1ea3ee0848274463044022028254f4659c715a5c1e49266f6d98a04e4f65adcfe2ff75af3c6b80a9669f76b0220596f7f94c90c115e9f6b9e25c8415cccd5cb04cab02470671549b5593c6126794630440220343eebbdb960ff1c06e1d254dd0f6bf4904d5713ea54cdc818a86d33ae9faa530220138e2bc37569e590d90cc24793e3b8218f2220c15be33be5cafb8727ccaa88424630440220762aac3f639e796fa2b42341850b9255f5499cfb0ba84e61f26f137262399b5002200c994617ef82a7f33700eccd1870bd391729bb05298e8a1ab58c21259f93280b473045022100fdd74fb4ad8093c202c97fafc37e6a9859b010e337ecff804fdcd81fdc3434bd02203039317dd55ec657505a2e6ed216fa00d53403cbaa20d27214f03821b6b17ae2463044022026d4ec27f83981073cbd1af448afb31769de40a60b64e93bff395838f52fc81502201b5d0ea59f6122df641f21abf3766bc37c487af49a16f8fc2f2a1f540768e26046304402200cbe2871b0aa440073965a413d084734ef8072fe36e26757605cf834ac743789022078b7a019e0fc349c0f4c4f491a5aecf637381b24045b4740142e0f435e89daaa46304402210098d2844d368d274eeb1011ff3d0cd1a3ee708d41ec7e71876a101251f68cc1b6021f3bc0bbf056d601ad4021b82f184bbea010a6f567d6bd793300f02498ecdf8e4730450221009cab565e927f774bbfe8a3555b4a6d867d69812c1788f848f27cff97acfa640f02204902037e8f9d043d2f244da86c418706057a3ba119db5c3fbc8f8d6bf9b1705c46304402200f62a03d3cde68fce4962b4335075d6b32f35218a92237ced6c9fa0b66b2fe1e0220196ed3ff219f62dbb22dd10b3ad91c5196f634446b81267370b908a912e6c17f4630440220639e6c511c7d38a9a6366de655c00603ca5a130fc14fdff14d2d1a7432abb885022044a26760f2a07f4bf1a309e721191292f542f9d9546d911a157fef0027bccd35ffffffff9c2403ae59c02e9110817ed29c5f4cf91d57ec1d3414d122f460c21f2adb9297bf55f3ea0025057e6088f78c1046639b63b4ed955562e77f7f629cbaf4b1d4be2e2ced0b018d1e975a8bc5c9af0041c11829795d9d02bdaf081a379b384b49a9c1a893dac768a53f603f4743833baefe7cb88edd787dfd79040046304402206fc6242d402599354978ecb37941fdb4b14a8a9b2c3c9f782730e71e1cea53260220635dbadc58f8b023d5b80905bf76e9cacb9a3e3a895921c7dc22c6e2aa3a69dc4630440220325b128c5820546683fa4171b8f4415b7637106ab131f8b703e8fe59ef32245302203719a06c3ec4527e761f07ff689f776225ffeb84bd1992723275a8e08d6b459b473045022100d21b7d7df64809782fcad9e9b76f77a8f548aaf82dc6d3b9fc54991e3df85322022062f38e37ac33ba7ecc0253744a4a0ff2af9d52062b9fa721a7e13c7a7cc5f69b473045022100ecc5fe7c94253fce3acf55203333576c7bcbb2035429743fcef95ef47f24291c02207b61b895bf2cdba31f277d0dfc5abc6554a6b3dee2e7de79ae0eff1668f0c43546304402206a4c04a06b2ba0fa4d72da30d0d73f87331ce4329499819498b981604cd43fe10220561fd67cd3dbcff2b775f552ef42de8a33065f930870fe55f336d6f428c189d946304402205f2af81c4fa965b8240f2d002f181780c5c8c38f77a943676fc2233dae0bdb2102204ab3da81e6a530995ab7599b754a92458c9fff3cc839f7665bfb5831e035a5a7473045022100c526c14acf0e99d0f1c23c4b88611690005e368e462b2b89fe36e9abd735bbcf022009199362249693a9d2d8bc1a60620eb3bded8204af001ca32c1e583d23e131ca473045022100afa7986936b8c75c55cd82936af06e4d6a02ec6293af889c75e1a6ca3c404c4002205da582888215825f04f03a88050f04290460edd9e4443882cf4af152209aaa2a473045022100c395bf025a3bd5d185485e80153d4a71c90baea44db5bb8fc6a5f6f32d8f08b102202d7cda0394082da379aaab471185c83fe8c4dfd1ef846632a0ab9c3d27723f8c463044022003ae2a17e20d90bfe258ec025622d3197b08647f4633e3cfd54b66379dedf76d0220553450ca976ebc057c6ecb788bc5eb8e010098ada6c4ffe583dbee37ca99975a46304402205795d2c37ea3b7b5b9b92e5c0e418995a6fe75717072842ba25f3656bad4c7f802204d9f6a023a182345345c8ae26ff1e1e11263a815cc9ea58e73601c61c230dfc7473045022100ad73e4ccd1a8ff563bfd7634618e4d68888a586aca6a128159371f78b69673d20220426737e88fe253ea9a85d2fbb12fe3ad9d082490e4a36ea542349c2238761af147304502210095411a30a1fbd6ef0b10ab4687f76fbbfc0f6001697504843a5124edf057f92f02203e1d45eaa45b56ee23bf7d83ab81685975b4490c0d49e738c96baeff148a2e6246304402205abc0ac643fa364f7f255db235804157d124205af82e2fa473d8bb4a7905443a02200d89fc0dda126eab8cd527efa6db5b6477bf82eb01c51e79e43a10d90c907f77473045022100f63be62ca0b94516daa56a183a08c880b37519a94ff21f8b626ec24aa921009302201cd4f1f51a500a07302ebe2feceac9173f923877d1141beae3bc4bf73d375ca94630440220417157dd09ea28643e22fb6b5163a84bc2e6bd43d155c528726600d241694fca0220299a89d6c3ec259e44b973400f6db255f18a52e42a6c62d9359fba0d2184a9cb54fb9e99311f221faba429b29f400f2fdb3c1833b3514baf686c3f1427544ad01c7f276c2414f20a8346304402200128b2bd914502e18cc63e6765573b8105302e76b07e7374ce48c4f0356974e0022053f7324e6eb3bb17f7a6c9441956f87ce0e391bcc7c3fa3fbb39723b80d941ea21024e50dee9358f0df3f21b80f29e0d1bde93f606da2715adfc1af46d8aedde443b1976a914e98e951bdc4590b669d22229ec4ce022d4ab3d8088acdfb81de16a2f64140877ae666028d1d3e6af44c1f0d069b2a47621f9a92ffa285c1d153da1bdfe0afd750400473045022100c74d067d87097f5b9cca436f522ba06b01b6f0e4193a9769df5f7358d78b3156022045de7c6f8f698567c6d6d91e3aca468bb14e2db320d7a7f182efcc4bd4876154463044022048b42559b5072f8bb35fa8000c863d685d5a8c7a5e0396d482930a816540530902201ed5d6a0b01aa6a1cdd27ec247f97c850ec9b0547eadf052d4de16055bec151d46304402203cd4b099a12c13b38e8fc80843c13571180170cfd1eac8812e7ccbd5d2c76a35022015f88503c2dd1f7e433a064db7b4fba81d0bf43ee592c669b43ba3b82eb7d0234630440220215c758518fcb78449522404ad529b688aab3d8e7c7ade095bf9c5cbf96d290c02202d0f02fcd89687bea70e2e7ca49b7d780a0785560a3198ed7df6c933f444520b4630440220360e163ab8412823a5253b1c08536f2838dac8b2a80fe3cc2e2b3e1f5df2aba402203639d70befaa16a4032f7b23e683fab9a22dff834f69a75e701880d9bb59c98b463044022015bab54156dc146bf5a1e0663034730319b446196486f92fc81477ecd303f72a022010d637cc7678a534dbc95fdeaf0641afdb68e82c5113f88e462a3604a8434050473045022100ae91d38077c2859d9c3cee7bb15689b48358b39c4cf0eff3624a15a93161a8390220441c02b87634818c5378e8d515c1a06a7bd6f97a616d71e82995f7267ce4b0a546304402206a6f43abdd26c615693220f3576010bfc85c667f83c7921846fe369883d99e910220570137eedc2344cd65e76551bb872feb6e4adeb218594e8d54f02cc93307613d463044022044e7176554d1f760e40852e5d1cbeac7bfdb9a805e2d8c013b385b02e4a4813b02205bc1b86e0a8604c63a096e5f87b7c04c7af0586a56d251eff676a531a4033fb84630440220063bf6ff87a5508a57e2d2c20dad19e270b1ab7264aa517738e21d3c5dc1964002201d24f476cbef0adbd89c74d1ddf7e72980a171e2b32c32ea66dedb01e49b4ff7463044022029741e5fefb4fab7bb7fbe3084f4d6887aa72d7a40ccb613652678ff880abaaa022026eb6a412d6d946da6724c78b951959616e50343ab92f2d1c722bf54b7278f65473045022100ed5b418a85e154525ad9d0dc8d27b98c00ce215ea13960f696322fa863e9833002205302c11b9116006ce59353659ab24c5cf7e666128c97d714455b17f1cb89bf114630440220316925877b29c00c876e35cc99d76eea2e0b3dfc8bd06abdccc3bdcbd6fd0e24022043ed0bd6681e1a4ba7d187c45b1a59383e137242baaafaff8ab601c38747d1d647304502210087b711b70e09f6ef6004461d9c688909d179a4be3a9574d63e1991afa7e22c3e022021e7ca60dcb515e677bd88319289a001abe26b07415ba7dfa00e70f95be8c6cb46304402201c8eff9a5051a60649ce671d6d31c54c9759c806e157e459962551884e7ea4af02203931cbf9f333f3443701c647afe58d3c06cbb26b141db7477e79c96e4d4d34a346304402201068eaf8e6f39c0a4625ba9349222bff0df0758bcf6313b37468cedeb94de7fd02206fe06ac2de1071e46439f558a35ebf6bf8875f1a518f5ce02dc6fc3e5f611a27665f47e94672c8145cb3e2213531615df2c0aa0c686e19798d215d8597bf59bcc5c9e794a0d6048afd0d0300473045022100810e6dd7464311e36fd702e892cd12581456651281829990fa9b692ed6f175a2022043e793b1da6d5820a3ebea0a22d0f07eaed3c0900314595f34df3e850bbb628c463044022059951b253a3ef907fb29d730442f8575396f041134c9ebcc0904feca33c640ed02207402c95e35eb2c1e2d9e6d6bd4accdf6620be3695bdf3d8212cb2c8bd1f7bc7246304402204e85f8b5a378073eba40f7ff3bb3734cc2a046ea7f060bc76baf65b0e3537faf0220607b544ce22b012d88161ab8083721d6b432badeed1aa93003787d5c76b69d4b473045022100c0abae23c4ba81796792accbaa00197aa97f14d52550a2b82f3fffe30cbd134c02200798af13740a9e3c2ea4137e272cea437398c9175b4d793cb45302ba6743ca0e47304502210091ac09a00ba09ed52c8f18169a84c88ae1e029f7c20bc47c222ebd59dd016f8e02200123051d8191675b1e63c48d223ddc0d38e1fea08358b576423b721c4dc27862463044022043875a601c2e98bc00d121f9dd7618050ac94e766bf8d3a927260221abbbcc6a02204e06c2bf529a9a1b75b160bd55fd73f345d9d40ee3d4f15f984cbb01d267fa19463044022040df323c538e4c9e10cb826507cd3f83aabb0983be818313a66392e82e801a5302200a718775ac7957a9350442df421b3f6059bd6c0a32f7776bdfc6edb1da98993b463044022040f84d8d0305b8164f0a91b7b9d6f2642714bce5fda5faee5ca4ea52720f7de9022054ef4dcedfed2882de7bfdcc2613da52d6aedaec29b84aabe135d663d90b62d84ccf542102db9d09b60d6fcf50d3290e3078173af5b6cdb2454746770d6c86b3677270c6732102089b8ac6727336a8343f140b65d76c8710364b89fae5669dcd8c6aac91904e142102ac196a356bb731f225d7d0005f32b864fb3b35836a3e28460af1a622f1c383f72102efc7bef0150752d1da515c7341b645f59292cdaccc4b7a17e87edf654ac5a4d72103ff059a385cc46d299a24bc5c7737a0c9b083247919062c317bc09d77974faec72102655ff6ff38151e48e7d40ed57bed7b6573e00044c4e159bc25f5c2ac6eab31dd56ae171fbd8c07f06ded9974d5f5c7232102312239452b357f9baa50043c7256211476f9f232e18df78a6b4abadae902a5dbac88dc9ef6847a8f73fd9b01582102aa962262b31bfb5274e57ab580d86fcc0e7cf354d1d6b42cbc9f41a8b79d69ba2103713031e5678adba942aebb965a0888d287390ad48ed0397bc0f8cf60160cd4342102c22bb3c125d0d421b842c41a8c8771def88e2cf26bba157e98b7bf18e74520b82103f0122c7d62fd18a596723a2c0887f680486ca1c1953560fb9a2c6c24a1ee8cf72103a02b0b5714a30150e5ae2024d2756cace2f10f9b33d26b80885ebc30933d090921021ee25cb3f0d378b0afee856d81bbcbca63cfea35bc983b38f8e7648410aecfac210379c09f5bff3d2b7fd6217b4f0dd3772eac005ea4b95a2bbe6c321486628b72ea2102aa4aefb79b03e19dcc6a1841b22bb5c226bf9f4c28902d4bcf4a348135912a7c2102af4252f121827a5d6b5d0f8273521a25cce2e7974519e09076cb796d2d3963052102a73c8370d07ac353040bac2f5e7ee27801190192c8a3e0dac5d0a2b19a72138b210225b5ec15c1a7361ce5a1cd91ce0b302db4c5a50b38e892612054c145717c263f2102fcc0ef0d7b132d3676b8249e4419d98e51dfe63581e6cdbfb751e8fbe7d2e32b5cae6e1b9954fc0fdb2500dcf34b9a5d23f7e70069bee40d9059b48500657a120783c184161976a9147e73483c1f4136c86417440e8d72f4e1fc58d1ea88ac6bedb17b05ed790800558d11f3f42f4acb01c875118efaebb41a2f98d618ec1106e05da749ff89685db0b7d5f8b72341d20df36e04e248473045022100f6dd02d1279300343dcd8db112457f03c15c89c11daa4193428ac2a80cc51d1d022037c66ebf834afdd2cf93e15825a20b64707d7cca329bd8fe10f7a8a207b23810e137ccc003894e32f597b20a381976a914d79d883b0301f03e486a74fa01f336fd0d1faef788ac59609e26c208c8b81976a9141d321f045a5c01d5f55b68fdb12ac95330cee8ae88ac600dbecc141508d2fddf015a2102d6f03e10197ab2369668a655814412f6f5e4303c9d0fbc3bea1407c221f900c6210376ef46775288543df061dd2a2f803e9d85989e6d2dc2429580c05c459c868e842103ca600d30d649b5a750fa3a3dfe3a09f80787b6e9744eba58b87e53103e5ba09821031cefc7bb608359a0ef7422e051c7e19cea0a78e97e15c43dd13ddaf8742298b9210267c31b11df0cdd357200d1cb38c4ab39817de7da3d51b83e844f7e4cf893acdf2103c2f607a37cfea2fe5bf5710d86de41650a8b0eb8f75384b1b2c9609c0f8a06582103b82e19cdfe141147ba7f66e66f720ded742e918dba294c4d198be46db83dcbef2102df6877eb91b595f31e5af9f344a565a0a85cf35ac9c2c752893d3375471ebd9121027d8fb6d39be0d5129030a4af6170d7fd257bc6dd205e14fbfd63754aaed8855f210290218d5c8429cf03fc75f51aaa0f6fb37a22be7ff881655c8fe49a666349b6402102f86b90764a47df66c7942543c0c19ac415c8695189dd01914a427ecf870ee8bb2102431bd4bc4ae39da048b5b568b1aebb5d15809a5b892f78139a8add08cfb199932102591002d24cba0cd4cad2fd0adaa0e02713df5e8a7a6ca96b9795a6210ead17e6210276897ef141aa27ac1f97ba3d56a773f5a7db8c8fc5e29fbbaa8aa356898275015eae48105e8beb94f6ae0a87af253f805370636b637b7d2ef1d6957302107b100a42bb8c917faccf36bd87c70f0ede834630440220127371362c7136deb9e37aeec538d250d67917a22968388ff7790eebd0324632022002aaa8abc49f6b6dbcfda2d57ffebb55cfc05297379294711100a70b9279ea7a21024739035107202fdcb2792f64e50ef6dd9abfd9a25f7028a00f1300e0c54070b81976a914424ec434327e9f08eb8858f2ec81ec2caa10b32e88ac9f81580ce09e2f7de808acc88137777047f886a379cd0ae303c0d4cfbcf816e8c669e56f899962aa6b46304402204b5e43ac0637c47c8e99dec1fdd491e05b26112cca3c47d80bb04262af24527f0220336aa40ea836770e4f132e8f2219d49db0c2d671814f6c07dd1fc82494ab4b0a232102bd252e706d7105578d124c96b252c182fc9682ca94af11fb507878803f8bf7e8ace688407aa930a1f025eccf5aae0e7f640770de99d4f9aab8221b1f8d06fdb11a5d15a891ca0e8c2b48473045022100b396358637f5408a6ddf71a0a8ec64a133ee090db161898b35d14a1d20691513022062823453959072b3970fa2d8563932174bf5dea14d31aa300d2c5369780537a7c523cad80b9e72fb038694a6f4923ac38314a36b334ff0b715e2ae182a35f719640a97ab525700d7fd5a0400473045022100aea47d8bfc8f53b6d936599472382ae1bcfeafd34bac7399770e581bb7a326ad022002ef9626ec3a42d101624e77f2af34720d47cbdf73f38ec2006d93d7396f9a7b473045022100edafc6336a7b0e16124c3a7039211229e2eacb3f7ac57eeea2d5d750859b29c302206f8f8643f10cee515b43a80f6747910051d3a507e244a39513c7907306caa961463044022035ac15c56678d3efc89a36ee35d29813ee777f74c85be23d83e9739727b6334f02202acd3f036b9dd29cd530adc674250afbcdccb0bfbce5fbe9d1ae77472a6fad4e473045022100eb6d5b1f8fbbe70f99ed977eec50ded19301d501d9a3f4b4a06e6649455beb580220024d02fe5ceaa330c8bca15aaa3126e1c6590e4e714b421aa379dc2f1cbbfe2b46304402206a06d6179946eb1cddb36c456228deee4ee28ef8e9e7df5e05ef47350c73d8d202200de03f0f60ed4681f8439432917face05bc4887761a5737c5e2a8bbf97e265d6473045022100ca68aacca09a252ff295548a5ef0a8839658db1ab690f1b259e390f94e32855e02202b9fc600b03dbfb0b76dd625921f6e5bc39656467fa1d9687c0d3deb55aaa363473045022100ac7f77fbd54003c0be2abfe6454aa11d9ae6db998ee5564ca9bcae8775af00aa02206295fe0ed3f83839d2b54850d9bfbf9b938a955c33a23b71fdfda5d56f1b84d9473045022100e30e09b8889f1e281507d12ea7723a8a5a25ce5fe6ec73929e4a94506fa076bc022022ecb49151eba458dedf02c7f1bf0251240ac83c6ccf3df618a9509e6fd082f84730450221009ecdbc46eb636fb73ab81b14d439f22444a5193bdbbf38a807fca677c87de0ec02200d3e3f726a45909359cf4b585ebb86363981e68c8cce9b6deb8d669787a256d646304402206db58aaddbfba5552702f7c44308b1aea9dd494fda54848b35ff84c2c71c8a7002200379ab9584a6de6101a17a4eebdc57961e91a3dbc4ae90b9a73819b073f68f4a463044022030afd384a182a7a8641c37fd673bfe93a74819249e54dbbf6c02e93de0ab6c2f022075512e27ccac64fe2e74fc35c7e351c8db3831fab9866af1904906c4bc03ecf947304502210084cf143e0023124dc27762baa8028293a4f4f60c980e62e9a199abf572fb903a02200e3e60f4f7eef39bea41db931203581ee3ddedfc299721c8dbf2907a241fef46473045022100ca1fb3621ea238721fc6965f7efc3165c30e28fb990c3a5e76d0917eab7f22c202202135d4425f9216007818ec3e9dc05624d31c1bb2d56624f09702e682ae63b79b4630440220273a91a355ac5900f4348f18c60def28232461122831ed1161497403c972446f022044d59600632e5bbc0a5cc843f1a5d7913a75f6629085cc8b5b39f1ba81f5324c473045022100e341c40ea77d26a2da37fad74ae0927e78be3db2bec832317a0b0e4ff516e66d02200f2a39d6a9ae1f343a67c1d1c6f58466731c227dee067514049cef7418476a2125002102d64327814f691a42d3755e238919ed191f2788f7a6ce6c2dcb23139930b8c97951aefae0d75723e1503282b725d3ea2fb64bd7a8564f9b9097dca0040072c3f21221b2f208bcdece988400e113070726646c0f5bd618a638ea5ffdeed8af3e3fd9f1ed0e66f5fe7daad18600961545733cb6c248473045022100d047a5b6bb5f02ee9147fea5ad516e360aa875fd3b58f252051fd442d20b7056022050531b945683cb12e2cf99e2b74a11506905d290b377cf03cc16dc381941aa11ed4e43d41d5dc7a0042f8c5b0c0e217550498552b4d14024cb406c92f41dcedb4f07e6ab71f6ab5f6c473045022100e0500858f38ad3ec59c6271997d54a0f7679661d129c188495d08fc695e587c20220708bfc9ccb872105f6c5aa7d8586dfe9ec82145a61edf38d5ab47760869d644023210291373b7b1a1ae01203ba5ac465ab47ad2975dd46feb0c6827d38bec670d79d14ace63a901a81919b3da3bbdf48602f94df63d0ccfcc8203bb1412e88212b533350f813f9822de75420fd3b02004630440220792d4365a4b433737a83cf75f47073e5266ab28e21758fa5994f7adbe92373bd022061a9def9ce44be09c934469a771ddb0eec559f2e257da0e733f5c05cdc1af78c46304402203a5b0294c6820e652a157a9f241658c632563594e4aaf3937f5f1fd2b7e94df60220625d6dee041dcc48c15927db2a4981c7854dbad62feda43ac084948cb4c37a72473045022100f8c67a99c36a2a73a0edc5defc063a51e426d8fa08b49a709fd96e39700fc2ed02204b0aa14dd4c6000ce9554812afa6c02a5765c41c214f908201328885d25fc3f14630440220784b4d20f4c85bf4b1a68a2683d8cfb7d798909399783005e42c856bd7aebe12022071b66e455d812e13171b675dcd3bbff559a7db42b09fea12a8531f75217b474f46304402200899bb9940e1180c55fba8400fb011ac6e47f52faa54b1d818eda651f6ccb27d02202dedac2049ff98bc142f183b4129a0617f351d8e7224a8ab7a70d6e8fcd982bc473045022100a0e3d8d0848e75d89871199b6b1ecdb5ebbded25cd84b31426a3bcb911852f2b022014eb50f2c2615d825c35c29a05dcef06550b755a47a27f5bddf199312bf432f246304402200ddc04324f0a6bbd1a066477aa6d07af95f2f815cd45fa58c59858af6b525f16022034797d1d71c08dbeba4792cc0cbc9ac55d17fe114cfff1ccd3c4e2cb41610100463044022055331ce180b06b6f79c73c7a41fff0365ea2504aaaa9b9f142be7854f91d2eb002206db67280ff22164606c70a79905eb917247eaf9d5eb5cfec5343b9dd4f6aba8a2b345573014aad6f4ccf7805ae1aed6e5dfd2757458b4d3b4da52f344afbbe0ed076784cf55e17a2484730450221009bfef877e07c3ce100208dd7d522071b364df4270a5734742804e9ac2c2426740220298f95eac3d3e78e71c2cc4e6d8647acf6c53df205eab3e44aa807a7e4daf6a3cf98bc760000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff036c30f9dc1d730fa017a91476326fdefe3eb33c3fd2888e7fa809bfdc53423a8761de5c33e996eaaf232103533dc3a1bc0452280cf1f581ef4653716c02d2c709e51d2107f7a96ad68edae0ac2f54e7b569135c7dfd3501002102486f9c0dd1895e81be684a01390943457416dab4f8ee7f13cb6e342c8b0d5f692102ddb8a7ead021bf99170557d9e91787b7d6da90d51a84de5215cf48b0ff16944221037876edc52e51fa062caa4e7954d4407bb5abb5525e720a401a0524a1f4e128672102494e028fe6cde1e42309a83d8fc1e9f7aa23c683647dba1c8902b04f8ab250c42102632bdad1832f3094a27011598434b6dfd3ad5c0e324343548955b9e47699ef202102c179afe6d0a8c7ad74977ba93a31d02b3339a4fa9eaf6f594418b748fda075dd21036d1d97c281eb12ff31d4a3d6967ab5ca70f7debea1541fd827e0b7afe8a93c2c21033f0fadba950ce670f916fd98329295be45de5e3e45f21df9568e9648462d84df21033de867cc52ae1833d035de009b0d2ae72415e51aa33572f751dacdfbc264800b59ae01c3d5a4") + "3262b4625df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456c7a266cac8e35450e0423b93743b6c84d7ceed95b888df512161c58c267042f824e234e53d85c450f52ee0ad04277aa2b104712aaa3359831e66c59bcef05d142a5fb39eca656fa8e5c56d7a84ef4523f8b36a8525e584473045022100fa3f875dc56ca67d750a98480dd62091ba5db306aa83938e221ce6893bc78f6f022041bcc644cab1a3fef3e20f30c45ebf02fbc559fa24183848d04f69613c13267e210282f8769261e6d41b92a2c0f5da838d945cf83443a500ffb6634890cc35b5af3c1976a91474afccd8daaf8002a3fe47fa38e32b18a3f3f96888ac864dd1e73dddd261dbbf721696f8a0806c8773a25791c09e2edcde3edb42d305c33ab17996bcafdafdae0100473045022100eec444dbf21c6b4666aff7988712cb453ab4b9e88339580a201e51c1f5948d5e02207609abbf8dbc5bd9e535e943ae4af288a04a289f3379f15101d3d9ae0d52585446304402203d53759c6495fdea3c35e3bb1aa54607ea33d8157412012cfa169c53fa725cc4022072762d6e12f29841a98f6621f0d41d8289fc59e01f5d2ff6b3e4c713555003b9463044022017bf9500d4365a291977ed2df6ed2ab05e5cf7362e9756b92c5fe813f6cee8f702201f130c151fdcae134954e453698b67ad84a610142584fece6d001fff6ac4eedd46304402202d273ec35117afcab9968a7ac663bc1d4548d6b5eb210307f2ac6f301d421f5802202a605ffb7d74199590f50d6fc16c57c2a97f3c27a5b68e59c014751d53a15f3e473045022100f23eb041b56f7d698814e081e4e0b8c0b80b9a073c912670c1f6528ceee1f06602202548608aaffe99a7431b0e294391cd494f490b3e0ee548eeea8db26d6ba344cd473045022100b1ef53e4924122c9dbab896207c735adcef072872551dff3b5c82f23a9f886b70220125f81b2b4cb0d5b7b5d39d4e54bb721d7984e35daa786937c5a978bf579778fc595c1506eb8b138422b7b030f333597d376cae48a2a162f8fcdb34d1367c17edac692475202893c84473045022100cf5692b94fdf9cf045627247d318ba8eb83bdaee2d86954026abf53987b64b3402206f7966290b24419dd47e630d7db7232e6ec7a4b298c9352ab4cfa20910adc3612102f0af5aa92439faf2abd642ab8303a49c227fc0e8f95deef0c04864784fce25961976a9142c24720ab39f3b158b5fd738b8f042f7fbe9648788ac0e54bb33e4688947c6b0ea2f32525f0848208590cbcd4cfa4b8e4f1ddad807ac0b12978952da44c8fd84020046304402200229543e423ee9a2f5158a3aa8f7780d16ecd45dd39d38104785be45744971a402205493995c294fbe777e757a49cd6b95a4822a2660b63fed65a4bf8ff08338e0ad463044022076cd3b02b9587a8adb4148ea950a537f20b91e0b7fe6c8bea5d2a10eda09e2370220502d0ab082222eb0115d1b55a423cc1ff873118c1a249c97e165239fd4ff2cd7473045022100f250569e6d29168dfcfb757bd71dcd9f1a72907f8d98903bb386252fd566d09202206702e8b001d424ffd0b6d924834b5f7af593f6c44a8dbd2e78e74fce07bf553746304402203cb61bc7732ae7d0f20db32c9887c1d3df8f9edb28ebbaeb5a8e879e1a17668e022000ce8c2b08fb319ce510fa86f5fcad674dfed27628c0c588ea3107760e5cfcbc473045022100ad09f0be69bf082be9507eb3e88a4bd00f2a57505cd379a31d38bafff0048133022070a224625a3035d974fa92d48aa492d1d6d71d9c5e6827b89fdcccfbccac9dd24730450221008609f7288c3e73ece5a63db8f10e52dddb549f6a6ea36bfb685466f17af91e0f022047d813a34138d871f3a2448c2e6a707b072b55d37f8628664dc5e8d6c9f87e6b4630440220098e44a7f30f423406ff10dc548a8b984cf4b51855cd3570c13b727508251383022032f253f9d34f3bd0a26ef457de5b4e7f9e0aa08efbe9644fe68ca682748b52514730450221008ab3a20a3b3314a904d02e336c8da91a0b8ae6996ac21a4dcb6a3d4cb3b757480220391bf3ce204a931ef33f64f9d50dbbdd272786e99832baa2a2454387e40e9a3146304402204f37424df7bb35aa2c60647453e9a12648c882163dc4af82f1ad6520b2daba3802207544a3efd891aff255f09e52e7805776758d63059bbdfa89def9aa54691d7b7919a460630a6a4477d3827237e6fd79015b2102a8b919462279783f36643d97d0f47289ddf1668a38351006193ef84b9c2d2d972103b5baca2b10f51b082e503bc0551d0e8aeddf7bedcdb0e41355224a4ce8d17d13210233685151ed8abafe6cb2886cd0570e1760173aa60f5f8428d68946f016e9d48b2103df9b579dde97467b32db940840130928350404bf62534e5420389bca85314fa321032c853e57d8f5071cc39bb06613646c393ee02aa8c19e04ffce61bcca6eb915e0210307305d027285bfb6e9e99ea934f2e382f5f21d9f4fe0881dee9024fc1ab6a8c82103ce8763ab2f397e1de5786bd630afa12a01c89724657fddc266dacc719bc82f962102f8b0a65653af2bf736982081021b6873b490305a9debd46c56aa568d7f905de5210301876498e73cb0fe1961610224fd900c2d9e91aec60da5966d0ecf2168d6981b2103965d912ccb7bac36628b803e3418994e43ef6eb1f68a30e7310df77fb3f519b421033513389f53d369567a7f4ae233c2b8f4d844f90313cefd6c6aa84db4321d11c45bae1b8c364b6e2f8be9fd57015821025a6d95bf4413228e74001f5384f40f3b3fbc1118e1a7864e54468f9cbf2007632102eb9f559cea1d00faad07d9a1d6d00e3fe1ab8d831f3128aa7e5733435eb46e522102c91658ba2977200559acf512eacb12287c55e189d12d402e26d0ef46d50100712103cfe92e548f583f08c90ae789d6d7f715042457a11d520ec55c4c2b25bf298f612103b949061060d317746576c1a15bb4666b5db1ee577be9b4fffd0ace3dfbff0aad2103b1bfe0d7b36744666eefbac4219ff8971e74d99c23b438566f04de6cbc8e1d9721020de7fc20e62610d39b74e695800590a0dd31f8867341dbb89b71e80ae90e660e2103f8886c1481c19819a6893e0ec7e744f0b11c07af791f980c7ef9118965450653210287dc2f87e960a2f74c5341d13ebd03bf083201d5143c9c6b47fa17c043a6eb322103317ae2c088ab99c377d8452416ef437def9faef950de5242f974461752919e785aaea9c486b9e1fff2ecfddf015e2102b1c3b280aabb6a0dc6d2316b468de14be4a1172b6886f248fbaf614990fb85252103e57dfbb3a3098efd15269c869386925ac173cd924a97a33d11384eb6553279b121039297348016892ad6f389b98d8d3e947c677e627a98493a22268ca29a6588c39d2102ad13539a531671f108a03185156b49bdc93d89d40c5bcb9d3c6d9d81ab55d5712102d5eb07a7cac45ad3562855eca2f748d6dca4381ae0b167c0d7b273bdeeadcc502102a94c7e9ad50a8c8c36ee801e4f724bbcdcd826244a1a3413d1fb7461c27daff621039688270efc35a955c0bb6a8cda0cc00646e79f98631c93b6003bafa79036b4de2103eb9de4bd49ede0107d8f53616fe1286233bcf22d8f8097c6812b24479cc4fb062102d45bdbebc933d9945a95e170ad00c2e563eea9514ac17fdde5d806e7ec15a91a210218aa00f864e6d5b198fcb2056f10ce8d5f3d851a141758191682e739c8a90e9c21020ace0019a1b9f8ef090c2c6ddb35796f907b24e5c3705af45dd238475597e69d210292a97a52e1913073e089ed29c3e5254d665a07884a39ed557badbcb948c4e7a9210213459a210153d67b4af2ed02fe228e9951572a3b383325f2f047429e89514b49210384c4ca5b44b52e26ac21ea4c7b98e79ae57f75bd528fe756aa06e5dbc8d105485eae709e07efc011445f1976a914ad7ca68463c1b3e3280698d10c4dc6e899fa992988ac92c5476f3a9507fc232103c0c90e4386820c7823f696944cb09e2417bed2797bfa80c9e8eb0e2b1a859266ac8416a4a2c219d4f91976a9140f755179ba239f8367e282cf0fa264be3a137f8388acfcbac8e89aa85170008de2412982f2458a0078d45932adb7fa51fd3501592102b7ed45c6ae164de9d8366e725d2eddcc2103c298dcc9f56b983a7189867d368a21033488822f69644d2f0e4f84753872ea7312c0b0ef4bab5019c9821da1837fbd3e21020f391cabe366c3e84a3b0f87ad9ec00d440ccb56ce88b74a1fc547ce20a1f68321022f98a0076e100eeae175b879f39bf4fb04a90b80f7dc5173e619264324c1d9e52102702c0f2ac79c62703993e1a555201a2e6197feb274e6c029f283525dad99165b210310e26b0191b3656a02fe28f84ced3ce9754bc0023744c49d17351f0a8a65b5f92103fef91df37cd5712ee3321ff8d426eb8329ec9cf894ec84e3413a7caabd96c65121034b73420408275b709690abdacbb4e52d5748272d9a09a35967de637f33427ade21034522c6680e4caf1450fc78de6220c42918cac60c478e514aa43a0c009ab52f3e59ae950dda81c8d61834232103715774fa3d6b7097d7278398a48801468c209b2310b5e33b7418358bfaf8fe36ac420ce9cd0b1672df0a6f4b273a91b36b53de0c31fff4cd2418a86ebfb1398852fe72a15e6c3cba3336431bc1df48473045022100842cf1218c0670afc5ce734b5c09e71dd7c5a6e926797fc7feca60f764a1ed330220795dcb61f0ebd50bce4080f54396a3b95e6bb954301f370106728085092d6e5460a5016987676d67d10fdde46e17a8b322d87de498cf2036840f822b2cfb8260d10dd74adcdca2bb001f398a7fc3f5e1ccc8797ec354587e81a8d799bc693b2cce90ae0460488c9d989c6b4fc3b6b109aa4746304402202ae7fe809db978c16436aabbcba866cd1cb57bed1e5e4bc673846f9fc4c8d69402202680cc0bcbc2db4eeb68e1f6ad97dc6ad4e29971e7f35a19d904adea923b996c667e25480000000000000000000000000000000000000000000000000000000000000000fffffffffd76040046304402201ad637b92394c2214c0b3e58e640bd30c5af9da5326374da54378846858edba70220014bb70fca2b610a691a97e9f317a42589e42e87ab50fc606eaa5173d8fdefc9473045022100f11ecd9d25eafac37a349e2f360f2e60c37531c5a81e477d3dc2b28d7ba81fa302202e2af213c51175d574595db73291e0eedf0c7cb52f12422d99e23428e4430ca6473045022100ff24451a87989940e582863fe837598fd4ab2832cdc797a98b6c7a42410bcb0f0220050b6b46bd0f1e5509365d697aa2f822384e9766eaa5099554a2d0e723416877463044022047c1b511c270a6464585500a7ed849405ec415e09e44c8964243c46aaa41f6f50220051a2f426d2aac9cd23a5891de2c59e3a0beb5d24c8b07ec887b80980429ae8e473045022100cff833b776c1bb01ef0a3f652b9463ed58556bd2f8a9fe8ab7fe885d35864f1802205204bed5da1cb014bc654dd5364dbb07a7773d8a91767f998b636d55d4a31f284630440220497eebd4f101899499f799709759826c58dfa9fe8be311d2d9ae828f0ab7ec2d02201c8e2233096133ba48946fe7339aa6f2d1808d8956fc833b5dc1ea3ee0848274463044022028254f4659c715a5c1e49266f6d98a04e4f65adcfe2ff75af3c6b80a9669f76b0220596f7f94c90c115e9f6b9e25c8415cccd5cb04cab02470671549b5593c6126794630440220343eebbdb960ff1c06e1d254dd0f6bf4904d5713ea54cdc818a86d33ae9faa530220138e2bc37569e590d90cc24793e3b8218f2220c15be33be5cafb8727ccaa88424630440220762aac3f639e796fa2b42341850b9255f5499cfb0ba84e61f26f137262399b5002200c994617ef82a7f33700eccd1870bd391729bb05298e8a1ab58c21259f93280b473045022100fdd74fb4ad8093c202c97fafc37e6a9859b010e337ecff804fdcd81fdc3434bd02203039317dd55ec657505a2e6ed216fa00d53403cbaa20d27214f03821b6b17ae2463044022026d4ec27f83981073cbd1af448afb31769de40a60b64e93bff395838f52fc81502201b5d0ea59f6122df641f21abf3766bc37c487af49a16f8fc2f2a1f540768e26046304402200cbe2871b0aa440073965a413d084734ef8072fe36e26757605cf834ac743789022078b7a019e0fc349c0f4c4f491a5aecf637381b24045b4740142e0f435e89daaa46304402210098d2844d368d274eeb1011ff3d0cd1a3ee708d41ec7e71876a101251f68cc1b6021f3bc0bbf056d601ad4021b82f184bbea010a6f567d6bd793300f02498ecdf8e4730450221009cab565e927f774bbfe8a3555b4a6d867d69812c1788f848f27cff97acfa640f02204902037e8f9d043d2f244da86c418706057a3ba119db5c3fbc8f8d6bf9b1705c46304402200f62a03d3cde68fce4962b4335075d6b32f35218a92237ced6c9fa0b66b2fe1e0220196ed3ff219f62dbb22dd10b3ad91c5196f634446b81267370b908a912e6c17f4630440220639e6c511c7d38a9a6366de655c00603ca5a130fc14fdff14d2d1a7432abb885022044a26760f2a07f4bf1a309e721191292f542f9d9546d911a157fef0027bccd35ffffffff9c2403ae59c02e9110817ed29c5f4cf91d57ec1d3414d122f460c21f2adb9297bf55f3ea0025057e6088f78c1046639b63b4ed955562e77f7f629cbaf4b1d4be2e2ced0b018d1e975a8bc5c9af0041c11829795d9d02bdaf081a379b384b49a9c1a893dac768a53f603f4743833baefe7cb88edd787dfd79040046304402206fc6242d402599354978ecb37941fdb4b14a8a9b2c3c9f782730e71e1cea53260220635dbadc58f8b023d5b80905bf76e9cacb9a3e3a895921c7dc22c6e2aa3a69dc4630440220325b128c5820546683fa4171b8f4415b7637106ab131f8b703e8fe59ef32245302203719a06c3ec4527e761f07ff689f776225ffeb84bd1992723275a8e08d6b459b473045022100d21b7d7df64809782fcad9e9b76f77a8f548aaf82dc6d3b9fc54991e3df85322022062f38e37ac33ba7ecc0253744a4a0ff2af9d52062b9fa721a7e13c7a7cc5f69b473045022100ecc5fe7c94253fce3acf55203333576c7bcbb2035429743fcef95ef47f24291c02207b61b895bf2cdba31f277d0dfc5abc6554a6b3dee2e7de79ae0eff1668f0c43546304402206a4c04a06b2ba0fa4d72da30d0d73f87331ce4329499819498b981604cd43fe10220561fd67cd3dbcff2b775f552ef42de8a33065f930870fe55f336d6f428c189d946304402205f2af81c4fa965b8240f2d002f181780c5c8c38f77a943676fc2233dae0bdb2102204ab3da81e6a530995ab7599b754a92458c9fff3cc839f7665bfb5831e035a5a7473045022100c526c14acf0e99d0f1c23c4b88611690005e368e462b2b89fe36e9abd735bbcf022009199362249693a9d2d8bc1a60620eb3bded8204af001ca32c1e583d23e131ca473045022100afa7986936b8c75c55cd82936af06e4d6a02ec6293af889c75e1a6ca3c404c4002205da582888215825f04f03a88050f04290460edd9e4443882cf4af152209aaa2a473045022100c395bf025a3bd5d185485e80153d4a71c90baea44db5bb8fc6a5f6f32d8f08b102202d7cda0394082da379aaab471185c83fe8c4dfd1ef846632a0ab9c3d27723f8c463044022003ae2a17e20d90bfe258ec025622d3197b08647f4633e3cfd54b66379dedf76d0220553450ca976ebc057c6ecb788bc5eb8e010098ada6c4ffe583dbee37ca99975a46304402205795d2c37ea3b7b5b9b92e5c0e418995a6fe75717072842ba25f3656bad4c7f802204d9f6a023a182345345c8ae26ff1e1e11263a815cc9ea58e73601c61c230dfc7473045022100ad73e4ccd1a8ff563bfd7634618e4d68888a586aca6a128159371f78b69673d20220426737e88fe253ea9a85d2fbb12fe3ad9d082490e4a36ea542349c2238761af147304502210095411a30a1fbd6ef0b10ab4687f76fbbfc0f6001697504843a5124edf057f92f02203e1d45eaa45b56ee23bf7d83ab81685975b4490c0d49e738c96baeff148a2e6246304402205abc0ac643fa364f7f255db235804157d124205af82e2fa473d8bb4a7905443a02200d89fc0dda126eab8cd527efa6db5b6477bf82eb01c51e79e43a10d90c907f77473045022100f63be62ca0b94516daa56a183a08c880b37519a94ff21f8b626ec24aa921009302201cd4f1f51a500a07302ebe2feceac9173f923877d1141beae3bc4bf73d375ca94630440220417157dd09ea28643e22fb6b5163a84bc2e6bd43d155c528726600d241694fca0220299a89d6c3ec259e44b973400f6db255f18a52e42a6c62d9359fba0d2184a9cb54fb9e99311f221faba429b29f400f2fdb3c1833b3514baf686c3f1427544ad01c7f276c2414f20a8346304402200128b2bd914502e18cc63e6765573b8105302e76b07e7374ce48c4f0356974e0022053f7324e6eb3bb17f7a6c9441956f87ce0e391bcc7c3fa3fbb39723b80d941ea21024e50dee9358f0df3f21b80f29e0d1bde93f606da2715adfc1af46d8aedde443b1976a914e98e951bdc4590b669d22229ec4ce022d4ab3d8088acdfb81de16a2f64140877ae666028d1d3e6af44c1f0d069b2a47621f9a92ffa285c1d153da1bdfe0afd750400473045022100c74d067d87097f5b9cca436f522ba06b01b6f0e4193a9769df5f7358d78b3156022045de7c6f8f698567c6d6d91e3aca468bb14e2db320d7a7f182efcc4bd4876154463044022048b42559b5072f8bb35fa8000c863d685d5a8c7a5e0396d482930a816540530902201ed5d6a0b01aa6a1cdd27ec247f97c850ec9b0547eadf052d4de16055bec151d46304402203cd4b099a12c13b38e8fc80843c13571180170cfd1eac8812e7ccbd5d2c76a35022015f88503c2dd1f7e433a064db7b4fba81d0bf43ee592c669b43ba3b82eb7d0234630440220215c758518fcb78449522404ad529b688aab3d8e7c7ade095bf9c5cbf96d290c02202d0f02fcd89687bea70e2e7ca49b7d780a0785560a3198ed7df6c933f444520b4630440220360e163ab8412823a5253b1c08536f2838dac8b2a80fe3cc2e2b3e1f5df2aba402203639d70befaa16a4032f7b23e683fab9a22dff834f69a75e701880d9bb59c98b463044022015bab54156dc146bf5a1e0663034730319b446196486f92fc81477ecd303f72a022010d637cc7678a534dbc95fdeaf0641afdb68e82c5113f88e462a3604a8434050473045022100ae91d38077c2859d9c3cee7bb15689b48358b39c4cf0eff3624a15a93161a8390220441c02b87634818c5378e8d515c1a06a7bd6f97a616d71e82995f7267ce4b0a546304402206a6f43abdd26c615693220f3576010bfc85c667f83c7921846fe369883d99e910220570137eedc2344cd65e76551bb872feb6e4adeb218594e8d54f02cc93307613d463044022044e7176554d1f760e40852e5d1cbeac7bfdb9a805e2d8c013b385b02e4a4813b02205bc1b86e0a8604c63a096e5f87b7c04c7af0586a56d251eff676a531a4033fb84630440220063bf6ff87a5508a57e2d2c20dad19e270b1ab7264aa517738e21d3c5dc1964002201d24f476cbef0adbd89c74d1ddf7e72980a171e2b32c32ea66dedb01e49b4ff7463044022029741e5fefb4fab7bb7fbe3084f4d6887aa72d7a40ccb613652678ff880abaaa022026eb6a412d6d946da6724c78b951959616e50343ab92f2d1c722bf54b7278f65473045022100ed5b418a85e154525ad9d0dc8d27b98c00ce215ea13960f696322fa863e9833002205302c11b9116006ce59353659ab24c5cf7e666128c97d714455b17f1cb89bf114630440220316925877b29c00c876e35cc99d76eea2e0b3dfc8bd06abdccc3bdcbd6fd0e24022043ed0bd6681e1a4ba7d187c45b1a59383e137242baaafaff8ab601c38747d1d647304502210087b711b70e09f6ef6004461d9c688909d179a4be3a9574d63e1991afa7e22c3e022021e7ca60dcb515e677bd88319289a001abe26b07415ba7dfa00e70f95be8c6cb46304402201c8eff9a5051a60649ce671d6d31c54c9759c806e157e459962551884e7ea4af02203931cbf9f333f3443701c647afe58d3c06cbb26b141db7477e79c96e4d4d34a346304402201068eaf8e6f39c0a4625ba9349222bff0df0758bcf6313b37468cedeb94de7fd02206fe06ac2de1071e46439f558a35ebf6bf8875f1a518f5ce02dc6fc3e5f611a27665f47e94672c8145cb3e2213531615df2c0aa0c686e19798d215d8597bf59bcc5c9e794a0d6048afd0d0300473045022100810e6dd7464311e36fd702e892cd12581456651281829990fa9b692ed6f175a2022043e793b1da6d5820a3ebea0a22d0f07eaed3c0900314595f34df3e850bbb628c463044022059951b253a3ef907fb29d730442f8575396f041134c9ebcc0904feca33c640ed02207402c95e35eb2c1e2d9e6d6bd4accdf6620be3695bdf3d8212cb2c8bd1f7bc7246304402204e85f8b5a378073eba40f7ff3bb3734cc2a046ea7f060bc76baf65b0e3537faf0220607b544ce22b012d88161ab8083721d6b432badeed1aa93003787d5c76b69d4b473045022100c0abae23c4ba81796792accbaa00197aa97f14d52550a2b82f3fffe30cbd134c02200798af13740a9e3c2ea4137e272cea437398c9175b4d793cb45302ba6743ca0e47304502210091ac09a00ba09ed52c8f18169a84c88ae1e029f7c20bc47c222ebd59dd016f8e02200123051d8191675b1e63c48d223ddc0d38e1fea08358b576423b721c4dc27862463044022043875a601c2e98bc00d121f9dd7618050ac94e766bf8d3a927260221abbbcc6a02204e06c2bf529a9a1b75b160bd55fd73f345d9d40ee3d4f15f984cbb01d267fa19463044022040df323c538e4c9e10cb826507cd3f83aabb0983be818313a66392e82e801a5302200a718775ac7957a9350442df421b3f6059bd6c0a32f7776bdfc6edb1da98993b463044022040f84d8d0305b8164f0a91b7b9d6f2642714bce5fda5faee5ca4ea52720f7de9022054ef4dcedfed2882de7bfdcc2613da52d6aedaec29b84aabe135d663d90b62d84ccf542102db9d09b60d6fcf50d3290e3078173af5b6cdb2454746770d6c86b3677270c6732102089b8ac6727336a8343f140b65d76c8710364b89fae5669dcd8c6aac91904e142102ac196a356bb731f225d7d0005f32b864fb3b35836a3e28460af1a622f1c383f72102efc7bef0150752d1da515c7341b645f59292cdaccc4b7a17e87edf654ac5a4d72103ff059a385cc46d299a24bc5c7737a0c9b083247919062c317bc09d77974faec72102655ff6ff38151e48e7d40ed57bed7b6573e00044c4e159bc25f5c2ac6eab31dd56ae171fbd8c07f06ded9974d5f5c7232102312239452b357f9baa50043c7256211476f9f232e18df78a6b4abadae902a5dbac88dc9ef6847a8f73fd9b01582102aa962262b31bfb5274e57ab580d86fcc0e7cf354d1d6b42cbc9f41a8b79d69ba2103713031e5678adba942aebb965a0888d287390ad48ed0397bc0f8cf60160cd4342102c22bb3c125d0d421b842c41a8c8771def88e2cf26bba157e98b7bf18e74520b82103f0122c7d62fd18a596723a2c0887f680486ca1c1953560fb9a2c6c24a1ee8cf72103a02b0b5714a30150e5ae2024d2756cace2f10f9b33d26b80885ebc30933d090921021ee25cb3f0d378b0afee856d81bbcbca63cfea35bc983b38f8e7648410aecfac210379c09f5bff3d2b7fd6217b4f0dd3772eac005ea4b95a2bbe6c321486628b72ea2102aa4aefb79b03e19dcc6a1841b22bb5c226bf9f4c28902d4bcf4a348135912a7c2102af4252f121827a5d6b5d0f8273521a25cce2e7974519e09076cb796d2d3963052102a73c8370d07ac353040bac2f5e7ee27801190192c8a3e0dac5d0a2b19a72138b210225b5ec15c1a7361ce5a1cd91ce0b302db4c5a50b38e892612054c145717c263f2102fcc0ef0d7b132d3676b8249e4419d98e51dfe63581e6cdbfb751e8fbe7d2e32b5cae6e1b9954fc0fdb2500dcf34b9a5d23f7e70069bee40d9059b48500657a120783c184161976a9147e73483c1f4136c86417440e8d72f4e1fc58d1ea88ac6bedb17b05ed790800558d11f3f42f4acb01c875118efaebb41a2f98d618ec1106e05da749ff89685db0b7d5f8b72341d20df36e04e248473045022100f6dd02d1279300343dcd8db112457f03c15c89c11daa4193428ac2a80cc51d1d022037c66ebf834afdd2cf93e15825a20b64707d7cca329bd8fe10f7a8a207b23810e137ccc003894e32f597b20a381976a914d79d883b0301f03e486a74fa01f336fd0d1faef788ac59609e26c208c8b81976a9141d321f045a5c01d5f55b68fdb12ac95330cee8ae88ac600dbecc141508d2fddf015a2102d6f03e10197ab2369668a655814412f6f5e4303c9d0fbc3bea1407c221f900c6210376ef46775288543df061dd2a2f803e9d85989e6d2dc2429580c05c459c868e842103ca600d30d649b5a750fa3a3dfe3a09f80787b6e9744eba58b87e53103e5ba09821031cefc7bb608359a0ef7422e051c7e19cea0a78e97e15c43dd13ddaf8742298b9210267c31b11df0cdd357200d1cb38c4ab39817de7da3d51b83e844f7e4cf893acdf2103c2f607a37cfea2fe5bf5710d86de41650a8b0eb8f75384b1b2c9609c0f8a06582103b82e19cdfe141147ba7f66e66f720ded742e918dba294c4d198be46db83dcbef2102df6877eb91b595f31e5af9f344a565a0a85cf35ac9c2c752893d3375471ebd9121027d8fb6d39be0d5129030a4af6170d7fd257bc6dd205e14fbfd63754aaed8855f210290218d5c8429cf03fc75f51aaa0f6fb37a22be7ff881655c8fe49a666349b6402102f86b90764a47df66c7942543c0c19ac415c8695189dd01914a427ecf870ee8bb2102431bd4bc4ae39da048b5b568b1aebb5d15809a5b892f78139a8add08cfb199932102591002d24cba0cd4cad2fd0adaa0e02713df5e8a7a6ca96b9795a6210ead17e6210276897ef141aa27ac1f97ba3d56a773f5a7db8c8fc5e29fbbaa8aa356898275015eae48105e8beb94f6ae0a87af253f805370636b637b7d2ef1d6957302107b100a42bb8c917faccf36bd87c70f0ede834630440220127371362c7136deb9e37aeec538d250d67917a22968388ff7790eebd0324632022002aaa8abc49f6b6dbcfda2d57ffebb55cfc05297379294711100a70b9279ea7a21024739035107202fdcb2792f64e50ef6dd9abfd9a25f7028a00f1300e0c54070b81976a914424ec434327e9f08eb8858f2ec81ec2caa10b32e88ac9f81580ce09e2f7de808acc88137777047f886a379cd0ae303c0d4cfbcf816e8c669e56f899962aa6b46304402204b5e43ac0637c47c8e99dec1fdd491e05b26112cca3c47d80bb04262af24527f0220336aa40ea836770e4f132e8f2219d49db0c2d671814f6c07dd1fc82494ab4b0a232102bd252e706d7105578d124c96b252c182fc9682ca94af11fb507878803f8bf7e8ace688407aa930a1f025eccf5aae0e7f640770de99d4f9aab8221b1f8d06fdb11a5d15a891ca0e8c2b48473045022100b396358637f5408a6ddf71a0a8ec64a133ee090db161898b35d14a1d20691513022062823453959072b3970fa2d8563932174bf5dea14d31aa300d2c5369780537a7c523cad80b9e72fb038694a6f4923ac38314a36b334ff0b715e2ae182a35f719640a97ab525700d7fd5a0400473045022100aea47d8bfc8f53b6d936599472382ae1bcfeafd34bac7399770e581bb7a326ad022002ef9626ec3a42d101624e77f2af34720d47cbdf73f38ec2006d93d7396f9a7b473045022100edafc6336a7b0e16124c3a7039211229e2eacb3f7ac57eeea2d5d750859b29c302206f8f8643f10cee515b43a80f6747910051d3a507e244a39513c7907306caa961463044022035ac15c56678d3efc89a36ee35d29813ee777f74c85be23d83e9739727b6334f02202acd3f036b9dd29cd530adc674250afbcdccb0bfbce5fbe9d1ae77472a6fad4e473045022100eb6d5b1f8fbbe70f99ed977eec50ded19301d501d9a3f4b4a06e6649455beb580220024d02fe5ceaa330c8bca15aaa3126e1c6590e4e714b421aa379dc2f1cbbfe2b46304402206a06d6179946eb1cddb36c456228deee4ee28ef8e9e7df5e05ef47350c73d8d202200de03f0f60ed4681f8439432917face05bc4887761a5737c5e2a8bbf97e265d6473045022100ca68aacca09a252ff295548a5ef0a8839658db1ab690f1b259e390f94e32855e02202b9fc600b03dbfb0b76dd625921f6e5bc39656467fa1d9687c0d3deb55aaa363473045022100ac7f77fbd54003c0be2abfe6454aa11d9ae6db998ee5564ca9bcae8775af00aa02206295fe0ed3f83839d2b54850d9bfbf9b938a955c33a23b71fdfda5d56f1b84d9473045022100e30e09b8889f1e281507d12ea7723a8a5a25ce5fe6ec73929e4a94506fa076bc022022ecb49151eba458dedf02c7f1bf0251240ac83c6ccf3df618a9509e6fd082f84730450221009ecdbc46eb636fb73ab81b14d439f22444a5193bdbbf38a807fca677c87de0ec02200d3e3f726a45909359cf4b585ebb86363981e68c8cce9b6deb8d669787a256d646304402206db58aaddbfba5552702f7c44308b1aea9dd494fda54848b35ff84c2c71c8a7002200379ab9584a6de6101a17a4eebdc57961e91a3dbc4ae90b9a73819b073f68f4a463044022030afd384a182a7a8641c37fd673bfe93a74819249e54dbbf6c02e93de0ab6c2f022075512e27ccac64fe2e74fc35c7e351c8db3831fab9866af1904906c4bc03ecf947304502210084cf143e0023124dc27762baa8028293a4f4f60c980e62e9a199abf572fb903a02200e3e60f4f7eef39bea41db931203581ee3ddedfc299721c8dbf2907a241fef46473045022100ca1fb3621ea238721fc6965f7efc3165c30e28fb990c3a5e76d0917eab7f22c202202135d4425f9216007818ec3e9dc05624d31c1bb2d56624f09702e682ae63b79b4630440220273a91a355ac5900f4348f18c60def28232461122831ed1161497403c972446f022044d59600632e5bbc0a5cc843f1a5d7913a75f6629085cc8b5b39f1ba81f5324c473045022100e341c40ea77d26a2da37fad74ae0927e78be3db2bec832317a0b0e4ff516e66d02200f2a39d6a9ae1f343a67c1d1c6f58466731c227dee067514049cef7418476a2125002102d64327814f691a42d3755e238919ed191f2788f7a6ce6c2dcb23139930b8c97951aefae0d75723e1503282b725d3ea2fb64bd7a8564f9b9097dca0040072c3f21221b2f208bcdece988400e113070726646c0f5bd618a638ea5ffdeed8af3e3fd9f1ed0e66f5fe7daad18600961545733cb6c248473045022100d047a5b6bb5f02ee9147fea5ad516e360aa875fd3b58f252051fd442d20b7056022050531b945683cb12e2cf99e2b74a11506905d290b377cf03cc16dc381941aa11ed4e43d41d5dc7a0042f8c5b0c0e217550498552b4d14024cb406c92f41dcedb4f07e6ab71f6ab5f6c473045022100e0500858f38ad3ec59c6271997d54a0f7679661d129c188495d08fc695e587c20220708bfc9ccb872105f6c5aa7d8586dfe9ec82145a61edf38d5ab47760869d644023210291373b7b1a1ae01203ba5ac465ab47ad2975dd46feb0c6827d38bec670d79d14ace63a901a81919b3da3bbdf48602f94df63d0ccfcc8203bb1412e88212b533350f813f9822de75420fd3b02004630440220792d4365a4b433737a83cf75f47073e5266ab28e21758fa5994f7adbe92373bd022061a9def9ce44be09c934469a771ddb0eec559f2e257da0e733f5c05cdc1af78c46304402203a5b0294c6820e652a157a9f241658c632563594e4aaf3937f5f1fd2b7e94df60220625d6dee041dcc48c15927db2a4981c7854dbad62feda43ac084948cb4c37a72473045022100f8c67a99c36a2a73a0edc5defc063a51e426d8fa08b49a709fd96e39700fc2ed02204b0aa14dd4c6000ce9554812afa6c02a5765c41c214f908201328885d25fc3f14630440220784b4d20f4c85bf4b1a68a2683d8cfb7d798909399783005e42c856bd7aebe12022071b66e455d812e13171b675dcd3bbff559a7db42b09fea12a8531f75217b474f46304402200899bb9940e1180c55fba8400fb011ac6e47f52faa54b1d818eda651f6ccb27d02202dedac2049ff98bc142f183b4129a0617f351d8e7224a8ab7a70d6e8fcd982bc473045022100a0e3d8d0848e75d89871199b6b1ecdb5ebbded25cd84b31426a3bcb911852f2b022014eb50f2c2615d825c35c29a05dcef06550b755a47a27f5bddf199312bf432f246304402200ddc04324f0a6bbd1a066477aa6d07af95f2f815cd45fa58c59858af6b525f16022034797d1d71c08dbeba4792cc0cbc9ac55d17fe114cfff1ccd3c4e2cb41610100463044022055331ce180b06b6f79c73c7a41fff0365ea2504aaaa9b9f142be7854f91d2eb002206db67280ff22164606c70a79905eb917247eaf9d5eb5cfec5343b9dd4f6aba8a2b345573014aad6f4ccf7805ae1aed6e5dfd2757458b4d3b4da52f344afbbe0ed076784cf55e17a2484730450221009bfef877e07c3ce100208dd7d522071b364df4270a5734742804e9ac2c2426740220298f95eac3d3e78e71c2cc4e6d8647acf6c53df205eab3e44aa807a7e4daf6a3cf98bc760000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff036c30f9dc1d730fa017a91476326fdefe3eb33c3fd2888e7fa809bfdc53423a8761de5c33e996eaaf232103533dc3a1bc0452280cf1f581ef4653716c02d2c709e51d2107f7a96ad68edae0ac2f54e7b569135c7dfd3501002102486f9c0dd1895e81be684a01390943457416dab4f8ee7f13cb6e342c8b0d5f692102ddb8a7ead021bf99170557d9e91787b7d6da90d51a84de5215cf48b0ff16944221037876edc52e51fa062caa4e7954d4407bb5abb5525e720a401a0524a1f4e128672102494e028fe6cde1e42309a83d8fc1e9f7aa23c683647dba1c8902b04f8ab250c42102632bdad1832f3094a27011598434b6dfd3ad5c0e324343548955b9e47699ef202102c179afe6d0a8c7ad74977ba93a31d02b3339a4fa9eaf6f594418b748fda075dd21036d1d97c281eb12ff31d4a3d6967ab5ca70f7debea1541fd827e0b7afe8a93c2c21033f0fadba950ce670f916fd98329295be45de5e3e45f21df9568e9648462d84df21033de867cc52ae1833d035de009b0d2ae72415e51aa33572f751dacdfbc264800b59ae01c3d5a4" + ) val txMatches = List( - (true, - DoubleSha256Digest( - "635f69962abb6e75cc3a94b6c604ad86f33f514eef12a33fefb8ea15389b1fd9")), - (true, - DoubleSha256Digest( - "62e40ece65cff821b739f2cf310a9917c97e7475153df8a55fde1ea151731f7f")), - (true, - DoubleSha256Digest( - "889d7ede4ca91fddc32498ff1b7400526419863af3a84da2dcd24cf487fd881d")), - (true, - DoubleSha256Digest( - "dab811210e8000ac63166d032cc2347a149b2796e10b0292c249f61486e416a8")) + ( + true, + DoubleSha256Digest( + "635f69962abb6e75cc3a94b6c604ad86f33f514eef12a33fefb8ea15389b1fd9" + ) + ), + ( + true, + DoubleSha256Digest( + "62e40ece65cff821b739f2cf310a9917c97e7475153df8a55fde1ea151731f7f" + ) + ), + ( + true, + DoubleSha256Digest( + "889d7ede4ca91fddc32498ff1b7400526419863af3a84da2dcd24cf487fd881d" + ) + ), + ( + true, + DoubleSha256Digest( + "dab811210e8000ac63166d032cc2347a149b2796e10b0292c249f61486e416a8" + ) + ) ) val txIds = txMatches.map(_._2) val merkleBlock = MerkleBlock(block, txIds) val partialMerkleTree = - PartialMerkleTree(merkleBlock.transactionCount, - merkleBlock.hashes, - merkleBlock.partialMerkleTree.bits) + PartialMerkleTree( + merkleBlock.transactionCount, + merkleBlock.hashes, + merkleBlock.partialMerkleTree.bits + ) partialMerkleTree must be(merkleBlock.partialMerkleTree) merkleBlock.partialMerkleTree.extractMatches must be(txIds) partialMerkleTree.extractMatches must be(txIds) partialMerkleTree.bits.toIndexedSeq must be( - List(true, true, true, true, true, true, true, false)) + List(true, true, true, true, true, true, true, false) + ) } it must "create a merkle block from a sequence of txids and a block" in { val block = Block( - "2f247158b40257ae05420c51c4f9cb2c0d01113685db8835af6f267c8aaf6f5f4e27f1696fb66c2799a6dd4b1acaa7eebee05f2762470de7bb60891c57c7892ad4a455593e6470192192002342d6255c043728cd4a050e54bcd4f4e7cc7f8d543aabb76d8748cf97c58edce17b99a51865575499cc016dab319000914c24ff6b348213f17befdb73872c4e7ce4934a4f70e0759e12178396421be8837042f81600a1386c473045022100d0b82cca7f8593bf93c120e44e520a275990632ce9b68280573c177c2ee3351202204d3251f0c0857220fffccea2af71a2991a8122f68ff8dc9cc5a18cd683bf85952321021bfea9104a9baf59dc6e92e95afc3fa6b4e1d93a9290fe61345e438daf4d503bac39c431895596a146dc3560e35aa2541f93fda8387790a9ecdcec42be5466acfc3d27c75f96e96b2d484730450221008587e06db9c70b2da9eccca309b29aa7e6ceaa5ec0a839570f900e7ecdac48bc022003b0405653c706eeb1a4a47b0f7bfe8dcd1b5557b9930327d156c429d5bbcd1747c094a58931e83a753240744eb79444f9328591e95fd56f77f4387ffed5aa3b5a799ce40cf0c542fd750400473045022100c1a6ca4ec3b5621c7d9963b52f1985d973f5fbb5a4f50702890996b87b85595202202cbf793d8d0b9c174b057805387d3bea0b1b65cf87a27fa8cf3d8ed8fb039914473045022100f86f17a28b2b7fb8dd458c7507999d4a2477c8f80e1ed4450b55d29631cccff202203851e9cb1e0bf2dbdc8f42dc44c82a6bae99d0a5261126d79f6d982afea8815d46304402206a6a80f4870153024490b826c1bd4f40f6ed91e21039aed3bd5a3e43d531d6ac02205a093b302de7c7e533913d060c461762591cd49972098eda962512f8d9e565b346304402205291112c88c643ad0628856f6c1040b347dba746d889e774ad184f941ec9855c02204121d8d8aad5bd5911afcd730fa075ff987c6618609411becf98b7f466dbb4f3473045022100fae2c8910c0ec0374736097bfa93cd2a866c4dd30ec3af3f102abd65b3a19b46022027de913044cceefcd4c5d812056dea05dd8a69cb235cb794ea14e84e096c5ecd46304402205f00600fb39cf79d0d1c10cf5b232ca0703306240f5978fa37e1a6dd3c6318bb02203423d39d05b0204e0d8a9d90351aa1dcb5645f5a80c566ec90fe35ce4fdce5e6463044022043c663f756ff0a0d29f00ac343e04a9739e3c5a2b059040d387e7f438a4f1f0e02204a7d82941aee47eced2bcf7e522c93e859347f6692425451a2675946ef8a72104630440220682be149764e6997248c8f22a1eef030b0aa094c26b67a63e7e7b0e1833ad7c5022052375d764c759f6119f522939e9dfd7289a87869bed031485019b8d99b25a404463044022068e80e99f593f783dd1d27c007576e49e37b4e1b8c89f969aba271f85c4c267602207381c3fb251d7d9a7d235b184364361ff4423159434d017c84d5869e38f09a2a46304402204c0a4bd6a70d298c0249b446c511ce86def7669bb6b5cc639f1b23f36091a12702202d29c32a8fbd71d33d7a03f494365a9078b199154782da7fe9aea192665fc78f46304402204515f64c2c13f761a2dffbdd487c4df7b657ac34869f1e36a49b096300b150b502203c084affc3af987d9e685b2a3ea0a01a84c9937b5ebb20267c49cf8a64d05de846304402206bc836b700746ce0e1f030f1b6faa9828ff1779cd4f05b8486db9c6ffc2769c40220056b492b41ee40df4aaf6605cab94dfad004a41663159678dab84fe6f2e9f2f0463044022009ed4275fd27d2a120bc2f0bdf69b8cc6fab8628faeefaf9d7b9cc7c18f7b2fc02201560d86acde75fa2a63f1eb40a47bee847dece63622a9cfb1d7626d8747e286746304402203462127f9f5ca7edec6ae7ad47cf2d0744a4d0f8d09f802954a491dc0a77fdda02206d0b1bd886ad7ef5096c71fc24c5fdf4144c0dd0a770d1497465efd2dfc51451473045022100919bbbaf560a34e334832f6440f7f5bf254fcc5d87f1382e0ca8f55b64dc385c02204811a5b9c7c2ed7b57e02acf7c3a55b8c05df9fec8f2f686b34b56ae752f3cf6463044022032d47a6d28fbb14c270bb10a99fb59e5250e7c363a82a82565df74282cea3c0a02207e60ad5a85f091a2eb44574d4d86e8aab21c59595fc05adfd95b2154d717bbc4a8057c94ddd44cfcfa79c8408ef5ca9118dad4b0540d2dc3c07a6245bef2cdc92e2eb932113d069969463044022077cf9ebf65fa531d1ee00593d0b65fb4be3a0dbf5eb30f567757817c03e0b81a02200133c0ef5310484da10ff4afa142f5d86f184d089253dd518e7252f8969ebcc021028b1ac06e23fb71aabfa7b3b1dea7e95558ae98eb7c913c173e269b08862b1e589ee9f81209594e4e4419b089d9255121034a44fe6edc7a32f9f4dcb5cdc52db227f83b127cb88be983350ee6b2156426c151ae25ca21b305587d9dfd350153210213204851866ae5f641ad75350a6fb87638e867a5b747869e5189f3e9147da39f21037bec564897697cd4a2b354643ca0b71bdb17728f1553fd8f6b6f65787a7a91ff21025a803208e92f837d55245b374d6a110416039992f6df32790d4d2cb9733b034d2103d057b615eecf55b9e5ac926c5bcf62e87066a0bb1242c54df1f896a5ecedb2aa2102d43dd3db230a390133d90935b8daf515ed87737003baa2c3913305ae8b41ad41210390e827472d19f448042bb29e853518954b965cf65a8ad2686eb11947c84012de2102c47ed486411aa5fba1c6a456b2b075861e4fe937eeaaa148f00b4b24870e86cc210319ebdd3d2b12afede62650464314c93201e6a5e94593fb4aeedb73b9c114ef402102247362bc7bc5e74a141583cb1082df1a8efa094d537f8de9a9f09b13fbca739359ae34529ecabf27f35e2321020e148ea60e6bade2da1602fffca4a7d67a4b7dcb311c6ba848667386973e66feac945e7ce325bc37cd1976a9147bda69999178c6a4b6d89f8ebbd94d3cbfdf655388ac0500f3fcacc58e48232103494ab432654b3266283bb68cd93d89276f03c86b8ca19ff1b708f4b7cab3f5daac3c42d5603f2ce10047002103b8addae404260839f3349b4b1057742e19f59c1db0fa037cd6ef7393a7b8d1672103873f30fa80e16ba6182fdbced8e5198c867f104ff1cdf90b340932e872af3cac52ae5b673e18f1708dea1976a91413eac030dbe824b5f86fee21e40e758b3b42959288aca0f58ffd54a2e91efd3501572102ae0fdf45bd92bc5aa35df8f5c4d90590cc1c9c389957f059f20522c60791ad6421026a0fcfba1a8cb871e6491370b530035cab26416cb9f751fba029a7fa6297e4b72102097564678faa59c8b6300df3ab709f08d6f2227d96b6c8b2cf01f4dc186572a7210359f32d27fae5ede2183ac8d9e5c3706cf8b93dccfd3bd26b2a2bc996a3534b71210373ce30bf1c574a997a57f1b99e843a7fe9773b4b188fc41cbf0e5fbaa6e1bee321028a864331e90458061dfb027a1ceef1ac75bd380f3cf5c853e4506e42df610c0b2103f858a27a7e2e63b3e012ff791f1b38f75ade9ddde1e461b867ef58f166ed6da5210281c568b5f72242e294056c6e53f809adbaab2117777ce3d8dc68a68793f6c6932103af79ec27072a573b6aabef7c2622e2ceef7a0b6dbe0ba6b82d7d73cec80d314759ae908ebb7f1f5a6d64002a1fdc66ba5086f8032c4572bde4696259bea3cab9c972eb5738be629aa3e81aefc7f08b3d01c8eb263048065efdad010046304402206101fd381adda1ab311d28d5d76a048e8ed22d054d47862514ebddef86f38746022078b298dd15f4650086ec352f40811ec0306ca8c73395e09b1fe5bd1a6d1487c2473045022100fa101e79ec5602d10c1a9c32dc40f663b8346feb95ab7cf610683e9370adc1c202200d06e022c83e15b4ebdebb66c68743075426ea207805871d37bbe68772b1454b46304402204a7ea44924b5b118dff41de8abbd7ed691f45882c3d5f8a4fe36eebd98c691d80220484e78cedf60b8aa0cc5d5dd63c4e805bfe39b9562c0cc5a779df9093541f6ca46304402201d0e4c62ae8e05da56b1ba240d86ec93912fcb86800df6ae055af1e0b6de18b702206d0fdef7ced1374a81179ed185f652daca0c350bb2f1c1d72a449b31c00ecd1c47304502210091f60e4ee97c095d2b6f5528d59c4fb6ee71f19ad832dbcf7fad8ef581b4087202200fbd21511732a9e687b8821665c8246f8c3c69447ea59c15d6d3cc5486938f9e46304402201c5920883f123b2659a56277259dee8a43f2aa5d2c81cf0e821433f61657c110022052c3628a764e201d74d846a609c90357c9e152443799c89ed01eb60e238bbf1f4b03351b90f713efb201281330d93e263eb24ea17dcdc796b553ad296eeab6307a339cae8dcbefa84746304402205379e14203cbe3a91c659fa804ad590810ba7e65bea515b9f1dcbf151d6f8b5902204ca15da394b4ac2ecab071702dc245908029c4e21dcff9af199a0f1a221f04109eb89539c2663d3dfaf41cfa3e4ce85ef2a236d0b745ff61e782f214e394d4c694afc5ff0abc411b4746304402200c97635e6e9c839d0c59011e6065c7a98a84bd812007d74780db07bfeff9d83a0220702da17f4ef2a2718af4694fbff87e7f407b5e4ce8f0ebe7860c29fc0caef4a1a3567464071fdb8fb8d69bef2bfd01025d2103f8c0811cc25c1aee46a56daa050264d3dc1e8085024e769ea81670c99ef398372103971a3da9af94725734001ec7e2c5870c4d9c375738df617d4c03f3ae0a95e9c621026b44c84a2646bfaa47eb595cc1d1f2aef4553e6456a186d4959bf8f695704cba21032e02282c4527294915e3a299b1c05c72e760a134b7ce110eb2315a1608c5447521034d57a263b104af70ea014a850e32d7795243fac04295206419be6547884b79bc2102e772830819c92f86b37bae687833b01500dd2efd8c5999f53dc83c2eaabb8d1b2102d77296b727b470f4c439198a8cdc87e534aa825cae1874ba4dfa6811b1f48ba621034222b79fecb6c68898b8f94b649f39e415b498ea04ac1c8d5e5441aabe5440cf210291c8f2572c8bf1058b0ed7a6010011b458c2b60bb6eb04118ecc3c7c0fca516621023abd9770f4b7c7d6450c9ffa681391e493eef0f60f768fbc06173608ad49ff3921036bc140600e58d6f728853d7a17d819e1ad78cb8cb2fd73aba96fd3390d0cf3872103d581349d55de4e5510cd383d19da4324af8cd9b168af64acbc8dd1ef4d0f755721025f2b33757c607b836733b3017dd65e3abd602469fc5fe152572566f437ea1ff5210353ba1a98a7498bab23f5eb16188b16b3a689ac23322b875a9bfac74b7ba640ed210249efe5b22f7980b650d563a064f68054fe09156a58e79d19e3036486f17bef885fae4896f05708aae9d717a91433674c61ee5bec90093bcf07bf9ddca283aa301b87abddb256c32ca8d41976a914a16bb220835fb8e964866717327cb44e0b3b376f88acf143f0c369d47ccb23210268b11874605075190703be6a1e5a963ff9fc0387d062b0324f70756fe8ef0983acd3ece8c0c87928ad17a9142b5f5920b6b6921c38e93714342cfb0171dc638587ce739c27ac5a817a1976a914bfee48d30995c8b8a35601cd9d5423af02d6434e88ac537329e6f27a89e41976a9142492dbe56951ddaa2e0c4a2cbb811ffded07903f88ac8014cfa3adc7ca0805eccff39ca37d4c53d31fc1955231272cbd6acae0e4d1ddc20384b16543db5365a77a9e234746304402200489bbee20504f3afee025531a8faf30a2aab1b08e2ed431c97e4abb4b56283a02200ce64994a9ab66e9b4e2b2af7ccbf7b6e0ca402ceaf4e29d0f29cf58e0bb14893e1e9371d520369488180440b76d8d5d649cf75875dd4ed84e7e7761bbad3231e51d52601222748f002dc0b72b9c712c458c844a083db6a174078b0e4f4867ce516fdc8ed8f32b21c21162aecfeeddd18a844730450221009f64eb385f84dcc1fa9313ff75e3a8e1665eca2e9a614dae74174aee3c00762c02203946b4a3bcaa8eec2f417abcecff86490739da66a8bf41fee92492174166c9d32102cfe330ee10302da072b599d113ca6a292cf78374788fd5542b76b3803377634e1976a9146375d4a731d767b99cec280ac9376229634bfb8a88ac18e6234226ad6cdde6282a1cd57b441566b00e3d6c9659b6aaf2e6ff540285f92ad5d78f78a030400032188c49e37a4d2de0bb351f5e8ae27bfbf3ffd7cbdcb902bc3eaa71551ba78df3c42edb5281fc78fd920500473045022100972bb873053bcb79d024b17031dec7c5a26a18f1e2214992372c4f15a30f0d16022047d90b0baf211b710f677bb6157f546d9b8ec29777cf8371a4ca52762925ac0c46304402201bdc416014a5c4ed88042c6f3751ab2d3c629cef4885727b615382acffdcbd6f0220158fe55a2b0d802ac742133f8290c8725fe5c5f3e7820f1eb4fd47914377bd2246304402207e8e4769e3bdd50cd01c2dd51f839d6001ddb14178ece9a75dcc9f7e73501cbe02200a5d974d49d88a00b3b5fbc9c1b1a7cd2ee19212179154fe1506a618d7b98b2b473045022100b69fc445f725e93cd3ab99e73e00c7a4ae39d7d419dc251ff7500f5563f4a9fe022026e747c324aff902183c26b1a2f076fe3c3174470be30a045cd444b8508b60c746304402200327444b22fe5d2deeb0f1d6c8977ea9757d783ded16ceb6bc4519e7f0baadbf02200f26063a60c6a6e5daafec38df4d03e62cc25c2dcd3f30efed042377c224e10b473045022100ce8992e834fa3c660e9a7190bae2676fac9d2a2f59bbd442c2e6ef647268540f02206ef2c2988795d92cd06c07817268ee4fce697d296a9644f3285ec7b5be79958c46304402202f60bfa078106c477a324b18688e71ccaa9c0f96ac146b17bf2b9aa007c02149022058080ed5ce256000d9f1cdfac908f95c97ad9110fcfa6fbfae517959e395e6ce46304402203a1c35d5e14017085d03745dbe777de0d66b73914c3ee4e9d54df5797e0a506f02206eb9edb92ed1b5623e40bcc4818dc11b5b85d16cc1ca7a39b62a7a5064dbcc0a473045022100fb5bc2a5ef78fd783371057beec835d72116cec65c099e8c922f9a88027a0136022040c427817bd0bfe59749d5a72b8606d9704bd39a971ca400f12291eef5ee264e46304402207cc201e99ff5243d81b71a4408844d1a0d1e53fa2127b6902763a9c50d95a0ed0220077cdf302cc005d5349adab4c479d711532284f475ae0291e676e25fd13e69cd4730450221008b5db9ef00e5fd11c0d8600610558312eeb0deef4a9cc8c03ed29579586a8554022007d9cf97e14e5eb7ebc178c81b04a227128272eb93813c55ea4f3ba0cfae9b32473045022100a1b8faabbad0c14a25fdf884658dc5808005640a8083cc338802ad45a6611f9102207d0cfb4c7ed2ea2878475a711dd57a6f42ebab8a56765024f823bd06d3eaa7cf473045022100cc89d81a385fd7945bc95e5658eb715faf209f244e5f3398d99ffe4f9ce643c002205afe76f4d46d0a3e3359f20d6dbd35e411e5a38bb19c4c0078e6ed76f2d1f95b46304402200764e5e18694353800907f4f84abc8e8b8cb069f3e6b26c826ce113639b2b91d02203f15940a474f1b353b7c279ed964cfb877beb7d761e52781025e8048ea2d1d60473045022100f6512845b8dc207a3bae030f51df69e2867bb3417a2b12ce6246c07118bd853d02205317ea91e78a0689af1633e75d581589d83588b35abab034697d981cd16a8240473045022100f1ddae4e26d399e6e73193b91e8e11d2b1a706368a216081cc2e0087475565cd02203afdaab247c766cdf1c0c6883b23c2e5db66db4df2aa1b3ecc925c389a8212b64630440220303277460991a5050961837dbbd9c3c1855b7f6733da56af9855f916bd3f64c802201cbef836fd69ca80eec58b62ef0d8cf57d270948cec66f67addc312139388a7a4ccf552103089014ded106cdde33483fd1a361a76de8129d8f200c71242e3dd0fda6cf8f2f210206d8d1f2624f621c3f30b73e3e07de771e665d8edae3426b6f7e2ef1e7061e892103675d0b5afb0ce9b558ed1177efcf5782ba4b055051f8da27218e709b322adb9721021db9cc3065dc738b6bdda3822b3a61b837a1091d629d275f229e711eb45af07e210319b74d8acf6ef64528326ff6fc31baeba4c8631908a757a831a82bfdf696f0fa2103889e2c0381943efee6cd20f5e2078edd918eb7b0778a9499f34e42e21f3465e656ae15aed42f0972d0194b64c2518223210223af4811bbcd4d5982af6960e97e6432500bbf915c038c205e867e1259b02bfaac2702c59e02495735fd8b02011321026bcbf69a06230b202010e1abf7fc5bcbc892a443142f76e349494615ebb33076210280919cb6dbfaf0211f0929c0c3a0272c4c06fa8cf495f532d32d78af8fa2f229210378a0ea90f4a52b12b454ff860e2321e8b24464b2169c468a3e51fa3781751f752103b372ab36fa0fd9d659b3dfe3ad0f7938471dd39c63e10808e09a918b11f5cb66210222fd1005ca1daa87c93fe031a19c99ce4c6b9d3fe4991ac123ca5104ab9372fc2103c9b566ff968c86e6f437064387ba4f8370822ec8fd12967c4113926058e75ffb21026eea3437217135f10def85a957649762687089de77491fdfe1a65a4776326aeb2102a5c88df754e4a19d3af5ac92c99351ae4997c4c5d2733fbde33b2535929d38da2102b03dc2fec3fd28266de13c1b28f656282ff4befa0ee13217dd7bb050a9d9bdbc2103280cfdf0a2842d701395f7194b8a1e32b26b5c73e19657145c7861ffbcbf295021025792fe84ec7f4513e0bc57ba5fc0e46473636f467b0d36832b127845c7482f102102cfeb11d170db132d7491a5d2b3a4916d876bc38199ff47933c3f79d1c89110a2210330410ef6756077904e93bc47ef9964a49890ce29984ed3bf4917dac8fd115da02102e0545f7570469f6784fd934712d5be11226546f7a90be00dddebda83143edc8c2103bc91bfbdfb3b87d9f0759b87404bc984f993aea336807dfbf068f7b7043c7270210347cd4a2f28d83ac8945681006ecd16cb9965ddecbbb96a904648d780d852e50a21023efdb63b827dc0559809975a9ee9caabc2e9022b7324ea0208e433065b7fca4e2102382a86cbdd671fa020ca862bf2bc6c3cb8efa39293826f9327083b70f1657c0521027cc4a3f9271f4c653d9a70ec515150f8ec4d5d97abbe83976b2ac983db8f66e60113ae0298e13d42d9db8cfd79015421037ea59ca9d2ca9add12daa79ac092e39d158048dad303f642bec393c9444f647c2102c433d0a85444e6bce649c8daa8bb010535114ddfec722e5c110d99bb307d7db5210268ece74697769d7f87d3080cd9b6c8031b4c5b82cc47cbb3fcd84d1e2d8f24c021029e78f394ef243ec50572db6b4f40a9e76d6dbad7f6b3a54d04bba420302633c22103487bb90849358eddd3c64e6db5c07a9898f3d9f7a6fe07c62f277abb228f1a3f2103d07e54d9ca3a76a7f857f466c0cb7e5c04df0d83ebcedf879a4d50238ab52e4721039dac049f9bfe92384e7b892ceaf5c0b88b42c1eec171152324ba536a2d84a5bc2102d1d112e97afe393b16ab4d9e5393e5efcc9b06bc5a683b5ac35e618dd64f77c22102d603983c29b305ebc30b4583658e5aaf13536ee7f31c96464ec7a8e6e4a1371d210274a2b7bda8e18d8965f626bf18e321f4ef595b6a28e32815d639d85e91c79c02210366f5694e036e60479587fb0122f4eee6e090470cd4216a844e11a632a6a3a7295baea46f26a20b559c07000efc21d48136770efddf01512103453ba9ea78543ccd0fa820cc7d6c86e5bdc4769c77450696048950b80433dd482102e3500407b5c882b5495c9ed43e2bc0729bac27724db3c7400854dad3183c78c42103a609c6a2b7ad43a310e30a5ce474d275325c587e586db55c43a9afeca4f68ab42102f6b6ffc821f32da645a31c7f86c1588f93bbe17634ed33c658ae459c7c174aec2103892c681ab3d26a4b0695faf43b5dd5f7163cb1e315152e9a735a62add4a84e022103581b752ef869ba3d9cf96001ff9c1ad5178e2f595f1c4681404b9f0217a96f2a21020041a12f5ef5f7238dbea789cd27e04d00b394a40c80506dce977a3660dceb8b2103ffeddcb98ceaa3977ff2548d74ccf9f15df32687f30c145bddfb0d62639fd10b210299aaf75b3b81a8989b72e9098d2f4dc26ac1ff960fd60c3f2628ad717d9cf9332103729c8af8e33f7429ba0d4607968678c7220410692270e7dcd1d7d5aa74560d6e210327a2a6b401740ff6a2add2b350193b22481b521d9cfed6a9fe73c1731670601f21022a3718f7d6027ceb9345a18971cf03f3234101d9cb2b8d950791e9e9f0f9f1f1210374b1b72fa9d29aace7b4b23540d279c4a6570cf41a9a208cd401f6ebc8a3d73f2102750ec475a34a12252b898972fe7ba59d90a036e6c760ef5a26cf883830683c945eae18623342a0ee6b8917a9141dc0a30ebf54ee41686147fb878b8ad83b288df5871cc2702e5c2925420010e1fee0b82f856117a91464f5c6846ef8672bf88fed779612ec0ec7d227cc87cdb001c654de590dfd9b015c2102d6469ac090e7ab0ac04bcb3cf97b9987ab4fc41ecdeb61feef13cae3d9fba6de2102b1280008615f651c4c18379c6e97a1c79861c7e8fa4c6796799bbc40458bba8c2103329ee3d3ecfe908bc64912324ffd6a230d26236712fb57d797538cfc35a52ddd2102ec72cfab6d622a9760ec63e4949aae324af584b7fe83324a4f5c6a4c5972ab0c2103d887e78149502fa74c46c8be462e9bdc8f82672b0de44902c68ba4f67495f96721029d2c2593e9c6521d5087beca492d955caec54233f4923be251f4d9b4e3c853de210268273d4fb018ba275a64e8c03e6f9cebf8ab142fdf53e3eb05ebd507e7f0269621021806fc4679d703e34af058cdf0dd9b7900a0f4ff23465d87b6e17d065438c13e2103e6b4804ae5862804a1f7bd632f5216e7cc724fd2c1b9f27cfaf38730a466964c2103ab5860ae2414cc6520ef1b7dadf7c1e3aff10e1a9a22a8b86a3367deb7f3452d210338b8c592406ac25735ac3d2208eedba2ebaa1e5845bb5531cd97d3954e666ecd2103be6121f4822d9c24d2c86b4bcd1a2e3e2e368716e29bf7a0e044c76e291ea49b5cae3d5cc2c223b54d7f040000000000000000000000000000000000000000000000000000000000000000ffffffff6a473045022100a4fcfbfade4c41c6fcd6e41df15f10045e32f4656258764ab8f805e89d9d43e202206d72cb9c442b61d0a7f27755916dcb893507187372629b1a08ab9c3dc150c1f7210299ac5dc6aaa801175a96809f2eb7a3bc9c8a5b93f71a001196beecfefb8ab274ffffffff2e8385f0c1a0613e5a2af5a50d12712159693487163b0b967f71a76fee56d10ff08a95b54746304402206c2c6128952287610dae1f6fdd1ad8ed5f952cca4160a2d2a00f68420697ee590220727b06013962341ec0e8de5f0b12ae672be69c86b848d84f2db195f55a76719e54b1c98c09b8a7ad804c884630178af9433a7881050d5cfd87dcc8788d0cf826ce43e7cbe1ff6afefdb0030047304502210087b68fe27eabfa4f06b90f41fdd15556dc32fe2acba8c11a710a33160992884902206539c4a13e92297087f3d888318e690e73d9dcd2916a161f9f8ce530e0644490473045022100c5cb35d666e0f0cf68704c0fe714d017d2ea2106483e40058005508f21d9b8fe0220303b577dce39de821bfbb6b56854700bb5bb0df5c147a3e0f214e48b59946422473045022100dd7694c431ad48143ef261d163a8221b87cfc6e589d6b42472a8892d10c52d0302204eaefd2c3378fa72412fa27f360d4790d0e50a8f7b1a5d8624959e015c0c0b94463044022037634adc089b295e97fd4aef7cca8017bbe1cb7de10b84ea9fd0edf549f4525002202fb7d941778b651f1a2d66d431cae3384b35f6120afb65d2d790cc0f16602fca463044022009c1ec813322782eceff706c3ec2446d4f56e787bd8c3c477dbc1a0e0cfa45130220343995339be1da738746256ea572837c54911a4dcbf1ff6ffcb93774bb1d967c4d4602562103658cbe412790816a4c2511025c900ab524e6a736c2399ec5efa42826904961a721027c4649c6a7fe582b3eb79347531293154492c83ba061d90b82876ef23c6bdeda210300c6d10cafc175107683332fe275227f4db0af936a2b4e4197c02d541a41cb112103ff51323f74758952288a78268f1cb18c0524e8a4bf1b40b6a8db2ce8a171ebf22102ea54dd70b6f97972d668666d70bbf4be6893d9f807860066261549384f1788bf2103f795ce50e03e47d21f96aafa41755821d575321760e5cdfe4322aa033a2cfe3a21021b10fe742be0dcc40c462bbd5327c616ddf110073a42dfe7b1942105fd5396342103b8c7734f15ed2e2ba3e70c80675b4d12c6b1001cd87056566b659d85668c3b6b2102375886e4e60a175d2869965d01e9e4737e087d16d73181650c727e03ec9b99e421025f023b82d762a5be722fe4c3cf3cd2c955cf67601494612955aee381e22ab0722102aae5ae83e67e3032ca1dfa1607a8259aae2aa909d9b78cf35f0eb2d82ae84b282102dd0e816c6328b2d482ecf7b32bf1803b33e793e2ed6356dafe1825fec8ce414d21021d254f0dd794346d187a92c4d9ca05e32d6554e11670e9498bc8f7b45cd999082102a3aae8af3162abdfc3a27ee7b55bfa67d18ffc85470b94a9376f0d9e62fa7b762102e5897c4c168fc593ff85dcb403f1295209c3ae9f9037f8ef1a95743e05503b8b2103a2912816bcdd549d59463e483cbf842883560f78bd4f579f9023372dba3b4c1221038c0ddeb41df85099a40d12ef8250336e7888bc6aea598caa44faa2e5812c2b6a0111aedfdce45edd4c460c7fc19c3de7519b83bf919c9173ec535c78cd1b0885def1cbe97b28ae184b524e84473045022100a18825a33f15061305a2f36930b813e67fb44a44f5dab784c31c33208d3e611a02202f5c3bcf823188c78f609ac525460f596e08477676165e5643b9848067cf2f47210206cd46c311d7e6238a8dfc78df0a4b43fc529a9c48df791f62fb8c050b320c421976a914b3497ca1071cea7c074f1df25e6f3023e98a6f3f88ac8b974220091d3b2721c70d582d17a914134fda603971e5b53fa6ad3e1a0f4efe386d264387bc0f0aa280e3a7dd2321022f7065d64cfc0ed9e14600b7cf8286868f0a2c74bfd0dc48957cd4d69117c6b1ac64ece0dc326105d800f21f10289e5aa50900459353e342c96fc617a914ac250f0fac101b360b30f60869d21be637bef8c987b83bad62ddc13ef3fd9b01532103140a1ce712cdefd10cbe46677029653cae5289cd0ccd68b4fd40c5ac079be6a921035764aa7f938e29dfe613c80c52427e577aff53f3469cdc3eb78d055e05a89d472103234042f2c158e9bf71e32db30aba5e2e0b44981ee42e7f0d79c800c00cb4b57421024636c3b3fc5e95a7c575fe001b868b3e4acc93161e67acf28272fdca2b4ddf372103f8833ee5bec14579d23bd987408b9f2c0e67f9188bca483ce814852c06f2b7452103b6c3bfe5bf1a3d0af3494f917bf8c134a0b76e56dcc34d6b56df5f6052fbc4092103b5d0c6f8835171e2cfe9a5d9c3aa4a300b74ce217b10a5522cf23c106bc201eb2103d06eb0806b3a15686c16eef0f06296f5bd7ca38162de3ef303487effe7b5447621025f834a5f1a7811464cd87a129866cb04560458a5a6ff0f29e99b14fa856c9795210246ea1eb112477b8bd702a8abe1ccd9b1dfd2790ed42a57fa6544bcece1b5d32221035163c243f7bcb8e8036f2b2296994057feafed60e140baf10cc1280c52efd3812102f2ce1f1180dcf44490b74f2a8d9af6e96b11321c9586cb674f3adcb7bccd48fc5cae102dcb7ca5c42b351976a91413a5d7d8aa82aa0b3077db3f9b7bb628e222ac0788ac8ba5a74c5fcb966417a914968ed5ddd83d344f340d5736c76ab94ddebc84d387860d9fb0b0a9a15500a3fe04c9") + "2f247158b40257ae05420c51c4f9cb2c0d01113685db8835af6f267c8aaf6f5f4e27f1696fb66c2799a6dd4b1acaa7eebee05f2762470de7bb60891c57c7892ad4a455593e6470192192002342d6255c043728cd4a050e54bcd4f4e7cc7f8d543aabb76d8748cf97c58edce17b99a51865575499cc016dab319000914c24ff6b348213f17befdb73872c4e7ce4934a4f70e0759e12178396421be8837042f81600a1386c473045022100d0b82cca7f8593bf93c120e44e520a275990632ce9b68280573c177c2ee3351202204d3251f0c0857220fffccea2af71a2991a8122f68ff8dc9cc5a18cd683bf85952321021bfea9104a9baf59dc6e92e95afc3fa6b4e1d93a9290fe61345e438daf4d503bac39c431895596a146dc3560e35aa2541f93fda8387790a9ecdcec42be5466acfc3d27c75f96e96b2d484730450221008587e06db9c70b2da9eccca309b29aa7e6ceaa5ec0a839570f900e7ecdac48bc022003b0405653c706eeb1a4a47b0f7bfe8dcd1b5557b9930327d156c429d5bbcd1747c094a58931e83a753240744eb79444f9328591e95fd56f77f4387ffed5aa3b5a799ce40cf0c542fd750400473045022100c1a6ca4ec3b5621c7d9963b52f1985d973f5fbb5a4f50702890996b87b85595202202cbf793d8d0b9c174b057805387d3bea0b1b65cf87a27fa8cf3d8ed8fb039914473045022100f86f17a28b2b7fb8dd458c7507999d4a2477c8f80e1ed4450b55d29631cccff202203851e9cb1e0bf2dbdc8f42dc44c82a6bae99d0a5261126d79f6d982afea8815d46304402206a6a80f4870153024490b826c1bd4f40f6ed91e21039aed3bd5a3e43d531d6ac02205a093b302de7c7e533913d060c461762591cd49972098eda962512f8d9e565b346304402205291112c88c643ad0628856f6c1040b347dba746d889e774ad184f941ec9855c02204121d8d8aad5bd5911afcd730fa075ff987c6618609411becf98b7f466dbb4f3473045022100fae2c8910c0ec0374736097bfa93cd2a866c4dd30ec3af3f102abd65b3a19b46022027de913044cceefcd4c5d812056dea05dd8a69cb235cb794ea14e84e096c5ecd46304402205f00600fb39cf79d0d1c10cf5b232ca0703306240f5978fa37e1a6dd3c6318bb02203423d39d05b0204e0d8a9d90351aa1dcb5645f5a80c566ec90fe35ce4fdce5e6463044022043c663f756ff0a0d29f00ac343e04a9739e3c5a2b059040d387e7f438a4f1f0e02204a7d82941aee47eced2bcf7e522c93e859347f6692425451a2675946ef8a72104630440220682be149764e6997248c8f22a1eef030b0aa094c26b67a63e7e7b0e1833ad7c5022052375d764c759f6119f522939e9dfd7289a87869bed031485019b8d99b25a404463044022068e80e99f593f783dd1d27c007576e49e37b4e1b8c89f969aba271f85c4c267602207381c3fb251d7d9a7d235b184364361ff4423159434d017c84d5869e38f09a2a46304402204c0a4bd6a70d298c0249b446c511ce86def7669bb6b5cc639f1b23f36091a12702202d29c32a8fbd71d33d7a03f494365a9078b199154782da7fe9aea192665fc78f46304402204515f64c2c13f761a2dffbdd487c4df7b657ac34869f1e36a49b096300b150b502203c084affc3af987d9e685b2a3ea0a01a84c9937b5ebb20267c49cf8a64d05de846304402206bc836b700746ce0e1f030f1b6faa9828ff1779cd4f05b8486db9c6ffc2769c40220056b492b41ee40df4aaf6605cab94dfad004a41663159678dab84fe6f2e9f2f0463044022009ed4275fd27d2a120bc2f0bdf69b8cc6fab8628faeefaf9d7b9cc7c18f7b2fc02201560d86acde75fa2a63f1eb40a47bee847dece63622a9cfb1d7626d8747e286746304402203462127f9f5ca7edec6ae7ad47cf2d0744a4d0f8d09f802954a491dc0a77fdda02206d0b1bd886ad7ef5096c71fc24c5fdf4144c0dd0a770d1497465efd2dfc51451473045022100919bbbaf560a34e334832f6440f7f5bf254fcc5d87f1382e0ca8f55b64dc385c02204811a5b9c7c2ed7b57e02acf7c3a55b8c05df9fec8f2f686b34b56ae752f3cf6463044022032d47a6d28fbb14c270bb10a99fb59e5250e7c363a82a82565df74282cea3c0a02207e60ad5a85f091a2eb44574d4d86e8aab21c59595fc05adfd95b2154d717bbc4a8057c94ddd44cfcfa79c8408ef5ca9118dad4b0540d2dc3c07a6245bef2cdc92e2eb932113d069969463044022077cf9ebf65fa531d1ee00593d0b65fb4be3a0dbf5eb30f567757817c03e0b81a02200133c0ef5310484da10ff4afa142f5d86f184d089253dd518e7252f8969ebcc021028b1ac06e23fb71aabfa7b3b1dea7e95558ae98eb7c913c173e269b08862b1e589ee9f81209594e4e4419b089d9255121034a44fe6edc7a32f9f4dcb5cdc52db227f83b127cb88be983350ee6b2156426c151ae25ca21b305587d9dfd350153210213204851866ae5f641ad75350a6fb87638e867a5b747869e5189f3e9147da39f21037bec564897697cd4a2b354643ca0b71bdb17728f1553fd8f6b6f65787a7a91ff21025a803208e92f837d55245b374d6a110416039992f6df32790d4d2cb9733b034d2103d057b615eecf55b9e5ac926c5bcf62e87066a0bb1242c54df1f896a5ecedb2aa2102d43dd3db230a390133d90935b8daf515ed87737003baa2c3913305ae8b41ad41210390e827472d19f448042bb29e853518954b965cf65a8ad2686eb11947c84012de2102c47ed486411aa5fba1c6a456b2b075861e4fe937eeaaa148f00b4b24870e86cc210319ebdd3d2b12afede62650464314c93201e6a5e94593fb4aeedb73b9c114ef402102247362bc7bc5e74a141583cb1082df1a8efa094d537f8de9a9f09b13fbca739359ae34529ecabf27f35e2321020e148ea60e6bade2da1602fffca4a7d67a4b7dcb311c6ba848667386973e66feac945e7ce325bc37cd1976a9147bda69999178c6a4b6d89f8ebbd94d3cbfdf655388ac0500f3fcacc58e48232103494ab432654b3266283bb68cd93d89276f03c86b8ca19ff1b708f4b7cab3f5daac3c42d5603f2ce10047002103b8addae404260839f3349b4b1057742e19f59c1db0fa037cd6ef7393a7b8d1672103873f30fa80e16ba6182fdbced8e5198c867f104ff1cdf90b340932e872af3cac52ae5b673e18f1708dea1976a91413eac030dbe824b5f86fee21e40e758b3b42959288aca0f58ffd54a2e91efd3501572102ae0fdf45bd92bc5aa35df8f5c4d90590cc1c9c389957f059f20522c60791ad6421026a0fcfba1a8cb871e6491370b530035cab26416cb9f751fba029a7fa6297e4b72102097564678faa59c8b6300df3ab709f08d6f2227d96b6c8b2cf01f4dc186572a7210359f32d27fae5ede2183ac8d9e5c3706cf8b93dccfd3bd26b2a2bc996a3534b71210373ce30bf1c574a997a57f1b99e843a7fe9773b4b188fc41cbf0e5fbaa6e1bee321028a864331e90458061dfb027a1ceef1ac75bd380f3cf5c853e4506e42df610c0b2103f858a27a7e2e63b3e012ff791f1b38f75ade9ddde1e461b867ef58f166ed6da5210281c568b5f72242e294056c6e53f809adbaab2117777ce3d8dc68a68793f6c6932103af79ec27072a573b6aabef7c2622e2ceef7a0b6dbe0ba6b82d7d73cec80d314759ae908ebb7f1f5a6d64002a1fdc66ba5086f8032c4572bde4696259bea3cab9c972eb5738be629aa3e81aefc7f08b3d01c8eb263048065efdad010046304402206101fd381adda1ab311d28d5d76a048e8ed22d054d47862514ebddef86f38746022078b298dd15f4650086ec352f40811ec0306ca8c73395e09b1fe5bd1a6d1487c2473045022100fa101e79ec5602d10c1a9c32dc40f663b8346feb95ab7cf610683e9370adc1c202200d06e022c83e15b4ebdebb66c68743075426ea207805871d37bbe68772b1454b46304402204a7ea44924b5b118dff41de8abbd7ed691f45882c3d5f8a4fe36eebd98c691d80220484e78cedf60b8aa0cc5d5dd63c4e805bfe39b9562c0cc5a779df9093541f6ca46304402201d0e4c62ae8e05da56b1ba240d86ec93912fcb86800df6ae055af1e0b6de18b702206d0fdef7ced1374a81179ed185f652daca0c350bb2f1c1d72a449b31c00ecd1c47304502210091f60e4ee97c095d2b6f5528d59c4fb6ee71f19ad832dbcf7fad8ef581b4087202200fbd21511732a9e687b8821665c8246f8c3c69447ea59c15d6d3cc5486938f9e46304402201c5920883f123b2659a56277259dee8a43f2aa5d2c81cf0e821433f61657c110022052c3628a764e201d74d846a609c90357c9e152443799c89ed01eb60e238bbf1f4b03351b90f713efb201281330d93e263eb24ea17dcdc796b553ad296eeab6307a339cae8dcbefa84746304402205379e14203cbe3a91c659fa804ad590810ba7e65bea515b9f1dcbf151d6f8b5902204ca15da394b4ac2ecab071702dc245908029c4e21dcff9af199a0f1a221f04109eb89539c2663d3dfaf41cfa3e4ce85ef2a236d0b745ff61e782f214e394d4c694afc5ff0abc411b4746304402200c97635e6e9c839d0c59011e6065c7a98a84bd812007d74780db07bfeff9d83a0220702da17f4ef2a2718af4694fbff87e7f407b5e4ce8f0ebe7860c29fc0caef4a1a3567464071fdb8fb8d69bef2bfd01025d2103f8c0811cc25c1aee46a56daa050264d3dc1e8085024e769ea81670c99ef398372103971a3da9af94725734001ec7e2c5870c4d9c375738df617d4c03f3ae0a95e9c621026b44c84a2646bfaa47eb595cc1d1f2aef4553e6456a186d4959bf8f695704cba21032e02282c4527294915e3a299b1c05c72e760a134b7ce110eb2315a1608c5447521034d57a263b104af70ea014a850e32d7795243fac04295206419be6547884b79bc2102e772830819c92f86b37bae687833b01500dd2efd8c5999f53dc83c2eaabb8d1b2102d77296b727b470f4c439198a8cdc87e534aa825cae1874ba4dfa6811b1f48ba621034222b79fecb6c68898b8f94b649f39e415b498ea04ac1c8d5e5441aabe5440cf210291c8f2572c8bf1058b0ed7a6010011b458c2b60bb6eb04118ecc3c7c0fca516621023abd9770f4b7c7d6450c9ffa681391e493eef0f60f768fbc06173608ad49ff3921036bc140600e58d6f728853d7a17d819e1ad78cb8cb2fd73aba96fd3390d0cf3872103d581349d55de4e5510cd383d19da4324af8cd9b168af64acbc8dd1ef4d0f755721025f2b33757c607b836733b3017dd65e3abd602469fc5fe152572566f437ea1ff5210353ba1a98a7498bab23f5eb16188b16b3a689ac23322b875a9bfac74b7ba640ed210249efe5b22f7980b650d563a064f68054fe09156a58e79d19e3036486f17bef885fae4896f05708aae9d717a91433674c61ee5bec90093bcf07bf9ddca283aa301b87abddb256c32ca8d41976a914a16bb220835fb8e964866717327cb44e0b3b376f88acf143f0c369d47ccb23210268b11874605075190703be6a1e5a963ff9fc0387d062b0324f70756fe8ef0983acd3ece8c0c87928ad17a9142b5f5920b6b6921c38e93714342cfb0171dc638587ce739c27ac5a817a1976a914bfee48d30995c8b8a35601cd9d5423af02d6434e88ac537329e6f27a89e41976a9142492dbe56951ddaa2e0c4a2cbb811ffded07903f88ac8014cfa3adc7ca0805eccff39ca37d4c53d31fc1955231272cbd6acae0e4d1ddc20384b16543db5365a77a9e234746304402200489bbee20504f3afee025531a8faf30a2aab1b08e2ed431c97e4abb4b56283a02200ce64994a9ab66e9b4e2b2af7ccbf7b6e0ca402ceaf4e29d0f29cf58e0bb14893e1e9371d520369488180440b76d8d5d649cf75875dd4ed84e7e7761bbad3231e51d52601222748f002dc0b72b9c712c458c844a083db6a174078b0e4f4867ce516fdc8ed8f32b21c21162aecfeeddd18a844730450221009f64eb385f84dcc1fa9313ff75e3a8e1665eca2e9a614dae74174aee3c00762c02203946b4a3bcaa8eec2f417abcecff86490739da66a8bf41fee92492174166c9d32102cfe330ee10302da072b599d113ca6a292cf78374788fd5542b76b3803377634e1976a9146375d4a731d767b99cec280ac9376229634bfb8a88ac18e6234226ad6cdde6282a1cd57b441566b00e3d6c9659b6aaf2e6ff540285f92ad5d78f78a030400032188c49e37a4d2de0bb351f5e8ae27bfbf3ffd7cbdcb902bc3eaa71551ba78df3c42edb5281fc78fd920500473045022100972bb873053bcb79d024b17031dec7c5a26a18f1e2214992372c4f15a30f0d16022047d90b0baf211b710f677bb6157f546d9b8ec29777cf8371a4ca52762925ac0c46304402201bdc416014a5c4ed88042c6f3751ab2d3c629cef4885727b615382acffdcbd6f0220158fe55a2b0d802ac742133f8290c8725fe5c5f3e7820f1eb4fd47914377bd2246304402207e8e4769e3bdd50cd01c2dd51f839d6001ddb14178ece9a75dcc9f7e73501cbe02200a5d974d49d88a00b3b5fbc9c1b1a7cd2ee19212179154fe1506a618d7b98b2b473045022100b69fc445f725e93cd3ab99e73e00c7a4ae39d7d419dc251ff7500f5563f4a9fe022026e747c324aff902183c26b1a2f076fe3c3174470be30a045cd444b8508b60c746304402200327444b22fe5d2deeb0f1d6c8977ea9757d783ded16ceb6bc4519e7f0baadbf02200f26063a60c6a6e5daafec38df4d03e62cc25c2dcd3f30efed042377c224e10b473045022100ce8992e834fa3c660e9a7190bae2676fac9d2a2f59bbd442c2e6ef647268540f02206ef2c2988795d92cd06c07817268ee4fce697d296a9644f3285ec7b5be79958c46304402202f60bfa078106c477a324b18688e71ccaa9c0f96ac146b17bf2b9aa007c02149022058080ed5ce256000d9f1cdfac908f95c97ad9110fcfa6fbfae517959e395e6ce46304402203a1c35d5e14017085d03745dbe777de0d66b73914c3ee4e9d54df5797e0a506f02206eb9edb92ed1b5623e40bcc4818dc11b5b85d16cc1ca7a39b62a7a5064dbcc0a473045022100fb5bc2a5ef78fd783371057beec835d72116cec65c099e8c922f9a88027a0136022040c427817bd0bfe59749d5a72b8606d9704bd39a971ca400f12291eef5ee264e46304402207cc201e99ff5243d81b71a4408844d1a0d1e53fa2127b6902763a9c50d95a0ed0220077cdf302cc005d5349adab4c479d711532284f475ae0291e676e25fd13e69cd4730450221008b5db9ef00e5fd11c0d8600610558312eeb0deef4a9cc8c03ed29579586a8554022007d9cf97e14e5eb7ebc178c81b04a227128272eb93813c55ea4f3ba0cfae9b32473045022100a1b8faabbad0c14a25fdf884658dc5808005640a8083cc338802ad45a6611f9102207d0cfb4c7ed2ea2878475a711dd57a6f42ebab8a56765024f823bd06d3eaa7cf473045022100cc89d81a385fd7945bc95e5658eb715faf209f244e5f3398d99ffe4f9ce643c002205afe76f4d46d0a3e3359f20d6dbd35e411e5a38bb19c4c0078e6ed76f2d1f95b46304402200764e5e18694353800907f4f84abc8e8b8cb069f3e6b26c826ce113639b2b91d02203f15940a474f1b353b7c279ed964cfb877beb7d761e52781025e8048ea2d1d60473045022100f6512845b8dc207a3bae030f51df69e2867bb3417a2b12ce6246c07118bd853d02205317ea91e78a0689af1633e75d581589d83588b35abab034697d981cd16a8240473045022100f1ddae4e26d399e6e73193b91e8e11d2b1a706368a216081cc2e0087475565cd02203afdaab247c766cdf1c0c6883b23c2e5db66db4df2aa1b3ecc925c389a8212b64630440220303277460991a5050961837dbbd9c3c1855b7f6733da56af9855f916bd3f64c802201cbef836fd69ca80eec58b62ef0d8cf57d270948cec66f67addc312139388a7a4ccf552103089014ded106cdde33483fd1a361a76de8129d8f200c71242e3dd0fda6cf8f2f210206d8d1f2624f621c3f30b73e3e07de771e665d8edae3426b6f7e2ef1e7061e892103675d0b5afb0ce9b558ed1177efcf5782ba4b055051f8da27218e709b322adb9721021db9cc3065dc738b6bdda3822b3a61b837a1091d629d275f229e711eb45af07e210319b74d8acf6ef64528326ff6fc31baeba4c8631908a757a831a82bfdf696f0fa2103889e2c0381943efee6cd20f5e2078edd918eb7b0778a9499f34e42e21f3465e656ae15aed42f0972d0194b64c2518223210223af4811bbcd4d5982af6960e97e6432500bbf915c038c205e867e1259b02bfaac2702c59e02495735fd8b02011321026bcbf69a06230b202010e1abf7fc5bcbc892a443142f76e349494615ebb33076210280919cb6dbfaf0211f0929c0c3a0272c4c06fa8cf495f532d32d78af8fa2f229210378a0ea90f4a52b12b454ff860e2321e8b24464b2169c468a3e51fa3781751f752103b372ab36fa0fd9d659b3dfe3ad0f7938471dd39c63e10808e09a918b11f5cb66210222fd1005ca1daa87c93fe031a19c99ce4c6b9d3fe4991ac123ca5104ab9372fc2103c9b566ff968c86e6f437064387ba4f8370822ec8fd12967c4113926058e75ffb21026eea3437217135f10def85a957649762687089de77491fdfe1a65a4776326aeb2102a5c88df754e4a19d3af5ac92c99351ae4997c4c5d2733fbde33b2535929d38da2102b03dc2fec3fd28266de13c1b28f656282ff4befa0ee13217dd7bb050a9d9bdbc2103280cfdf0a2842d701395f7194b8a1e32b26b5c73e19657145c7861ffbcbf295021025792fe84ec7f4513e0bc57ba5fc0e46473636f467b0d36832b127845c7482f102102cfeb11d170db132d7491a5d2b3a4916d876bc38199ff47933c3f79d1c89110a2210330410ef6756077904e93bc47ef9964a49890ce29984ed3bf4917dac8fd115da02102e0545f7570469f6784fd934712d5be11226546f7a90be00dddebda83143edc8c2103bc91bfbdfb3b87d9f0759b87404bc984f993aea336807dfbf068f7b7043c7270210347cd4a2f28d83ac8945681006ecd16cb9965ddecbbb96a904648d780d852e50a21023efdb63b827dc0559809975a9ee9caabc2e9022b7324ea0208e433065b7fca4e2102382a86cbdd671fa020ca862bf2bc6c3cb8efa39293826f9327083b70f1657c0521027cc4a3f9271f4c653d9a70ec515150f8ec4d5d97abbe83976b2ac983db8f66e60113ae0298e13d42d9db8cfd79015421037ea59ca9d2ca9add12daa79ac092e39d158048dad303f642bec393c9444f647c2102c433d0a85444e6bce649c8daa8bb010535114ddfec722e5c110d99bb307d7db5210268ece74697769d7f87d3080cd9b6c8031b4c5b82cc47cbb3fcd84d1e2d8f24c021029e78f394ef243ec50572db6b4f40a9e76d6dbad7f6b3a54d04bba420302633c22103487bb90849358eddd3c64e6db5c07a9898f3d9f7a6fe07c62f277abb228f1a3f2103d07e54d9ca3a76a7f857f466c0cb7e5c04df0d83ebcedf879a4d50238ab52e4721039dac049f9bfe92384e7b892ceaf5c0b88b42c1eec171152324ba536a2d84a5bc2102d1d112e97afe393b16ab4d9e5393e5efcc9b06bc5a683b5ac35e618dd64f77c22102d603983c29b305ebc30b4583658e5aaf13536ee7f31c96464ec7a8e6e4a1371d210274a2b7bda8e18d8965f626bf18e321f4ef595b6a28e32815d639d85e91c79c02210366f5694e036e60479587fb0122f4eee6e090470cd4216a844e11a632a6a3a7295baea46f26a20b559c07000efc21d48136770efddf01512103453ba9ea78543ccd0fa820cc7d6c86e5bdc4769c77450696048950b80433dd482102e3500407b5c882b5495c9ed43e2bc0729bac27724db3c7400854dad3183c78c42103a609c6a2b7ad43a310e30a5ce474d275325c587e586db55c43a9afeca4f68ab42102f6b6ffc821f32da645a31c7f86c1588f93bbe17634ed33c658ae459c7c174aec2103892c681ab3d26a4b0695faf43b5dd5f7163cb1e315152e9a735a62add4a84e022103581b752ef869ba3d9cf96001ff9c1ad5178e2f595f1c4681404b9f0217a96f2a21020041a12f5ef5f7238dbea789cd27e04d00b394a40c80506dce977a3660dceb8b2103ffeddcb98ceaa3977ff2548d74ccf9f15df32687f30c145bddfb0d62639fd10b210299aaf75b3b81a8989b72e9098d2f4dc26ac1ff960fd60c3f2628ad717d9cf9332103729c8af8e33f7429ba0d4607968678c7220410692270e7dcd1d7d5aa74560d6e210327a2a6b401740ff6a2add2b350193b22481b521d9cfed6a9fe73c1731670601f21022a3718f7d6027ceb9345a18971cf03f3234101d9cb2b8d950791e9e9f0f9f1f1210374b1b72fa9d29aace7b4b23540d279c4a6570cf41a9a208cd401f6ebc8a3d73f2102750ec475a34a12252b898972fe7ba59d90a036e6c760ef5a26cf883830683c945eae18623342a0ee6b8917a9141dc0a30ebf54ee41686147fb878b8ad83b288df5871cc2702e5c2925420010e1fee0b82f856117a91464f5c6846ef8672bf88fed779612ec0ec7d227cc87cdb001c654de590dfd9b015c2102d6469ac090e7ab0ac04bcb3cf97b9987ab4fc41ecdeb61feef13cae3d9fba6de2102b1280008615f651c4c18379c6e97a1c79861c7e8fa4c6796799bbc40458bba8c2103329ee3d3ecfe908bc64912324ffd6a230d26236712fb57d797538cfc35a52ddd2102ec72cfab6d622a9760ec63e4949aae324af584b7fe83324a4f5c6a4c5972ab0c2103d887e78149502fa74c46c8be462e9bdc8f82672b0de44902c68ba4f67495f96721029d2c2593e9c6521d5087beca492d955caec54233f4923be251f4d9b4e3c853de210268273d4fb018ba275a64e8c03e6f9cebf8ab142fdf53e3eb05ebd507e7f0269621021806fc4679d703e34af058cdf0dd9b7900a0f4ff23465d87b6e17d065438c13e2103e6b4804ae5862804a1f7bd632f5216e7cc724fd2c1b9f27cfaf38730a466964c2103ab5860ae2414cc6520ef1b7dadf7c1e3aff10e1a9a22a8b86a3367deb7f3452d210338b8c592406ac25735ac3d2208eedba2ebaa1e5845bb5531cd97d3954e666ecd2103be6121f4822d9c24d2c86b4bcd1a2e3e2e368716e29bf7a0e044c76e291ea49b5cae3d5cc2c223b54d7f040000000000000000000000000000000000000000000000000000000000000000ffffffff6a473045022100a4fcfbfade4c41c6fcd6e41df15f10045e32f4656258764ab8f805e89d9d43e202206d72cb9c442b61d0a7f27755916dcb893507187372629b1a08ab9c3dc150c1f7210299ac5dc6aaa801175a96809f2eb7a3bc9c8a5b93f71a001196beecfefb8ab274ffffffff2e8385f0c1a0613e5a2af5a50d12712159693487163b0b967f71a76fee56d10ff08a95b54746304402206c2c6128952287610dae1f6fdd1ad8ed5f952cca4160a2d2a00f68420697ee590220727b06013962341ec0e8de5f0b12ae672be69c86b848d84f2db195f55a76719e54b1c98c09b8a7ad804c884630178af9433a7881050d5cfd87dcc8788d0cf826ce43e7cbe1ff6afefdb0030047304502210087b68fe27eabfa4f06b90f41fdd15556dc32fe2acba8c11a710a33160992884902206539c4a13e92297087f3d888318e690e73d9dcd2916a161f9f8ce530e0644490473045022100c5cb35d666e0f0cf68704c0fe714d017d2ea2106483e40058005508f21d9b8fe0220303b577dce39de821bfbb6b56854700bb5bb0df5c147a3e0f214e48b59946422473045022100dd7694c431ad48143ef261d163a8221b87cfc6e589d6b42472a8892d10c52d0302204eaefd2c3378fa72412fa27f360d4790d0e50a8f7b1a5d8624959e015c0c0b94463044022037634adc089b295e97fd4aef7cca8017bbe1cb7de10b84ea9fd0edf549f4525002202fb7d941778b651f1a2d66d431cae3384b35f6120afb65d2d790cc0f16602fca463044022009c1ec813322782eceff706c3ec2446d4f56e787bd8c3c477dbc1a0e0cfa45130220343995339be1da738746256ea572837c54911a4dcbf1ff6ffcb93774bb1d967c4d4602562103658cbe412790816a4c2511025c900ab524e6a736c2399ec5efa42826904961a721027c4649c6a7fe582b3eb79347531293154492c83ba061d90b82876ef23c6bdeda210300c6d10cafc175107683332fe275227f4db0af936a2b4e4197c02d541a41cb112103ff51323f74758952288a78268f1cb18c0524e8a4bf1b40b6a8db2ce8a171ebf22102ea54dd70b6f97972d668666d70bbf4be6893d9f807860066261549384f1788bf2103f795ce50e03e47d21f96aafa41755821d575321760e5cdfe4322aa033a2cfe3a21021b10fe742be0dcc40c462bbd5327c616ddf110073a42dfe7b1942105fd5396342103b8c7734f15ed2e2ba3e70c80675b4d12c6b1001cd87056566b659d85668c3b6b2102375886e4e60a175d2869965d01e9e4737e087d16d73181650c727e03ec9b99e421025f023b82d762a5be722fe4c3cf3cd2c955cf67601494612955aee381e22ab0722102aae5ae83e67e3032ca1dfa1607a8259aae2aa909d9b78cf35f0eb2d82ae84b282102dd0e816c6328b2d482ecf7b32bf1803b33e793e2ed6356dafe1825fec8ce414d21021d254f0dd794346d187a92c4d9ca05e32d6554e11670e9498bc8f7b45cd999082102a3aae8af3162abdfc3a27ee7b55bfa67d18ffc85470b94a9376f0d9e62fa7b762102e5897c4c168fc593ff85dcb403f1295209c3ae9f9037f8ef1a95743e05503b8b2103a2912816bcdd549d59463e483cbf842883560f78bd4f579f9023372dba3b4c1221038c0ddeb41df85099a40d12ef8250336e7888bc6aea598caa44faa2e5812c2b6a0111aedfdce45edd4c460c7fc19c3de7519b83bf919c9173ec535c78cd1b0885def1cbe97b28ae184b524e84473045022100a18825a33f15061305a2f36930b813e67fb44a44f5dab784c31c33208d3e611a02202f5c3bcf823188c78f609ac525460f596e08477676165e5643b9848067cf2f47210206cd46c311d7e6238a8dfc78df0a4b43fc529a9c48df791f62fb8c050b320c421976a914b3497ca1071cea7c074f1df25e6f3023e98a6f3f88ac8b974220091d3b2721c70d582d17a914134fda603971e5b53fa6ad3e1a0f4efe386d264387bc0f0aa280e3a7dd2321022f7065d64cfc0ed9e14600b7cf8286868f0a2c74bfd0dc48957cd4d69117c6b1ac64ece0dc326105d800f21f10289e5aa50900459353e342c96fc617a914ac250f0fac101b360b30f60869d21be637bef8c987b83bad62ddc13ef3fd9b01532103140a1ce712cdefd10cbe46677029653cae5289cd0ccd68b4fd40c5ac079be6a921035764aa7f938e29dfe613c80c52427e577aff53f3469cdc3eb78d055e05a89d472103234042f2c158e9bf71e32db30aba5e2e0b44981ee42e7f0d79c800c00cb4b57421024636c3b3fc5e95a7c575fe001b868b3e4acc93161e67acf28272fdca2b4ddf372103f8833ee5bec14579d23bd987408b9f2c0e67f9188bca483ce814852c06f2b7452103b6c3bfe5bf1a3d0af3494f917bf8c134a0b76e56dcc34d6b56df5f6052fbc4092103b5d0c6f8835171e2cfe9a5d9c3aa4a300b74ce217b10a5522cf23c106bc201eb2103d06eb0806b3a15686c16eef0f06296f5bd7ca38162de3ef303487effe7b5447621025f834a5f1a7811464cd87a129866cb04560458a5a6ff0f29e99b14fa856c9795210246ea1eb112477b8bd702a8abe1ccd9b1dfd2790ed42a57fa6544bcece1b5d32221035163c243f7bcb8e8036f2b2296994057feafed60e140baf10cc1280c52efd3812102f2ce1f1180dcf44490b74f2a8d9af6e96b11321c9586cb674f3adcb7bccd48fc5cae102dcb7ca5c42b351976a91413a5d7d8aa82aa0b3077db3f9b7bb628e222ac0788ac8ba5a74c5fcb966417a914968ed5ddd83d344f340d5736c76ab94ddebc84d387860d9fb0b0a9a15500a3fe04c9" + ) val txMatches = Seq( DoubleSha256Digest( - "7e7f11df739ad846b757b8b7f20fc2c9e1311284b3c209b855830ae9ae204b49"), + "7e7f11df739ad846b757b8b7f20fc2c9e1311284b3c209b855830ae9ae204b49" + ), DoubleSha256Digest( - "6605d7be8e606e64ad9e4ac6eed7c515f4f543c8bd8d09f09d255fbf7bf48f2d") + "6605d7be8e606e64ad9e4ac6eed7c515f4f543c8bd8d09f09d255fbf7bf48f2d" + ) ) val merkleBlock = MerkleBlock(block, txMatches) @@ -357,22 +443,26 @@ class MerkleBlockTests extends BitcoinSUnitTest { val initialFilter = BloomFilter(6, 0.00001, UInt32.zero, BloomUpdateAll) val txMatches = List( DoubleSha256Digest( - "266aeeb4e2b8e6646218c5027480170ae68d19cc74bc2381aa0595ded52b0d14"), + "266aeeb4e2b8e6646218c5027480170ae68d19cc74bc2381aa0595ded52b0d14" + ), DoubleSha256Digest( - "92461b83e7601e4b912815b3fd4b112f1b2e357e88b273e95caeb4f20ebba4af"), + "92461b83e7601e4b912815b3fd4b112f1b2e357e88b273e95caeb4f20ebba4af" + ), DoubleSha256Digest( - "bc0481052ae0efa952b6e37c115766b6bae2efebd236e1bbbdfaf025dab02d16") + "bc0481052ae0efa952b6e37c115766b6bae2efebd236e1bbbdfaf025dab02d16" + ) ) val filterWithTxIdsInserted = initialFilter.insertByteVectors(txMatches.map(_.bytes)) val block = Block( - "887c8f96315ee6920acc3dfe8edeacf825228a89e1d49da0f08ee5f7c96f8abf2b37a74d829f107c92c51221514c6bac2cb38dae00fde41d6ec9bcceffd3ee6de1c4a3dd24e4b653f2946453e480f5d904a990495c065e2c3e5aed041398a52e41faad8a0587b75d5f4ec7990456a18ee17f4d8e0af6145b18d700398d224c0000000000000000000000000000000000000000000000000000000000000000ffffffff48473045022100be2e9aeba58510af05a4167f5d76bb2cc6ed106c9ea96519e5342c394952f74402200be2089c7693e4bc73b6e7dae848096d72b5a675636a4cd0717e6658080fe383ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff6b463044022012e57cdec8b83326cd88ebf1e5389a033516d048f22392707f9565667eeb7f25022030554902e2e7501f9f3773dc794b3e964d58a30bed0ba95f23890af1807fd095232102afee4c42dd10b8472403c85d8940a2c80c96d3316ec04c9981137c732bc8380cacffffffffb6b5f8b7b06c8695278e18f589f7aab568f0227de0c8c72eddf578543d541feb21210aa76c473045022100d01f639e630c74a058174e223bda485c6dd771664e5330358ddc858c9a3f200902202ca3017624b36928677bd66e0241f3a95e6dbba58571c5c2ca78507b5803d7f72321020a60750372456735b75b890025d1d62bcfe92f187c073f0cd6cabd358efe131fac39fde36fab34f924dfc3d637c1e1eb1127a9bbd5cac02262197e5511707ea0c2b729c2f136c821a900a3783cac1e4bb48bedfd31d883eed5763be4501d0dc6c79f8c65c4eafb92cb70d43ce3236888da07fdd30600473045022100c4007b453ba6300877bfeddff917b9339c36bb65805a08fe524b37b01c03068b0220554523357d993ff94a1d6dad4f7704c017c365d1ae3c2e206be7c9f5276d31c2473045022100eb7dad7c329428b3c7a554b45443eb3acd298362546bddc5e2417edb9e895c20022078e6b8a97bfbafdcf30914f576aa523991f924c70368ec1e2facd61fac35e4ea463044022075e2144b07f4db93287b439ba080ed71bcfcbf391d2da71888217a469dac9cfc022050e2e6c674433df799b69930279e99b9b18cc01545fa63753918953ca54c18e1473045022100ec7d53d0dc89fe30885349300b99b7eb1cf15830ed811a196e80b5eb8e3c30710220415f5b9370d7a8fa516eb3b7f213b863a92b0b737b243245b23a878df7bb95f8473045022100f29c0274997ebad5a652e3059d1a54e8a3f4157188d1fca1726310148e10621802201e6f5510af7097606914443900ce5685e172caa42d176166e1766c6a3744a06d473045022100eb11155333f6864bed6de7827ede99fd471ba30907130b0a3cdd4ace9f67ae740220142a21ef47283813e6555602fd06ef8c5cbfeb9833f42bc04e50754eaa4849a6473045022100d117607d2be1a000b543d6806f7f6b32b397828c7b305c024206ac98a3ff362d02205770c11d73ebeeb8f8e108a61fcb5893d15c271b86dce5ad1011fa938168e628473045022100d637b961fde0bcfcf0c29cdfe5df86b4f6365e5d0f3455fe1b83e58b7e21e218022059fc437cfc402382bbbb803a251a5dc3770c12de56c600a68722a3b0eeca21d14730450221009629540995c916d05b3188c299c0708a60cdee0c0c71cf7b0388940e79288ac402202c689be5c26d1bb042c178f98dbed8662047431d9b2b6e5b72d7f38ad5d366ee473045022100fbfa297685af28fe931f6d7092c56938b6b1b1026e3cbf8609be302da135be0b022068e8612193589491e4b712cc36f2246782926812d8bd6d8bd5fdb99e34756ae64730450221009657c1ed74c3faf6c2806697243e0b2ffefccbf70d93949f141a30c82934b1590220515b94a0d5a756013ba06878c5e25d1a725d842a43a07681961dc77ad9f8267446304402201ed2016b2268b055782c54552b960c0b5f2840b2f83642a77708d2b7910a47ac02201396bd8fb783f1a8cdea0c1ae7773d18539b5fff997dbfbb7fe15ac068a7bd5b46304402205a1969479cf140639e1bc9fb1b71f7090746726c30d1bc46b34394877c2879fb02205cfaf07faf38961b11eb1d31d5f147eac3d2f7ca6436f891a4532446b5a05bf34630440220117d93355b117de897078cb366f289b3699508093f1ca335f613ca4a9f0fd93f0220014ad36491b03174af20e30244549afcef57fdb65a7f144d272b519349a5ab9946304402206812359a0511e12a8f2a04c43fa258f67979a7cad7ed19f18157aad2205b280402205abee40733664e3a7455d2928be119e991eef9244816b88159b10ab5424e9710473045022100c0b3dcf69485996c131ca2749cee700825e24c075bf17a4825d3c3f074eb3b7b02200f283abf1de6394a920bbf7f6419207ad5c1573989013e02094b2de2320482ac473045022100de4d5ce21bd172504d0fe85485be46eb96a290c4001ee5efa982fa374ef8bb170220580e8e21d755208bd7110bd0e432767b3fdb117d6a2c085b2ba4871a1db8a051473045022100a0b9f8e0fa8fab2fa448568a75aa639c70907e192d10b399c3da17c7ebf05bae02205dc7ba7932125c9c0b61480562c167e222b772bafe6c21c9a1b963278b44f2e6463044022027029b091dcfd9a560f2718c251785ad1cb470f1f89b30e2abf86576d81c1aa502203b49f1b9834bc9317ed5c1e804ff9f71c5f0081ae4bd4265fd27165c6be25015473045022100c7f6674704de5c8d3845763180d39980b3a353fecc7f588aceffef5c1429408902204e4811985f97f5de781221f6a27902ab150796042cca01127d92494716e0b6f44d350100210355f201c2b5abf78b834df937aa1ae761cf7adf2da9743b0280e20ca8f0327cf32103dfcba703b2b1655ea9cdc2868f1d7d4cbae336b0e5989c374c045fc10936a4ca2103ab68d3f403ede3e8a20902a81019702f6a3795f2c98d65e8a40d72c4b2c83d7c21038c69da913f1abeb3b533aba694fde358dffc0d832a8eee6488bc09008785798921025dd18ec3ee31a9ca98bfa96dd9cbe8f6a0dc4dbf71e70a2ec3c74dbc85e4175a2103c7b7bfb705ac7d37ece1e6aaf439b0d2e50f168170030320dd91669e1c6dcfc32103456c2b89921e8939641594e3bd1ffa06b3a6eee51c43cf298733814880791fe121030af71b0e6d0a78c1bf72c71c2a94fac7235060ff3271edbf06a9e1fbe1a0a5d92103e2898272229b5cb84eabd9282f54479a2335258056001eec7d60a7e18791d98d59aeda554df207f3b1fe186616cbe117a914ac5003eef3644d50a72a0fa9c47a9d742e401f8d87e9614799ad8ae6e81976a9148fa73febc2527239fb638299a16bc34020ce482b88ac8ab0492fb98a5f4b1976a9147604735aa700f59d8499fc0691e7efa72855358b88acca279f9fbe04ab1bfd7901572102848a13f904eb9e5817fe12f00826a3487a08f5de484f0b0c9ddf6359987d49372103cb7ceb20fc71f85301b544fc570db072abefc90ccc126473c5eecf9a07e3282d21021393025609afc502a11197e4a78cda287aabebcc8e6907600c713b6493691be121024b3dd5f6e9eafa6b940fd5ed20ed32b66d039a9cac3936854442d38f21ea71222103304b87633e34123f7b6adc9b17561ba4fc0095a1f56074990d24244b2d0f8456210203556cc22fd170496a49796f4348c6c9d5ca4633b254a056f46a0340d800a148210272b644c5bf2671b89d371b783e2fe59e216e9e64b7641a348493cef4e539e1282103cdaf3ccd60795bffec2336996b127b8c3f726787df0ecee91f44deef1faac0e42102c6b657dff2a196b54407ebb0be6c718d1fa7e49011c62b569ee14dfd7030fe3f2103c8796aa3de63704b137ffd70eb67aac50783c072895f47c43f564e7d5a63a35f2102dfb4f6b5ce6a2e60cbd7f61f85d592067c29c3c0f720755ba107a0c92e6bb1535baeaaaf7283d75c5d1117a91418cfed2544dfc440a1c8dbe01912476481853437877388d8574b6373f02321035752321b67acec5619916f22e8aca3a064cc53ae6b479677f3af55c465556250ac1894827104d0939b232103ae0367f34ca494b8a455b9cbbc2987b2902514bb3928eb6459e6b8545234c202ac1b859e789bbb85da0219cb4fab5ac288852ecb663318f209899c095d07db0a824a819b11b9ea8973892267fe3969463044022026e659e0dffaa15c9138ed0d5a0f8183c2b39c5efe1cbe8ae457725c07b7cffc02200619d4ca8085634a2f8e14aafc0bc3912371cc9d92eb14bad0a0b07092219fe82102dec995876cbe0e2aa63d9918c6efef2c82be99543f2e507348e4c54b433bd78acb67c35fcaeb0c5815bd7f5e7749d279d5c8dbf2058d470fd3f145c7fe65803510b2155306ac32b248473045022100ea49564a0a611425c867fe50be7d5e52a81476b08b2df8cf212161eb2abfa20a02203bc5c879c52f79826f671c4b4afa8b045467fd7ac99b0a2d4a076e9f3e33ed86c364110f0269d6f5bbb7ad6a3a1976a914d2c7bee052151a6ac7abc8ef2ae3473e23ee32d288ac14d158735771863c47002102a5efde88a25351b29a0f298deff0787741f2e5e6cec7b530675a55307912599d21036f3db04fc7f9470513c1f4f3847955321c9a1ea9569a20217976668a6c69ee8e52ae9e81e0e84eadab21045501b4d66a2b88b91f6bbe4cb4630d3996d50b03fa90dd119ee45dbea2ddcf635d91b2a8009713e25072558da4ec072266dde652286160eac74f670d94a68e83ca190d2ab38ec9c9ca2898b3b348473045022100a406265c19c9d1f41244c1367b9691719eea9d9d7b00fdb9900de75ea6530fe702204a85cb59da30bc663c99bc984f127364b1c4e0669af8205b144e373a7f789309214a20d75df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c94569d8dc1760054d64086b676355bad83d3281ced0346650e25902120fbed01c0acbbd2afeb6e3cccc0ea326f6f220067f9d984089afcbecd9bc01e288b00210285ee2696c0b33d96f533d1ca0e53322e0d9ee4d42978bee55ec939e75e0ea98521022833f49a724937f0fee99e2d67f44f0aa78c90fcd835d0fa28918299af37b78f21032e157a22bd26b8cb2f5fd0f591775b7d288c84fda388229161e119be13607e7021036b6c8e2af0ead63c9417f101ef33b50d921bfcce82ec0e902abf8cdd54b8511154aeec6eba886e4f221247002103bdbc5b680f046d08c7109c32acb2fe600584f3aad29ddf9b0bd91dfe1ffbda7d2102add04cd10c97b2643d91198dec636886fe71e564eeaa3d227b420cbe9aff23b452ae4fbace44b2b9958b1976a9148b80bb21ec40dd72d1a9d7c7c016d06226d5112b88ac729199551e0f13cbfd57015321035c9d266b3d9fa493e8b65e2731a290267832d52b1a2e6945f2a0ad27f1b1d0c52102b3008a496a2b53d3a443f986754ed685ce84812fef072faeeef6c5af19fbf2ce21031d26837805c45be45394c363c7b68fad46f7db999f2b19dfb5aef0adaf28ee6b210321f9b813c6aa857fc23bda82ca0ffc8d694cedefa50d01799105a20fffc162562103b497a9127eb68cf477188a3104f5b5a9c87d449c0dff435d75cefc3bd7cdf6032103690b70d25af7be2c32241cd790124ca907766c962ef00c9e37c74d3190fb571a2102d90eaf34bdc9f2d9be3f86adc28422e42560e3f1c91f9a1e2137dbddd3c030732103cd6e31d4c46ce39e352974bfc36ce201a379e45421f9aac9ff9f431dceb91c052102a4c7d223d81e6a35e26d5db3e6ded6488c91aca18b234abc23dd31e596a7899c21026b5020bbc7d49d82f9008a665cc31bae04074179750625b680d13d3ca59600835aaebdedeb5d146f3b3c0069b3cf14a03497a32321028c2d3a4708a7a5c40a7e622e3a0dcb8f9480c84c3fa123fca5b2b6e9b7a6fe46ac4ba26fb069bdb608232102169141342d1a65e5f60dcf7b6a96f648c148d1f606dee0c61f94d6a6a920fce1ac063c760a13bfd35f17a914f3d6141c10d328f812df134eee5d472e6097f41f87e0dc16b805e9723105daca73fe427044da780d8c447c70b5d377298ffae7aeaff70c839710ed610640a720750669463044022046eb81d4d8f2762f58c7be81d5174c54bdeb080dd49a1aa8a8ff3eebef6c781a022049387733430abd124788f54bf318243a411c66105777b5e65f49a5a2b349a922210242fbb90fd600030f6393c82c28f28ac7192f1dbe3814cb6e43c40c4af560a93b1f71d6f50000000000000000000000000000000000000000000000000000000000000000ffffffff48473045022100f3f79188992ed1441b5757766d081b98183cf0621e8e7a0fa5b237e6b418da0e022018cc73179be917d65b88daee9599efa33a975c7911c8f5e7cb4eba539e8b8c35ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff4746304402206701c863888b53992e2cae5836d96f436e6bdf7131eff0c376a6d7b864af097b02207adf8007115e2454c9e77ae510d2c75be9f4246d00a59e54cad1e5b2eaf9a75affffffffa78f8a1343fd0974c91e8e5cd32d3e5850cfccfc845ff9bc042ffe0f519d6480396f3d02480046304402203a775aa122d52f5781d72c4e77a07d0fd397b026957cc381ae9ae1e6e9b861f202201c70235c0b5a144d4e713c191430c4cc399d6ebdcf09e4c6db929a75156047752a012626610e2ec0f7bcc0a3da2b22db840fdba3267b3077ca441cc80c3d4dd93927beb8fbcaa0ca6a473045022100be64701085b771327e386bcde17c1b480d0cd5802df1d658df1f0e9d8b057f6002201a5840f2c2b1f24c8d371eeec40c92226c11734045198ab92ef22ce818da3ae52103df30bf86e3bf077d1a8ea85bc8dd9d323ea72ec3fa82bc0f3424dddfe7221f7f14d13a850418e76d149c4db4b21976a914ce7f4b19378b353ea8f75675d2abb8244c812bfc88accf4b5db323d165aa1976a9147683f0855a06dc3b24b035951e0a1c521eff96e688ac34cccd7d958a199817a9148d37c78afd9d80042c4c6aa118aea630efd6ccf187cf1f9692e7037d2f1976a914fb75d625401fb73c211b5301b994ebdd4252da2e88ac6b2c4a14") + "887c8f96315ee6920acc3dfe8edeacf825228a89e1d49da0f08ee5f7c96f8abf2b37a74d829f107c92c51221514c6bac2cb38dae00fde41d6ec9bcceffd3ee6de1c4a3dd24e4b653f2946453e480f5d904a990495c065e2c3e5aed041398a52e41faad8a0587b75d5f4ec7990456a18ee17f4d8e0af6145b18d700398d224c0000000000000000000000000000000000000000000000000000000000000000ffffffff48473045022100be2e9aeba58510af05a4167f5d76bb2cc6ed106c9ea96519e5342c394952f74402200be2089c7693e4bc73b6e7dae848096d72b5a675636a4cd0717e6658080fe383ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff6b463044022012e57cdec8b83326cd88ebf1e5389a033516d048f22392707f9565667eeb7f25022030554902e2e7501f9f3773dc794b3e964d58a30bed0ba95f23890af1807fd095232102afee4c42dd10b8472403c85d8940a2c80c96d3316ec04c9981137c732bc8380cacffffffffb6b5f8b7b06c8695278e18f589f7aab568f0227de0c8c72eddf578543d541feb21210aa76c473045022100d01f639e630c74a058174e223bda485c6dd771664e5330358ddc858c9a3f200902202ca3017624b36928677bd66e0241f3a95e6dbba58571c5c2ca78507b5803d7f72321020a60750372456735b75b890025d1d62bcfe92f187c073f0cd6cabd358efe131fac39fde36fab34f924dfc3d637c1e1eb1127a9bbd5cac02262197e5511707ea0c2b729c2f136c821a900a3783cac1e4bb48bedfd31d883eed5763be4501d0dc6c79f8c65c4eafb92cb70d43ce3236888da07fdd30600473045022100c4007b453ba6300877bfeddff917b9339c36bb65805a08fe524b37b01c03068b0220554523357d993ff94a1d6dad4f7704c017c365d1ae3c2e206be7c9f5276d31c2473045022100eb7dad7c329428b3c7a554b45443eb3acd298362546bddc5e2417edb9e895c20022078e6b8a97bfbafdcf30914f576aa523991f924c70368ec1e2facd61fac35e4ea463044022075e2144b07f4db93287b439ba080ed71bcfcbf391d2da71888217a469dac9cfc022050e2e6c674433df799b69930279e99b9b18cc01545fa63753918953ca54c18e1473045022100ec7d53d0dc89fe30885349300b99b7eb1cf15830ed811a196e80b5eb8e3c30710220415f5b9370d7a8fa516eb3b7f213b863a92b0b737b243245b23a878df7bb95f8473045022100f29c0274997ebad5a652e3059d1a54e8a3f4157188d1fca1726310148e10621802201e6f5510af7097606914443900ce5685e172caa42d176166e1766c6a3744a06d473045022100eb11155333f6864bed6de7827ede99fd471ba30907130b0a3cdd4ace9f67ae740220142a21ef47283813e6555602fd06ef8c5cbfeb9833f42bc04e50754eaa4849a6473045022100d117607d2be1a000b543d6806f7f6b32b397828c7b305c024206ac98a3ff362d02205770c11d73ebeeb8f8e108a61fcb5893d15c271b86dce5ad1011fa938168e628473045022100d637b961fde0bcfcf0c29cdfe5df86b4f6365e5d0f3455fe1b83e58b7e21e218022059fc437cfc402382bbbb803a251a5dc3770c12de56c600a68722a3b0eeca21d14730450221009629540995c916d05b3188c299c0708a60cdee0c0c71cf7b0388940e79288ac402202c689be5c26d1bb042c178f98dbed8662047431d9b2b6e5b72d7f38ad5d366ee473045022100fbfa297685af28fe931f6d7092c56938b6b1b1026e3cbf8609be302da135be0b022068e8612193589491e4b712cc36f2246782926812d8bd6d8bd5fdb99e34756ae64730450221009657c1ed74c3faf6c2806697243e0b2ffefccbf70d93949f141a30c82934b1590220515b94a0d5a756013ba06878c5e25d1a725d842a43a07681961dc77ad9f8267446304402201ed2016b2268b055782c54552b960c0b5f2840b2f83642a77708d2b7910a47ac02201396bd8fb783f1a8cdea0c1ae7773d18539b5fff997dbfbb7fe15ac068a7bd5b46304402205a1969479cf140639e1bc9fb1b71f7090746726c30d1bc46b34394877c2879fb02205cfaf07faf38961b11eb1d31d5f147eac3d2f7ca6436f891a4532446b5a05bf34630440220117d93355b117de897078cb366f289b3699508093f1ca335f613ca4a9f0fd93f0220014ad36491b03174af20e30244549afcef57fdb65a7f144d272b519349a5ab9946304402206812359a0511e12a8f2a04c43fa258f67979a7cad7ed19f18157aad2205b280402205abee40733664e3a7455d2928be119e991eef9244816b88159b10ab5424e9710473045022100c0b3dcf69485996c131ca2749cee700825e24c075bf17a4825d3c3f074eb3b7b02200f283abf1de6394a920bbf7f6419207ad5c1573989013e02094b2de2320482ac473045022100de4d5ce21bd172504d0fe85485be46eb96a290c4001ee5efa982fa374ef8bb170220580e8e21d755208bd7110bd0e432767b3fdb117d6a2c085b2ba4871a1db8a051473045022100a0b9f8e0fa8fab2fa448568a75aa639c70907e192d10b399c3da17c7ebf05bae02205dc7ba7932125c9c0b61480562c167e222b772bafe6c21c9a1b963278b44f2e6463044022027029b091dcfd9a560f2718c251785ad1cb470f1f89b30e2abf86576d81c1aa502203b49f1b9834bc9317ed5c1e804ff9f71c5f0081ae4bd4265fd27165c6be25015473045022100c7f6674704de5c8d3845763180d39980b3a353fecc7f588aceffef5c1429408902204e4811985f97f5de781221f6a27902ab150796042cca01127d92494716e0b6f44d350100210355f201c2b5abf78b834df937aa1ae761cf7adf2da9743b0280e20ca8f0327cf32103dfcba703b2b1655ea9cdc2868f1d7d4cbae336b0e5989c374c045fc10936a4ca2103ab68d3f403ede3e8a20902a81019702f6a3795f2c98d65e8a40d72c4b2c83d7c21038c69da913f1abeb3b533aba694fde358dffc0d832a8eee6488bc09008785798921025dd18ec3ee31a9ca98bfa96dd9cbe8f6a0dc4dbf71e70a2ec3c74dbc85e4175a2103c7b7bfb705ac7d37ece1e6aaf439b0d2e50f168170030320dd91669e1c6dcfc32103456c2b89921e8939641594e3bd1ffa06b3a6eee51c43cf298733814880791fe121030af71b0e6d0a78c1bf72c71c2a94fac7235060ff3271edbf06a9e1fbe1a0a5d92103e2898272229b5cb84eabd9282f54479a2335258056001eec7d60a7e18791d98d59aeda554df207f3b1fe186616cbe117a914ac5003eef3644d50a72a0fa9c47a9d742e401f8d87e9614799ad8ae6e81976a9148fa73febc2527239fb638299a16bc34020ce482b88ac8ab0492fb98a5f4b1976a9147604735aa700f59d8499fc0691e7efa72855358b88acca279f9fbe04ab1bfd7901572102848a13f904eb9e5817fe12f00826a3487a08f5de484f0b0c9ddf6359987d49372103cb7ceb20fc71f85301b544fc570db072abefc90ccc126473c5eecf9a07e3282d21021393025609afc502a11197e4a78cda287aabebcc8e6907600c713b6493691be121024b3dd5f6e9eafa6b940fd5ed20ed32b66d039a9cac3936854442d38f21ea71222103304b87633e34123f7b6adc9b17561ba4fc0095a1f56074990d24244b2d0f8456210203556cc22fd170496a49796f4348c6c9d5ca4633b254a056f46a0340d800a148210272b644c5bf2671b89d371b783e2fe59e216e9e64b7641a348493cef4e539e1282103cdaf3ccd60795bffec2336996b127b8c3f726787df0ecee91f44deef1faac0e42102c6b657dff2a196b54407ebb0be6c718d1fa7e49011c62b569ee14dfd7030fe3f2103c8796aa3de63704b137ffd70eb67aac50783c072895f47c43f564e7d5a63a35f2102dfb4f6b5ce6a2e60cbd7f61f85d592067c29c3c0f720755ba107a0c92e6bb1535baeaaaf7283d75c5d1117a91418cfed2544dfc440a1c8dbe01912476481853437877388d8574b6373f02321035752321b67acec5619916f22e8aca3a064cc53ae6b479677f3af55c465556250ac1894827104d0939b232103ae0367f34ca494b8a455b9cbbc2987b2902514bb3928eb6459e6b8545234c202ac1b859e789bbb85da0219cb4fab5ac288852ecb663318f209899c095d07db0a824a819b11b9ea8973892267fe3969463044022026e659e0dffaa15c9138ed0d5a0f8183c2b39c5efe1cbe8ae457725c07b7cffc02200619d4ca8085634a2f8e14aafc0bc3912371cc9d92eb14bad0a0b07092219fe82102dec995876cbe0e2aa63d9918c6efef2c82be99543f2e507348e4c54b433bd78acb67c35fcaeb0c5815bd7f5e7749d279d5c8dbf2058d470fd3f145c7fe65803510b2155306ac32b248473045022100ea49564a0a611425c867fe50be7d5e52a81476b08b2df8cf212161eb2abfa20a02203bc5c879c52f79826f671c4b4afa8b045467fd7ac99b0a2d4a076e9f3e33ed86c364110f0269d6f5bbb7ad6a3a1976a914d2c7bee052151a6ac7abc8ef2ae3473e23ee32d288ac14d158735771863c47002102a5efde88a25351b29a0f298deff0787741f2e5e6cec7b530675a55307912599d21036f3db04fc7f9470513c1f4f3847955321c9a1ea9569a20217976668a6c69ee8e52ae9e81e0e84eadab21045501b4d66a2b88b91f6bbe4cb4630d3996d50b03fa90dd119ee45dbea2ddcf635d91b2a8009713e25072558da4ec072266dde652286160eac74f670d94a68e83ca190d2ab38ec9c9ca2898b3b348473045022100a406265c19c9d1f41244c1367b9691719eea9d9d7b00fdb9900de75ea6530fe702204a85cb59da30bc663c99bc984f127364b1c4e0669af8205b144e373a7f789309214a20d75df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c94569d8dc1760054d64086b676355bad83d3281ced0346650e25902120fbed01c0acbbd2afeb6e3cccc0ea326f6f220067f9d984089afcbecd9bc01e288b00210285ee2696c0b33d96f533d1ca0e53322e0d9ee4d42978bee55ec939e75e0ea98521022833f49a724937f0fee99e2d67f44f0aa78c90fcd835d0fa28918299af37b78f21032e157a22bd26b8cb2f5fd0f591775b7d288c84fda388229161e119be13607e7021036b6c8e2af0ead63c9417f101ef33b50d921bfcce82ec0e902abf8cdd54b8511154aeec6eba886e4f221247002103bdbc5b680f046d08c7109c32acb2fe600584f3aad29ddf9b0bd91dfe1ffbda7d2102add04cd10c97b2643d91198dec636886fe71e564eeaa3d227b420cbe9aff23b452ae4fbace44b2b9958b1976a9148b80bb21ec40dd72d1a9d7c7c016d06226d5112b88ac729199551e0f13cbfd57015321035c9d266b3d9fa493e8b65e2731a290267832d52b1a2e6945f2a0ad27f1b1d0c52102b3008a496a2b53d3a443f986754ed685ce84812fef072faeeef6c5af19fbf2ce21031d26837805c45be45394c363c7b68fad46f7db999f2b19dfb5aef0adaf28ee6b210321f9b813c6aa857fc23bda82ca0ffc8d694cedefa50d01799105a20fffc162562103b497a9127eb68cf477188a3104f5b5a9c87d449c0dff435d75cefc3bd7cdf6032103690b70d25af7be2c32241cd790124ca907766c962ef00c9e37c74d3190fb571a2102d90eaf34bdc9f2d9be3f86adc28422e42560e3f1c91f9a1e2137dbddd3c030732103cd6e31d4c46ce39e352974bfc36ce201a379e45421f9aac9ff9f431dceb91c052102a4c7d223d81e6a35e26d5db3e6ded6488c91aca18b234abc23dd31e596a7899c21026b5020bbc7d49d82f9008a665cc31bae04074179750625b680d13d3ca59600835aaebdedeb5d146f3b3c0069b3cf14a03497a32321028c2d3a4708a7a5c40a7e622e3a0dcb8f9480c84c3fa123fca5b2b6e9b7a6fe46ac4ba26fb069bdb608232102169141342d1a65e5f60dcf7b6a96f648c148d1f606dee0c61f94d6a6a920fce1ac063c760a13bfd35f17a914f3d6141c10d328f812df134eee5d472e6097f41f87e0dc16b805e9723105daca73fe427044da780d8c447c70b5d377298ffae7aeaff70c839710ed610640a720750669463044022046eb81d4d8f2762f58c7be81d5174c54bdeb080dd49a1aa8a8ff3eebef6c781a022049387733430abd124788f54bf318243a411c66105777b5e65f49a5a2b349a922210242fbb90fd600030f6393c82c28f28ac7192f1dbe3814cb6e43c40c4af560a93b1f71d6f50000000000000000000000000000000000000000000000000000000000000000ffffffff48473045022100f3f79188992ed1441b5757766d081b98183cf0621e8e7a0fa5b237e6b418da0e022018cc73179be917d65b88daee9599efa33a975c7911c8f5e7cb4eba539e8b8c35ffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffff4746304402206701c863888b53992e2cae5836d96f436e6bdf7131eff0c376a6d7b864af097b02207adf8007115e2454c9e77ae510d2c75be9f4246d00a59e54cad1e5b2eaf9a75affffffffa78f8a1343fd0974c91e8e5cd32d3e5850cfccfc845ff9bc042ffe0f519d6480396f3d02480046304402203a775aa122d52f5781d72c4e77a07d0fd397b026957cc381ae9ae1e6e9b861f202201c70235c0b5a144d4e713c191430c4cc399d6ebdcf09e4c6db929a75156047752a012626610e2ec0f7bcc0a3da2b22db840fdba3267b3077ca441cc80c3d4dd93927beb8fbcaa0ca6a473045022100be64701085b771327e386bcde17c1b480d0cd5802df1d658df1f0e9d8b057f6002201a5840f2c2b1f24c8d371eeec40c92226c11734045198ab92ef22ce818da3ae52103df30bf86e3bf077d1a8ea85bc8dd9d323ea72ec3fa82bc0f3424dddfe7221f7f14d13a850418e76d149c4db4b21976a914ce7f4b19378b353ea8f75675d2abb8244c812bfc88accf4b5db323d165aa1976a9147683f0855a06dc3b24b035951e0a1c521eff96e688ac34cccd7d958a199817a9148d37c78afd9d80042c4c6aa118aea630efd6ccf187cf1f9692e7037d2f1976a914fb75d625401fb73c211b5301b994ebdd4252da2e88ac6b2c4a14" + ) val (merkleBlock, _) = MerkleBlock(block, filterWithTxIdsInserted) merkleBlock.partialMerkleTree.extractMatches must be(txMatches) } - //TODO: This is *extremely* slow, this is currently the longest running property we have taking about 6 minutes to run - //I think it is the generator MerkleGenerator.merkleBlockWithInsertTxIds + // TODO: This is *extremely* slow, this is currently the longest running property we have taking about 6 minutes to run + // I think it is the generator MerkleGenerator.merkleBlockWithInsertTxIds it must "contains all inserted txids when we directly create a merkle block from the txids && " + "contains all txids matched by a bloom filter && " + "serialization symmetry" in { @@ -382,7 +472,8 @@ class MerkleBlockTests extends BitcoinSUnitTest { assert( extractedMatches == txIds && extractedMatches.intersect(txIds) == txIds && - MerkleBlock(merkleBlock.hex) == merkleBlock) + MerkleBlock(merkleBlock.hex) == merkleBlock + ) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/PartialMerkleTreeTests.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/PartialMerkleTreeTests.scala index 865f1ebb4e..7aff971398 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/PartialMerkleTreeTests.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/blockchain/PartialMerkleTreeTests.scala @@ -12,7 +12,7 @@ import scodec.bits.BitVector */ class PartialMerkleTreeTests extends BitcoinSUnitTest { "PartialMerkleTree" must "from a list of txs and a bit indicating if the tx matched the filter" in { - //https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L185 + // https://github.com/bitcoin/bitcoin/blob/master/src/test/bloom_tests.cpp#L185 val block = Block( "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb68000000000000052752895" + "58f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010000" + @@ -42,20 +42,25 @@ class PartialMerkleTreeTests extends BitcoinSUnitTest { "014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c7" + "72c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc" + "9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac00000000" + - "0100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000") + "0100000001b4a47603e71b61bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb6042034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000" + ) val hash1 = DoubleSha256Digest( BytesUtil.flipEndianness( - "74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")) + "74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20" + ) + ) val hash2 = DoubleSha256Digest( BytesUtil.flipEndianness( - "dd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")) + "dd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053" + ) + ) - //5ef2374cf1cd1c0b8c1b795950c077fc571cca44866c375a1ed17ace665cfaaa - //d403489f6b1a2f7de72c6e4573e1cc7ac15745518e42a0bf884f58dc48f45533 - //8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221 - //5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd - //201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674 + // 5ef2374cf1cd1c0b8c1b795950c077fc571cca44866c375a1ed17ace665cfaaa + // d403489f6b1a2f7de72c6e4573e1cc7ac15745518e42a0bf884f58dc48f45533 + // 8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221 + // 5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd + // 201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674 val filter = BloomFilter(10, 0.000001, UInt32.zero, BloomUpdateAll) .insert(hash1) @@ -63,61 +68,96 @@ class PartialMerkleTreeTests extends BitcoinSUnitTest { val (merkleBlock, _) = MerkleBlock(block, filter) val partialMerkleTree = merkleBlock.partialMerkleTree partialMerkleTree.bits.slice(0, 8).toIndexedSeq must be( - Seq(true, true, false, true, false, true, false, true)) + Seq(true, true, false, true, false, true, false, true) + ) partialMerkleTree.bits .slice(8, partialMerkleTree.bits.size) .toIndexedSeq must be( - Seq(true, true, true, true, false, false, false, false)) + Seq(true, true, true, true, false, false, false, false) + ) partialMerkleTree.hashes must be( Seq( DoubleSha256Digest( - "5ef2374cf1cd1c0b8c1b795950c077fc571cca44866c375a1ed17ace665cfaaa"), + "5ef2374cf1cd1c0b8c1b795950c077fc571cca44866c375a1ed17ace665cfaaa" + ), DoubleSha256Digest( - "d403489f6b1a2f7de72c6e4573e1cc7ac15745518e42a0bf884f58dc48f45533"), + "d403489f6b1a2f7de72c6e4573e1cc7ac15745518e42a0bf884f58dc48f45533" + ), DoubleSha256Digest( - "8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221"), + "8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221" + ), DoubleSha256Digest( - "5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd"), + "5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd" + ), DoubleSha256Digest( - "201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674") - )) + "201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674" + ) + ) + ) partialMerkleTree.extractMatches must be(Seq(hash2, hash1)) } it must "detect if a node at a given height and position matches a tx that the bloom filter matched" in { - //these values are related to this test case for merkle block inside of core - //https://github.com/bitcoin/bitcoin/blob/f17032f703288d43a76cffe8fa89b87ade9e3074/src/test/bloom_tests.cpp#L185 + // these values are related to this test case for merkle block inside of core + // https://github.com/bitcoin/bitcoin/blob/f17032f703288d43a76cffe8fa89b87ade9e3074/src/test/bloom_tests.cpp#L185 val maxHeight = 4 val matchedTxs = List( - (false, - DoubleSha256Digest( - "a3f3ac605d5e4727f4ea72e9346a5d586f0231460fd52ad9895bc8240d871def")), - (false, - DoubleSha256Digest( - "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")), - (false, - DoubleSha256Digest( - "2ee1e12587e497ada70d9bd10d31e83f0a924825b96cb8d04e8936d793fb60db")), - (false, - DoubleSha256Digest( - "7ad8b910d0c7ba2369bc7f18bb53d80e1869ba2c32274996cebe1ae264bc0e22")), - (false, - DoubleSha256Digest( - "4e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371")), - (false, - DoubleSha256Digest( - "e0c28dbf9f266a8997e1a02ef44af3a1ee48202253d86161d71282d01e5e30fe")), - (false, - DoubleSha256Digest( - "8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221")), - (true, - DoubleSha256Digest( - "5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd")), - (true, - DoubleSha256Digest( - "201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674")) + ( + false, + DoubleSha256Digest( + "a3f3ac605d5e4727f4ea72e9346a5d586f0231460fd52ad9895bc8240d871def" + ) + ), + ( + false, + DoubleSha256Digest( + "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9" + ) + ), + ( + false, + DoubleSha256Digest( + "2ee1e12587e497ada70d9bd10d31e83f0a924825b96cb8d04e8936d793fb60db" + ) + ), + ( + false, + DoubleSha256Digest( + "7ad8b910d0c7ba2369bc7f18bb53d80e1869ba2c32274996cebe1ae264bc0e22" + ) + ), + ( + false, + DoubleSha256Digest( + "4e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371" + ) + ), + ( + false, + DoubleSha256Digest( + "e0c28dbf9f266a8997e1a02ef44af3a1ee48202253d86161d71282d01e5e30fe" + ) + ), + ( + false, + DoubleSha256Digest( + "8719e60a59869e70a7a7a5d4ff6ceb979cd5abe60721d4402aaf365719ebd221" + ) + ), + ( + true, + DoubleSha256Digest( + "5310aedf9c8068f1e862ac9186724f7fdedb0aa9819833af4f4016fca6d21fdd" + ) + ), + ( + true, + DoubleSha256Digest( + "201f4587ec86b58297edc2dd32d6fcd998aa794308aac802a8af3be0e081d674" + ) + ) ) // it must trivially match the merkle root @@ -127,14 +167,14 @@ class PartialMerkleTreeTests extends BitcoinSUnitTest { PartialMerkleTree.matchesTx(maxHeight, 1, 0, matchedTxs) must be(true) PartialMerkleTree.matchesTx(maxHeight, 1, 1, matchedTxs) must be(true) - //it must match the 2nd and 3rd grandchild of the merkle root, and must NOT match the 1st and 4th grand child + // it must match the 2nd and 3rd grandchild of the merkle root, and must NOT match the 1st and 4th grand child PartialMerkleTree.matchesTx(maxHeight, 2, 0, matchedTxs) must be(false) PartialMerkleTree.matchesTx(maxHeight, 2, 1, matchedTxs) must be(true) PartialMerkleTree.matchesTx(maxHeight, 2, 2, matchedTxs) must be(true) PartialMerkleTree.matchesTx(maxHeight, 2, 3, matchedTxs) must be(false) - //it must match the match the 4th and 5th great grand child merkle root, an must NOT match the 1st,2nd,3rd,6th + // it must match the match the 4th and 5th great grand child merkle root, an must NOT match the 1st,2nd,3rd,6th PartialMerkleTree.matchesTx(maxHeight, 3, 0, matchedTxs) must be(false) PartialMerkleTree.matchesTx(maxHeight, 3, 1, matchedTxs) must be(false) PartialMerkleTree.matchesTx(maxHeight, 3, 2, matchedTxs) must be(false) @@ -144,7 +184,7 @@ class PartialMerkleTreeTests extends BitcoinSUnitTest { PartialMerkleTree.matchesTx(maxHeight, 3, 5, matchedTxs) must be(false) - //it must match the the correct leaf nodes (great-great-grand-children), which are indexes 7 and 8 + // it must match the the correct leaf nodes (great-great-grand-children), which are indexes 7 and 8 PartialMerkleTree.matchesTx(maxHeight, 4, 0, matchedTxs) must be(false) PartialMerkleTree.matchesTx(maxHeight, 4, 1, matchedTxs) must be(false) PartialMerkleTree.matchesTx(maxHeight, 4, 2, matchedTxs) must be(false) @@ -161,12 +201,18 @@ class PartialMerkleTreeTests extends BitcoinSUnitTest { it must "match no transactions if we give a list of no transactions" in { val maxHeight = 1 val matchedTxs = Seq( - (false, - DoubleSha256Digest( - "a3f3ac605d5e4727f4ea72e9346a5d586f0231460fd52ad9895bc8240d871def")), - (false, - DoubleSha256Digest( - "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")) + ( + false, + DoubleSha256Digest( + "a3f3ac605d5e4727f4ea72e9346a5d586f0231460fd52ad9895bc8240d871def" + ) + ), + ( + false, + DoubleSha256Digest( + "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9" + ) + ) ) PartialMerkleTree.matchesTx(maxHeight, 0, 0, matchedTxs) must be(false) @@ -176,115 +222,175 @@ class PartialMerkleTreeTests extends BitcoinSUnitTest { it must "build a partial merkle tree with no matches and 1 transaction in the original block" in { val txMatches = Seq( - (false, - DoubleSha256Digest( - "01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552"))) + ( + false, + DoubleSha256Digest( + "01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552" + ) + ) + ) val partialMerkleTree = PartialMerkleTree(txMatches) partialMerkleTree.bits.toIndexedSeq must be( - Seq(false, false, false, false, false, false, false, false)) + Seq(false, false, false, false, false, false, false, false) + ) partialMerkleTree.tree must be( - Leaf(DoubleSha256Digest( - "01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552"))) + Leaf( + DoubleSha256Digest( + "01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552" + ) + ) + ) partialMerkleTree.transactionCount must be(UInt32(1)) partialMerkleTree.extractMatches.isEmpty must be(true) } it must "build a partial merkle tree with 1 match and 2 transactions inside the original block" in { val txMatches = Seq( - (false, - DoubleSha256Digest( - "01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")), - (true, - DoubleSha256Digest( - "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")) + ( + false, + DoubleSha256Digest( + "01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552" + ) + ), + ( + true, + DoubleSha256Digest( + "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9" + ) + ) ) val partialMerkleTree = PartialMerkleTree(txMatches) partialMerkleTree.bits.toIndexedSeq must be( - Seq(true, false, true, false, false, false, false, false)) + Seq(true, false, true, false, false, false, false, false) + ) partialMerkleTree.tree must be( Node( DoubleSha256Digest( - "b130d701e65ac8c65f30dc4b20aabf349036b7c87f11f012f4f3f53f666791e6"), - Leaf(DoubleSha256Digest( - "01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552")), - Leaf(DoubleSha256Digest( - "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9")) - )) + "b130d701e65ac8c65f30dc4b20aabf349036b7c87f11f012f4f3f53f666791e6" + ), + Leaf( + DoubleSha256Digest( + "01272b2b1c8c33a1b4e9ab111db41c9ac275e686fbd9c5d482e586d03e9e0552" + ) + ), + Leaf( + DoubleSha256Digest( + "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9" + ) + ) + ) + ) partialMerkleTree.extractMatches must be( - Seq(DoubleSha256Digest( - "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9"))) + Seq( + DoubleSha256Digest( + "076d0317ee70ee36cf396a9871ab3bf6f8e6d538d7f8a9062437dcb71c75fcf9" + ) + ) + ) } it must "calculate bits correctly for a tree of height 1" in { val matches = List( - (true, - DoubleSha256Digest( - "caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2"))) + ( + true, + DoubleSha256Digest( + "caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2" + ) + ) + ) val partialMerkleTree = PartialMerkleTree(matches) partialMerkleTree.tree must be( - Leaf(DoubleSha256Digest( - "caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2"))) + Leaf( + DoubleSha256Digest( + "caa02f1194fb44dea407a7cf713ddcf30e69f49c297f9275f9236fec42d945b2" + ) + ) + ) partialMerkleTree.bits.toIndexedSeq must be( - Seq(true, false, false, false, false, false, false, false)) + Seq(true, false, false, false, false, false, false, false) + ) } it must "correctly compute a merkle tree that has an odd amount of txids on the merkle tree" in { - //this test is meant to prevent these failures on travis ci - //https://travis-ci.org/bitcoin-s/bitcoin-s-core/builds/205812075#L2774 + // this test is meant to prevent these failures on travis ci + // https://travis-ci.org/bitcoin-s/bitcoin-s-core/builds/205812075#L2774 val hashes: Seq[DoubleSha256Digest] = List( DoubleSha256Digest( - "1563b82f187da1067f5000dabe3a4f4ae8650e207aa163e1d25ded8175e2bae1"), + "1563b82f187da1067f5000dabe3a4f4ae8650e207aa163e1d25ded8175e2bae1" + ), DoubleSha256Digest( - "151cfc67334a38be8abdb5752f2346f8989c33336275d385b5c61af3edfa0a51"), + "151cfc67334a38be8abdb5752f2346f8989c33336275d385b5c61af3edfa0a51" + ), DoubleSha256Digest( - "f3309f2f4697a95be63e61eae9946b9f9e143909faafeec6fdda01284f5192f8"), + "f3309f2f4697a95be63e61eae9946b9f9e143909faafeec6fdda01284f5192f8" + ), DoubleSha256Digest( - "0b38edce452a4ea17b5d76346c9e81ad03e9ecaa887d9a76edeb4da807ce8439"), + "0b38edce452a4ea17b5d76346c9e81ad03e9ecaa887d9a76edeb4da807ce8439" + ), DoubleSha256Digest( - "ae2caf79fc55e3e887ddb39bcd7f8436f0423e1e8f1f37872ee84779ebdf28c1"), + "ae2caf79fc55e3e887ddb39bcd7f8436f0423e1e8f1f37872ee84779ebdf28c1" + ), DoubleSha256Digest( - "4c5db2bdd85cef0a37fe4e675b0c342c9b92df90fabe19c5258aa164bdcfddbc"), + "4c5db2bdd85cef0a37fe4e675b0c342c9b92df90fabe19c5258aa164bdcfddbc" + ), DoubleSha256Digest( - "ec35eda50230cef0b04be44a070b3fcdbf1766f512cd0432f26a34df6249002a"), + "ec35eda50230cef0b04be44a070b3fcdbf1766f512cd0432f26a34df6249002a" + ), DoubleSha256Digest( - "aee82970ace34438dc1d0f3655c62b60c5a28d5754a7d9903706f841fe760dcf"), + "aee82970ace34438dc1d0f3655c62b60c5a28d5754a7d9903706f841fe760dcf" + ), DoubleSha256Digest( - "584a8cd477057c6ddd3f17be8d47e02210e26a48ef77f3a35bd46903d29b47f8"), + "584a8cd477057c6ddd3f17be8d47e02210e26a48ef77f3a35bd46903d29b47f8" + ), DoubleSha256Digest( - "0b55b03bde4e82068f869f4f7f9560fb987f14c15b45b19eff352957ea7a5101"), + "0b55b03bde4e82068f869f4f7f9560fb987f14c15b45b19eff352957ea7a5101" + ), DoubleSha256Digest( - "f185de9349b800e635ec1dfa06fe0be3ae7cd694f2dbaeeff2d39c58dbebcfd2"), + "f185de9349b800e635ec1dfa06fe0be3ae7cd694f2dbaeeff2d39c58dbebcfd2" + ), DoubleSha256Digest( - "023175e3a4f7fa993b45a9ca3604b17835866e6af1aff740fa28bae82b8bc71e"), + "023175e3a4f7fa993b45a9ca3604b17835866e6af1aff740fa28bae82b8bc71e" + ), DoubleSha256Digest( - "be6ce29d3dd0f7f777f188b94a5ae514bd763a5a0ff81055fea090596d3acc0b"), + "be6ce29d3dd0f7f777f188b94a5ae514bd763a5a0ff81055fea090596d3acc0b" + ), DoubleSha256Digest( - "7f1f476304d88a844ff5f5ae2dc0b17e704aa560619fba3753744ca03dea029b"), + "7f1f476304d88a844ff5f5ae2dc0b17e704aa560619fba3753744ca03dea029b" + ), DoubleSha256Digest( - "9d6453d3573dfadbf93532953ef3e63f4731fc9543705af9988bb8038f060e30"), + "9d6453d3573dfadbf93532953ef3e63f4731fc9543705af9988bb8038f060e30" + ), DoubleSha256Digest( - "9d19dd76defcb7bf991ad62e3a468423ddca09ff3181b8f03d57dbc4e25a1596"), + "9d19dd76defcb7bf991ad62e3a468423ddca09ff3181b8f03d57dbc4e25a1596" + ), DoubleSha256Digest( - "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"), + "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456" + ), DoubleSha256Digest( - "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456") + "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456" + ) ) val numTransactions = UInt32(20) val bits = BitVector.bits( List(true, true, true, true, true, true, true, false, true, true, false, - true, true, true, false, true, true, true, true, false, true, true, - true, true, true, true, true, false, true, true, true, true, false, - true, true, true, true, false, false, false)) + true, true, true, false, true, true, true, true, false, true, true, + true, true, true, true, true, false, true, true, true, true, false, + true, true, true, true, false, false, false) + ) val tree = PartialMerkleTree(numTransactions, hashes, bits) - tree.extractMatches.contains(DoubleSha256Digest( - "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456")) must be( - true) + tree.extractMatches.contains( + DoubleSha256Digest( + "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456" + ) + ) must be(true) } it must "be able to extract all of the txids we indicated to be matches" in { forAll(MerkleGenerator.partialMerkleTree) { - case (partialMerkleTree: PartialMerkleTree, - txMatches: Seq[(Boolean, DoubleSha256Digest)]) => + case ( + partialMerkleTree: PartialMerkleTree, + txMatches: Seq[(Boolean, DoubleSha256Digest)] + ) => val matchedTxs = txMatches.filter(_._1).map(_._2) assert(partialMerkleTree.extractMatches == matchedTxs) } @@ -294,9 +400,11 @@ class PartialMerkleTreeTests extends BitcoinSUnitTest { forAll(MerkleGenerator.partialMerkleTree) { case (partialMerkleTree: PartialMerkleTree, _) => val partialMerkleTree2 = - PartialMerkleTree(partialMerkleTree.transactionCount, - partialMerkleTree.hashes, - partialMerkleTree.bits) + PartialMerkleTree( + partialMerkleTree.transactionCount, + partialMerkleTree.hashes, + partialMerkleTree.bits + ) assert(partialMerkleTree2 == partialMerkleTree) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/AdditionTrieNodeTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/AdditionTrieNodeTest.scala index 363f85797f..5131a2c5d5 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/AdditionTrieNodeTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/AdditionTrieNodeTest.scala @@ -13,8 +13,9 @@ class AdditionTrieNodeTest extends BitcoinSUnitTest { val nonces: Int = 10 @tailrec - private def computeAllPrefixes(accum: Vector[Vector[Vector[Int]]] = - Vector.empty): Vector[Vector[Int]] = { + private def computeAllPrefixes( + accum: Vector[Vector[Vector[Int]]] = Vector.empty + ): Vector[Vector[Int]] = { if (accum.length == nonces) { accum.flatten } else { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/CETCalculatorTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/CETCalculatorTest.scala index dc7e04bd39..f1c747b563 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/CETCalculatorTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/CETCalculatorTest.scala @@ -52,11 +52,13 @@ class CETCalculatorTest extends BitcoinSUnitTest { VariablePayoutRange(109, 110) ) - val ranges = CETCalculator.splitIntoRanges(0, - 110, - Satoshis(10000), - func, - RoundingIntervals.noRounding) + val ranges = CETCalculator.splitIntoRanges( + 0, + 110, + Satoshis(10000), + func, + RoundingIntervals.noRounding + ) assert(ranges == expected) } @@ -77,11 +79,13 @@ class CETCalculatorTest extends BitcoinSUnitTest { val expected = Vector(VariablePayoutRange(0, 7)) - val ranges = CETCalculator.splitIntoRanges(0, - 7, - Satoshis(10000), - func, - RoundingIntervals.noRounding) + val ranges = CETCalculator.splitIntoRanges( + 0, + 7, + Satoshis(10000), + func, + RoundingIntervals.noRounding + ) assert(ranges == expected) } @@ -138,8 +142,10 @@ class CETCalculatorTest extends BitcoinSUnitTest { forAll(baseGen) { base => val edgeCase = - CETCalculator.backGroupings(Vector(1, base - 1, base - 1, base - 1), - base) + CETCalculator.backGroupings( + Vector(1, base - 1, base - 1, base - 1), + base + ) assert(edgeCase == Vector(Vector(1))) } } @@ -152,16 +158,19 @@ class CETCalculatorTest extends BitcoinSUnitTest { assert(singleDigitGroupings == Vector.empty) } else { assert( - singleDigitGroupings == (digit1 + 1).until(digit2).map(Vector(_))) + singleDigitGroupings == (digit1 + 1).until(digit2).map(Vector(_)) + ) } } } it should "correctly compute all groupings" in { - val edgeCase = CETCalculator.groupByIgnoringDigits(start = 123, - end = 123, - base = 10, - numDigits = 3) + val edgeCase = CETCalculator.groupByIgnoringDigits( + start = 123, + end = 123, + base = 10, + numDigits = 3 + ) assert(edgeCase == Vector(Vector(1, 2, 3))) val prefix = Vector(0, 1, 2, 0) @@ -179,18 +188,22 @@ class CETCalculatorTest extends BitcoinSUnitTest { Vector(13, 2) ) - val smallGroupings = CETCalculator.groupByIgnoringDigits(start = 171, - end = 210, - base = 16, - numDigits = 2) + val smallGroupings = CETCalculator.groupByIgnoringDigits( + start = 171, + end = 210, + base = 16, + numDigits = 2 + ) assert(smallGroupings == smallExpected) val smallExpectedWithPrefix = smallExpected.map(prefix ++ _) val smallGroupingsWithPrefix = - CETCalculator.groupByIgnoringDigits(start = 73899, - end = 73938, - base = 16, - numDigits = 6) + CETCalculator.groupByIgnoringDigits( + start = 73899, + end = 73938, + base = 16, + numDigits = 6 + ) assert(smallGroupingsWithPrefix == smallExpectedWithPrefix) val expected = Vector( @@ -224,18 +237,22 @@ class CETCalculatorTest extends BitcoinSUnitTest { Vector(4, 3, 2, 1) ) - val groupings = CETCalculator.groupByIgnoringDigits(start = 1234, - end = 4321, - base = 10, - numDigits = 4) + val groupings = CETCalculator.groupByIgnoringDigits( + start = 1234, + end = 4321, + base = 10, + numDigits = 4 + ) assert(groupings == expected) val expectedWithPrefix = expected.map(prefix ++ _) val groupingsWithPrefix = - CETCalculator.groupByIgnoringDigits(start = 1201234, - end = 1204321, - base = 10, - numDigits = 8) + CETCalculator.groupByIgnoringDigits( + start = 1201234, + end = 1204321, + base = 10, + numDigits = 8 + ) assert(groupingsWithPrefix == expectedWithPrefix) } @@ -337,13 +354,15 @@ class CETCalculatorTest extends BitcoinSUnitTest { }.map(o => CETOutcome(o._1, o._2)) val cetOutcomes = - CETCalculator.computeCETs(base = 10, - numDigits = 3, - function = func, - totalCollateral = Satoshis(10000), - rounding = RoundingIntervals.noRounding, - min = 0, - max = 110) + CETCalculator.computeCETs( + base = 10, + numDigits = 3, + function = func, + totalCollateral = Satoshis(10000), + rounding = RoundingIntervals.noRounding, + min = 0, + max = 110 + ) assert(cetOutcomes == expected) } @@ -351,29 +370,37 @@ class CETCalculatorTest extends BitcoinSUnitTest { numDigits: Int, cetDigits: Vector[Int], maxErrorExp: Int, - minFailExp: Int): ( + minFailExp: Int + ): ( Vector[(Vector[Int], Vector[Int])], - Vector[(Vector[Int], Vector[Int])]) = { + Vector[(Vector[Int], Vector[Int])] + ) = { val coveringCETsMax = - CETCalculator.computeCoveringCETsBinary(numDigits = numDigits, - cetDigits = cetDigits, - maxErrorExp = maxErrorExp, - minFailExp = minFailExp, - maximizeCoverage = true, - numOracles = 2) + CETCalculator.computeCoveringCETsBinary( + numDigits = numDigits, + cetDigits = cetDigits, + maxErrorExp = maxErrorExp, + minFailExp = minFailExp, + maximizeCoverage = true, + numOracles = 2 + ) val coveringCETsMin = - CETCalculator.computeCoveringCETsBinary(numDigits = numDigits, - cetDigits = cetDigits, - maxErrorExp = maxErrorExp, - minFailExp = minFailExp, - maximizeCoverage = false, - numOracles = 2) + CETCalculator.computeCoveringCETsBinary( + numDigits = numDigits, + cetDigits = cetDigits, + maxErrorExp = maxErrorExp, + minFailExp = minFailExp, + maximizeCoverage = false, + numOracles = 2 + ) assert(coveringCETsMax.forall(_.length == 2)) assert(coveringCETsMin.forall(_.length == 2)) - (coveringCETsMax.map(ds => (ds.head, ds.last)), - coveringCETsMin.map(ds => (ds.head, ds.last))) + ( + coveringCETsMax.map(ds => (ds.head, ds.last)), + coveringCETsMin.map(ds => (ds.head, ds.last)) + ) } it should "correctly cover small middle CETs" in { @@ -381,10 +408,12 @@ class CETCalculatorTest extends BitcoinSUnitTest { val cet = Vector(0, 0, 1, 0, 1, 1, 0, 0, 1) val (coveringCETsMax, coveringCETsMin) = - computeCoveringCETsMinAndMax(numDigits = 14, - cetDigits = cet, - maxErrorExp = 11, - minFailExp = 7) + computeCoveringCETsMinAndMax( + numDigits = 14, + cetDigits = cet, + maxErrorExp = 11, + minFailExp = 7 + ) assert(coveringCETsMax == Vector((cet, Vector(0, 0, 1)))) assert(coveringCETsMin == Vector((cet, Vector(0, 0, 1, 0, 1)))) @@ -395,16 +424,22 @@ class CETCalculatorTest extends BitcoinSUnitTest { val cet = Vector(0, 1, 0, 0, 0, 0, 0, 1, 1) val (coveringCETsMax, coveringCETsMin) = - computeCoveringCETsMinAndMax(numDigits = 13, - cetDigits = cet, - maxErrorExp = 11, - minFailExp = 7) + computeCoveringCETsMinAndMax( + numDigits = 13, + cetDigits = cet, + maxErrorExp = 11, + minFailExp = 7 + ) assert( - coveringCETsMax == Vector((cet, Vector(0, 1)), (cet, Vector(0, 0, 1)))) + coveringCETsMax == Vector((cet, Vector(0, 1)), (cet, Vector(0, 0, 1))) + ) assert( - coveringCETsMin == Vector((cet, Vector(0, 1, 0, 0, 0)), - (cet, Vector(0, 0, 1, 1, 1, 1)))) + coveringCETsMin == Vector( + (cet, Vector(0, 1, 0, 0, 0)), + (cet, Vector(0, 0, 1, 1, 1, 1)) + ) + ) } it should "correctly cover small right CETs" in { @@ -412,16 +447,22 @@ class CETCalculatorTest extends BitcoinSUnitTest { val cet = Vector(0, 1, 1, 1, 1, 1, 0, 1, 0) val (coveringCETsMax, coveringCETsMin) = - computeCoveringCETsMinAndMax(numDigits = 13, - cetDigits = cet, - maxErrorExp = 11, - minFailExp = 7) + computeCoveringCETsMinAndMax( + numDigits = 13, + cetDigits = cet, + maxErrorExp = 11, + minFailExp = 7 + ) assert( - coveringCETsMax == Vector((cet, Vector(0, 1)), (cet, Vector(1, 0, 0)))) + coveringCETsMax == Vector((cet, Vector(0, 1)), (cet, Vector(1, 0, 0))) + ) assert( - coveringCETsMin == Vector((cet, Vector(0, 1, 1, 1, 1)), - (cet, Vector(1, 0, 0, 0, 0, 0, 0)))) + coveringCETsMin == Vector( + (cet, Vector(0, 1, 1, 1, 1)), + (cet, Vector(1, 0, 0, 0, 0, 0, 0)) + ) + ) } it should "correctly cover max-error sized CETs" in { @@ -429,20 +470,27 @@ class CETCalculatorTest extends BitcoinSUnitTest { val cet = Vector(0, 1) val (coveringCETsMax, coveringCETsMin) = - computeCoveringCETsMinAndMax(numDigits = 13, - cetDigits = cet, - maxErrorExp = 11, - minFailExp = 7) + computeCoveringCETsMinAndMax( + numDigits = 13, + cetDigits = cet, + maxErrorExp = 11, + minFailExp = 7 + ) assert( - coveringCETsMax == Vector((Vector(0, 1, 0), Vector(0, 0, 1)), - (cet, cet), - (Vector(0, 1, 1), Vector(1, 0, 0)))) + coveringCETsMax == Vector( + (Vector(0, 1, 0), Vector(0, 0, 1)), + (cet, cet), + (Vector(0, 1, 1), Vector(1, 0, 0)) + ) + ) assert( coveringCETsMin == Vector( (Vector(0, 1, 0, 0, 0, 0), Vector(0, 0, 1, 1, 1, 1)), (cet, cet), - (Vector(0, 1, 1, 1, 1, 1), Vector(1, 0, 0, 0, 0, 0)))) + (Vector(0, 1, 1, 1, 1, 1), Vector(1, 0, 0, 0, 0, 0)) + ) + ) } it should "correctly cover large CETs" in { @@ -450,20 +498,27 @@ class CETCalculatorTest extends BitcoinSUnitTest { val cet = Vector(0, 0, 1) val (coveringCETsMax, coveringCETsMin) = - computeCoveringCETsMinAndMax(numDigits = 15, - cetDigits = cet, - maxErrorExp = 11, - minFailExp = 7) + computeCoveringCETsMinAndMax( + numDigits = 15, + cetDigits = cet, + maxErrorExp = 11, + minFailExp = 7 + ) assert( - coveringCETsMax == Vector((Vector(0, 0, 1, 0, 0), Vector(0, 0, 0, 1, 1)), - (cet, cet), - (Vector(0, 0, 1, 1, 1), Vector(0, 1, 0, 0, 0)))) + coveringCETsMax == Vector( + (Vector(0, 0, 1, 0, 0), Vector(0, 0, 0, 1, 1)), + (cet, cet), + (Vector(0, 0, 1, 1, 1), Vector(0, 1, 0, 0, 0)) + ) + ) assert( coveringCETsMin == Vector( (Vector(0, 0, 1, 0, 0, 0, 0, 0), Vector(0, 0, 0, 1, 1, 1, 1, 1)), (cet, cet), - (Vector(0, 0, 1, 1, 1, 1, 1, 1), Vector(0, 1, 0, 0, 0, 0, 0, 0)))) + (Vector(0, 0, 1, 1, 1, 1, 1, 1), Vector(0, 1, 0, 0, 0, 0, 0, 0)) + ) + ) } it should "correctly cover small leftmost (0) CETs" in { @@ -471,10 +526,12 @@ class CETCalculatorTest extends BitcoinSUnitTest { val cet = Vector(0, 0, 0, 0, 0, 0, 0) val (coveringCETsMax, coveringCETsMin) = - computeCoveringCETsMinAndMax(numDigits = 13, - cetDigits = cet, - maxErrorExp = 11, - minFailExp = 7) + computeCoveringCETsMinAndMax( + numDigits = 13, + cetDigits = cet, + maxErrorExp = 11, + minFailExp = 7 + ) assert(coveringCETsMax == Vector((cet, Vector(0, 0)))) assert(coveringCETsMin == Vector((cet, Vector(0, 0, 0, 0, 0)))) @@ -485,10 +542,12 @@ class CETCalculatorTest extends BitcoinSUnitTest { val cet = Vector(1, 1, 1, 1, 1, 1, 1, 1) val (coveringCETsMax, coveringCETsMin) = - computeCoveringCETsMinAndMax(numDigits = 13, - cetDigits = cet, - maxErrorExp = 11, - minFailExp = 7) + computeCoveringCETsMinAndMax( + numDigits = 13, + cetDigits = cet, + maxErrorExp = 11, + minFailExp = 7 + ) assert(coveringCETsMax == Vector((cet, Vector(1, 1)))) assert(coveringCETsMin == Vector((cet, Vector(1, 1, 1, 1, 1)))) @@ -498,35 +557,47 @@ class CETCalculatorTest extends BitcoinSUnitTest { val cet = Vector(0, 0) val (coveringCETsMax, coveringCETsMin) = - computeCoveringCETsMinAndMax(numDigits = 13, - cetDigits = cet, - maxErrorExp = 11, - minFailExp = 7) + computeCoveringCETsMinAndMax( + numDigits = 13, + cetDigits = cet, + maxErrorExp = 11, + minFailExp = 7 + ) assert( - coveringCETsMax == Vector((cet, cet), (Vector(0, 0, 1), Vector(0, 1, 0)))) + coveringCETsMax == Vector((cet, cet), (Vector(0, 0, 1), Vector(0, 1, 0))) + ) assert( coveringCETsMin == Vector( (cet, cet), - (Vector(0, 0, 1, 1, 1, 1), Vector(0, 1, 0, 0, 0, 0)))) + (Vector(0, 0, 1, 1, 1, 1), Vector(0, 1, 0, 0, 0, 0)) + ) + ) } it should "correctly cover large rightmost (maxValue) CETs" in { val cet = Vector(1, 1) val (coveringCETsMax, coveringCETsMin) = - computeCoveringCETsMinAndMax(numDigits = 14, - cetDigits = cet, - maxErrorExp = 11, - minFailExp = 7) + computeCoveringCETsMinAndMax( + numDigits = 14, + cetDigits = cet, + maxErrorExp = 11, + minFailExp = 7 + ) assert( - coveringCETsMax == Vector((Vector(1, 1, 0, 0), Vector(1, 0, 1, 1)), - (cet, cet))) + coveringCETsMax == Vector( + (Vector(1, 1, 0, 0), Vector(1, 0, 1, 1)), + (cet, cet) + ) + ) assert( coveringCETsMin == Vector( (Vector(1, 1, 0, 0, 0, 0, 0), Vector(1, 0, 1, 1, 1, 1, 1)), - (cet, cet))) + (cet, cet) + ) + ) } it should "correctly cover a CET with other CETs within bounds" in { @@ -577,8 +648,10 @@ class CETCalculatorTest extends BitcoinSUnitTest { } primaryAndCoveringIntervalsMax.zip(coveringIntervalsMin).foreach { - case (((primaryLeft, primaryRight), (maxCoverLeft, maxCoverRight)), - (minCoverLeft, minCoverRight)) => + case ( + ((primaryLeft, primaryRight), (maxCoverLeft, maxCoverRight)), + (minCoverLeft, minCoverRight) + ) => assert(maxCoverLeft <= minCoverLeft) assert(maxCoverRight >= minCoverRight) @@ -590,7 +663,8 @@ class CETCalculatorTest extends BitcoinSUnitTest { def assertValidCover( coverLeft: Long, coverRight: Long, - maxCoverage: Boolean): Assertion = { + maxCoverage: Boolean + ): Assertion = { if (primaryLeft == coverLeft && primaryRight == coverRight) { succeed } else if (primaryLeft >= coverLeft && primaryRight <= coverRight) { @@ -598,17 +672,21 @@ class CETCalculatorTest extends BitcoinSUnitTest { assert(coverRight - coverLeft + 1 == maxError) } else { val sideToBoundary = - math.max(primaryRight % maxError, - maxError - (primaryLeft % maxError)) + math.max( + primaryRight % maxError, + maxError - (primaryLeft % maxError) + ) assert(coverRight - coverLeft + 1 <= 2 * sideToBoundary) assert(coverRight - coverLeft + 1 >= sideToBoundary) } assert( - primaryLeft - coverLeft >= minFail || coverLeft == 0 || relevantPrimaryCETs.length == 2) + primaryLeft - coverLeft >= minFail || coverLeft == 0 || relevantPrimaryCETs.length == 2 + ) assert(primaryRight - coverLeft < maxError) assert( - coverRight - primaryRight >= minFail || coverRight == maxVal || relevantPrimaryCETs.length == 2) + coverRight - primaryRight >= minFail || coverRight == maxVal || relevantPrimaryCETs.length == 2 + ) assert(coverRight - primaryLeft < maxError) } else { val (mostInner, leastInner, mostOuter) = @@ -652,17 +730,21 @@ class CETCalculatorTest extends BitcoinSUnitTest { assert(maxCoverIntervalRight >= minCoverIntervalRight) assert( - left - maxCoverIntervalLeft >= minFail || maxCoverIntervalLeft == 0) + left - maxCoverIntervalLeft >= minFail || maxCoverIntervalLeft == 0 + ) assert(left - maxCoverIntervalLeft < maxError) assert( - maxCoverIntervalRight - right >= minFail || maxCoverIntervalRight == maxVal) + maxCoverIntervalRight - right >= minFail || maxCoverIntervalRight == maxVal + ) assert(maxCoverIntervalRight - right < maxError) assert( - left - minCoverIntervalLeft >= minFail || minCoverIntervalLeft == 0) + left - minCoverIntervalLeft >= minFail || minCoverIntervalLeft == 0 + ) assert(left - minCoverIntervalLeft < maxError) assert( - minCoverIntervalRight - right >= minFail || minCoverIntervalRight == maxVal) + minCoverIntervalRight - right >= minFail || minCoverIntervalRight == maxVal + ) assert(minCoverIntervalRight - right < maxError) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/ContractDescriptorTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/ContractDescriptorTest.scala index 043cf6ed8f..0adc8dacce 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/ContractDescriptorTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/ContractDescriptorTest.scala @@ -64,7 +64,8 @@ class ContractDescriptorTest extends BitcoinSUnitTest { serializationVersion = DLCSerializationVersion.Beta ) assertThrows[IllegalArgumentException]( - NumericContractDescriptor(func, 2, RoundingIntervals.noRounding)) + NumericContractDescriptor(func, 2, RoundingIntervals.noRounding) + ) } it should "fail for starting above the minimum" in { @@ -76,7 +77,8 @@ class ContractDescriptorTest extends BitcoinSUnitTest { serializationVersion = DLCSerializationVersion.Beta ) assertThrows[IllegalArgumentException]( - NumericContractDescriptor(func, 2, RoundingIntervals.noRounding)) + NumericContractDescriptor(func, 2, RoundingIntervals.noRounding) + ) } it should "fail for ending below the maximum" in { @@ -88,7 +90,8 @@ class ContractDescriptorTest extends BitcoinSUnitTest { serializationVersion = DLCSerializationVersion.Beta ) assertThrows[IllegalArgumentException]( - NumericContractDescriptor(func, 2, RoundingIntervals.noRounding)) + NumericContractDescriptor(func, 2, RoundingIntervals.noRounding) + ) } it should "fail for ending above the maximum" in { @@ -100,30 +103,36 @@ class ContractDescriptorTest extends BitcoinSUnitTest { serializationVersion = DLCSerializationVersion.Beta ) assertThrows[IllegalArgumentException]( - NumericContractDescriptor(func, 2, RoundingIntervals.noRounding)) + NumericContractDescriptor(func, 2, RoundingIntervals.noRounding) + ) } it should "parse a numeric contract descriptor pre 144" in { - //we have to be able to parse old numeric contract descriptors - //pre pr 144 on the DLC spec as we have old wallets deployed with this - //https://github.com/discreetlogcontracts/dlcspecs/pull/144 + // we have to be able to parse old numeric contract descriptors + // pre pr 144 on the DLC spec as we have old wallets deployed with this + // https://github.com/discreetlogcontracts/dlcspecs/pull/144 val func = DLCPayoutCurve.polynomialInterpolate( Vector( - PiecewisePolynomialPoint(outcome = 0, - payout = Satoshis(0), - isEndpoint = true), - PiecewisePolynomialPoint(outcome = 3, - payout = Satoshis(100), - isEndpoint = true) + PiecewisePolynomialPoint( + outcome = 0, + payout = Satoshis(0), + isEndpoint = true + ), + PiecewisePolynomialPoint( + outcome = 3, + payout = Satoshis(100), + isEndpoint = true + ) ), serializationVersion = DLCSerializationVersion.Beta ) val expected = - NumericContractDescriptor(outcomeValueFunc = func, - numDigits = 2, - roundingIntervals = - RoundingIntervals.noRounding) + NumericContractDescriptor( + outcomeValueFunc = func, + numDigits = 2, + roundingIntervals = RoundingIntervals.noRounding + ) val oldHex = "fda720260002fda7261a0002010000000000000000000000010300000000000000640000fda724020000" diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/ContractOraclePairTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/ContractOraclePairTest.scala index 140e96c158..62eef7d447 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/ContractOraclePairTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/ContractOraclePairTest.scala @@ -18,27 +18,34 @@ class ContractOraclePairTest extends BitcoinSUnitTest { it should "not be able to construct an invalid enum contract oracle pair" in { val contractDescriptor = EnumContractDescriptor( Vector("Never", "gonna", "give", "you", "up").map( - EnumOutcome(_) -> Satoshis.zero)) + EnumOutcome(_) -> Satoshis.zero + ) + ) def enumOracleInfo(outcomes: Vector[String]): EnumSingleOracleInfo = { EnumSingleOracleInfo( OracleAnnouncementV0TLV.dummyForEventsAndKeys( ECPrivateKey.freshPrivateKey, ECPrivateKey.freshPrivateKey.schnorrNonce, - outcomes.map(EnumOutcome.apply))) + outcomes.map(EnumOutcome.apply) + ) + ) } val oracleInfo1 = enumOracleInfo(Vector("Never", "gonna", "let", "you", "down")) val oracleInfo2 = enumOracleInfo( - Vector("Never", "gonna", "run", "around", "and", "desert", "you")) + Vector("Never", "gonna", "run", "around", "and", "desert", "you") + ) val oracleInfo3 = enumOracleInfo(Vector("Never", "gonna", "make", "you", "cry")) val multiOracleInfo = EnumMultiOracleInfo( 2, OrderedAnnouncements( - Vector(oracleInfo1, oracleInfo2, oracleInfo3).map(_.announcement))) + Vector(oracleInfo1, oracleInfo2, oracleInfo3).map(_.announcement) + ) + ) assertThrows[IllegalArgumentException]( ContractOraclePair.EnumPair(contractDescriptor, oracleInfo1) @@ -59,9 +66,12 @@ class ContractOraclePairTest extends BitcoinSUnitTest { val contractDescriptor = NumericContractDescriptor( DLCPayoutCurve.polynomialInterpolate( - Vector(PiecewisePolynomialEndpoint(0, 0), - PiecewisePolynomialEndpoint((1L << 7) - 1, 1)), - serializationVersion = DLCSerializationVersion.Beta), + Vector( + PiecewisePolynomialEndpoint(0, 0), + PiecewisePolynomialEndpoint((1L << 7) - 1, 1) + ), + serializationVersion = DLCSerializationVersion.Beta + ), numDigits = 7, RoundingIntervals.noRounding ) @@ -71,8 +81,11 @@ class ContractOraclePairTest extends BitcoinSUnitTest { Vector.fill(numDigits)(ECPrivateKey.freshPrivateKey.schnorrNonce) val sorted = OrderedNonces.fromUnsorted(unsorted) NumericSingleOracleInfo( - OracleAnnouncementV0TLV.dummyForKeys(ECPrivateKey.freshPrivateKey, - sorted)) + OracleAnnouncementV0TLV.dummyForKeys( + ECPrivateKey.freshPrivateKey, + sorted + ) + ) } val oracleInfo1 = numericOracleInfo(1) @@ -81,13 +94,16 @@ class ContractOraclePairTest extends BitcoinSUnitTest { val announcements = OrderedAnnouncements( - Vector(oracleInfo1, oracleInfo2, oracleInfo3).map(_.announcement)) + Vector(oracleInfo1, oracleInfo2, oracleInfo3).map(_.announcement) + ) val multiOracleInfoExact = NumericExactMultiOracleInfo(2, announcements) - val multiOracleInfo = NumericMultiOracleInfo(2, - announcements, - maxErrorExp = 2, - minFailExp = 1, - maximizeCoverage = true) + val multiOracleInfo = NumericMultiOracleInfo( + 2, + announcements, + maxErrorExp = 2, + minFailExp = 1, + maximizeCoverage = true + ) assertThrows[IllegalArgumentException]( ContractOraclePair.NumericPair(contractDescriptor, oracleInfo1) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala index bfafa0e72b..07a5de7534 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCMessageTest.scala @@ -22,16 +22,19 @@ class DLCMessageTest extends BitcoinSJvmTest { it must "not allow a DLCTimeout where the contract times out before it matures" in { assertThrows[IllegalArgumentException]( - DLCTimeouts(BlockHeight(4), BlockHeight(2))) + DLCTimeouts(BlockHeight(4), BlockHeight(2)) + ) assertThrows[IllegalArgumentException]( - DLCTimeouts(BlockTime(UInt32(4)), BlockTime(UInt32(2)))) + DLCTimeouts(BlockTime(UInt32(4)), BlockTime(UInt32(2))) + ) } val dummyPubKey: ECPublicKey = ECPublicKey.freshPublicKey val dummyPubKey2: ECPublicKey = ECPublicKey.freshPublicKey val dummyAddress: BitcoinAddress = BitcoinAddress( - "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa") + "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa" + ) val dummyStr: String = "00000000000000000008bba30d4d0fb53dcbffb601557de9f16d257d4f1985b7" @@ -39,7 +42,8 @@ class DLCMessageTest extends BitcoinSJvmTest { val dummyOracle: EnumSingleOracleInfo = EnumSingleOracleInfo.dummyForKeys( ECPrivateKey.freshPrivateKey, ECPublicKey.freshPublicKey.schnorrNonce, - Vector(EnumOutcome(dummyStr))) + Vector(EnumOutcome(dummyStr)) + ) val dummySig: PartialSignature = PartialSignature(dummyPubKey, DummyECDigitalSignature) @@ -58,7 +62,8 @@ class DLCMessageTest extends BitcoinSJvmTest { fundOutputSerialId = UInt64.max, feeRate = SatoshisPerVirtualByte.one, timeouts = DLCTimeouts(BlockHeight(1), BlockHeight(2)) - )) + ) + ) } it must "not allow same change and fund output serial id for a DLCOffer" in { @@ -75,7 +80,8 @@ class DLCMessageTest extends BitcoinSJvmTest { fundOutputSerialId = UInt64.one, feeRate = SatoshisPerVirtualByte.one, timeouts = DLCTimeouts(BlockHeight(1), BlockHeight(2)) - )) + ) + ) } it must "not allow a negative collateral for a DLCAccept" in { @@ -91,7 +97,10 @@ class DLCMessageTest extends BitcoinSJvmTest { Vector( EnumOracleOutcome( Vector(dummyOracle), - EnumOutcome(dummyStr)).sigPoint -> ECAdaptorSignature.dummy)), + EnumOutcome(dummyStr) + ).sigPoint -> ECAdaptorSignature.dummy + ) + ), dummySig, DLCAccept.NoNegotiationFields, Sha256Digest.empty diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCPayoutCurveTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCPayoutCurveTest.scala index 42c6b889f3..e6f496bf69 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCPayoutCurveTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCPayoutCurveTest.scala @@ -43,8 +43,10 @@ class DLCPayoutCurveTest extends BitcoinSUnitTest { it should "agree on lines and degree 1 polynomials" in { forAll(nPoints(2), Gen.listOfN(1000, numGen)) { - case (Vector(point1: OutcomePayoutPoint, point2: OutcomePayoutPoint), - outcomes) => + case ( + Vector(point1: OutcomePayoutPoint, point2: OutcomePayoutPoint), + outcomes + ) => val line = OutcomePayoutLine(point1, point2) val polyDegOne = OutcomePayoutPolynomial(Vector(point1, point2)) @@ -88,10 +90,14 @@ class DLCPayoutCurveTest extends BitcoinSUnitTest { it should "agree on quadratics and degree 2 polynomials" in { forAll(nPoints(3), Gen.listOfN(1000, numGen)) { - case (Vector(point1: OutcomePayoutPoint, - point2: OutcomePayoutPoint, - point3: OutcomePayoutPoint), - outcomes) => + case ( + Vector( + point1: OutcomePayoutPoint, + point2: OutcomePayoutPoint, + point3: OutcomePayoutPoint + ), + outcomes + ) => val parabola = OutcomePayoutQuadratic(point1, point2, point3) val polyDegTwo = OutcomePayoutPolynomial(Vector(point1, point2, point3)) @@ -165,11 +171,15 @@ class DLCPayoutCurveTest extends BitcoinSUnitTest { it should "agree on cubics and degree 3 polynomials" in { forAll(nPoints(4), Gen.listOfN(1000, numGen)) { - case (Vector(point1: OutcomePayoutPoint, - point2: OutcomePayoutPoint, - point3: OutcomePayoutPoint, - point4: OutcomePayoutPoint), - outcomes) => + case ( + Vector( + point1: OutcomePayoutPoint, + point2: OutcomePayoutPoint, + point3: OutcomePayoutPoint, + point4: OutcomePayoutPoint + ), + outcomes + ) => val cubic = OutcomePayoutCubic(point1, point2, point3, point4) val polyDegThree = OutcomePayoutPolynomial(Vector(point1, point2, point3, point4)) @@ -193,12 +203,14 @@ class DLCPayoutCurveTest extends BitcoinSUnitTest { (nums(0), nums(1), nums(2), nums(3)) } - forAll(intGen, - intGen, - intGen, - intGen, - Gen.listOfN(1000, numGen), - fourNums) { case (a, b, c, d, outcomes, (x1, x2, x3, x4)) => + forAll( + intGen, + intGen, + intGen, + intGen, + Gen.listOfN(1000, numGen), + fourNums + ) { case (a, b, c, d, outcomes, (x1, x2, x3, x4)) => def expectedPayout(outcome: BigDecimal): Satoshis = { val value = a * outcome * outcome * outcome + b * outcome * outcome + c * outcome + d @@ -283,30 +295,33 @@ class DLCPayoutCurveTest extends BitcoinSUnitTest { } it should "agree on hyperbolas and y = d/x + translatePayout" in { - forAll(intGen.suchThat(_ > 0), - intGen, - Gen.listOfN(1000, numGen.suchThat(_ > 0))) { - case (d, translatePayout, outcomes) => - def expectedPayout(outcome: BigDecimal): Satoshis = { - val value = d / outcome + translatePayout - val rounded = value.setScale(0, RoundingMode.FLOOR).toLongExact - Satoshis(rounded) - } + forAll( + intGen.suchThat(_ > 0), + intGen, + Gen.listOfN(1000, numGen.suchThat(_ > 0)) + ) { case (d, translatePayout, outcomes) => + def expectedPayout(outcome: BigDecimal): Satoshis = { + val value = d / outcome + translatePayout + val rounded = value.setScale(0, RoundingMode.FLOOR).toLongExact + Satoshis(rounded) + } - val hyperbola = - DLCHyperbolaPayoutCurvePiece(usePositivePiece = true, - translateOutcome = 0, - translatePayout, - a = 1, - b = 0, - c = 0, - d, - OutcomePayoutPoint(0, 0), - OutcomePayoutPoint(Long.MaxValue, 0)) + val hyperbola = + DLCHyperbolaPayoutCurvePiece( + usePositivePiece = true, + translateOutcome = 0, + translatePayout, + a = 1, + b = 0, + c = 0, + d, + OutcomePayoutPoint(0, 0), + OutcomePayoutPoint(Long.MaxValue, 0) + ) - outcomes.foreach { outcome => - assert(hyperbola(outcome) == expectedPayout(outcome)) - } + outcomes.foreach { outcome => + assert(hyperbola(outcome) == expectedPayout(outcome)) + } } } @@ -315,27 +330,38 @@ class DLCPayoutCurveTest extends BitcoinSUnitTest { val point1 = PiecewisePolynomialEndpoint(10, Satoshis(100)) val line = - DLCPayoutCurve.polynomialInterpolate(Vector(point0, point1), - serializationVersion = - DLCSerializationVersion.Beta) + DLCPayoutCurve.polynomialInterpolate( + Vector(point0, point1), + serializationVersion = DLCSerializationVersion.Beta + ) val lineFunc = line.pieces assert( - lineFunc == Vector(OutcomePayoutLine(point0.toOutcomePayoutPoint, - point1.toOutcomePayoutPoint))) + lineFunc == Vector( + OutcomePayoutLine( + point0.toOutcomePayoutPoint, + point1.toOutcomePayoutPoint + ) + ) + ) val point2 = PiecewisePolynomialMidpoint(20, Satoshis.zero) val point3 = PiecewisePolynomialEndpoint(30, Satoshis(300)) val quad = - DLCPayoutCurve.polynomialInterpolate(Vector(point1, point2, point3), - serializationVersion = - DLCSerializationVersion.Beta) + DLCPayoutCurve.polynomialInterpolate( + Vector(point1, point2, point3), + serializationVersion = DLCSerializationVersion.Beta + ) val quadFunc = quad.pieces assert( quadFunc == Vector( - OutcomePayoutQuadratic(point1.toOutcomePayoutPoint, - point2.toOutcomePayoutPoint, - point3.toOutcomePayoutPoint))) + OutcomePayoutQuadratic( + point1.toOutcomePayoutPoint, + point2.toOutcomePayoutPoint, + point3.toOutcomePayoutPoint + ) + ) + ) val point4 = PiecewisePolynomialMidpoint(40, Satoshis(600)) val point5 = PiecewisePolynomialMidpoint(50, Satoshis(500)) @@ -343,20 +369,26 @@ class DLCPayoutCurveTest extends BitcoinSUnitTest { val cubicPoints = Vector(point3, point4, point5, point6) val cubic = - DLCPayoutCurve.polynomialInterpolate(cubicPoints, - serializationVersion = - DLCSerializationVersion.Beta) + DLCPayoutCurve.polynomialInterpolate( + cubicPoints, + serializationVersion = DLCSerializationVersion.Beta + ) val cubicFunc = cubic.pieces assert( cubicFunc == Vector( - OutcomePayoutCubic(point3.toOutcomePayoutPoint, - point4.toOutcomePayoutPoint, - point5.toOutcomePayoutPoint, - point6.toOutcomePayoutPoint))) + OutcomePayoutCubic( + point3.toOutcomePayoutPoint, + point4.toOutcomePayoutPoint, + point5.toOutcomePayoutPoint, + point6.toOutcomePayoutPoint + ) + ) + ) val func = DLCPayoutCurve.polynomialInterpolate( Vector(point0, point1, point2, point3, point4, point5, point6), - serializationVersion = DLCSerializationVersion.Beta) + serializationVersion = DLCSerializationVersion.Beta + ) val allFuncs = func.pieces assert(allFuncs == lineFunc ++ quadFunc ++ cubicFunc) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCUtilTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCUtilTest.scala index 9e3ff59d81..3bfdf018f1 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCUtilTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/DLCUtilTest.scala @@ -19,10 +19,12 @@ class DLCUtilTest extends BitcoinSUnitTest { "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff020000ffffffff0101000000000000000000000000" val tx = Transaction.fromHex(txHex) val outputIdx = 0 - val tempContractId = Sha256Digest.empty //32 bytes of 0x0000..000 - val contractId = DLCUtil.computeContractId(fundingTx = tx, - outputIdx = outputIdx, - tempContractId = tempContractId) + val tempContractId = Sha256Digest.empty // 32 bytes of 0x0000..000 + val contractId = DLCUtil.computeContractId( + fundingTx = tx, + outputIdx = outputIdx, + tempContractId = tempContractId + ) val expected = "a3f942fe9cd3280f2e9b0e95a6228b4cc48b94f85a7f20129f89d3c3a80f4dd8" @@ -30,7 +32,7 @@ class DLCUtilTest extends BitcoinSUnitTest { } it must "preserve ordering of attestments when parsing them" in { - //see: https://github.com/bitcoin-s/bitcoin-s/issues/4808 + // see: https://github.com/bitcoin-s/bitcoin-s/issues/4808 val announcementHex = "fdd824fd02d455abcf3b585c9729e92e13c9762c4adc9c6062be721ae217a8aac0ff92a73e837231809bf6f6b75192d665b301c0f4011f247bdc00c8752e524d65baeb1c3deb04ba9838623f02c940d20d7b185d410178cff7990c7fcf19186c7f58c7c4b8defdd822fd026e0012218b59ec12cb8b221e00ef6d3b88a19650b3fb99ea3b6d0f9ef8c356741347c16319d4bfa31978500f32876c6adbc18bee655f35dc97fa4824cf0775981542b96e658c9c5d257576db17d454806b6bd366c26bedf1ae358e1715377449b23c39afed7b41274028982c274bd01b799b35db36a6b31c10211dc05fe3cd3b059099361ecb7be6d7351aa516bea56a6100b4c2635da049c6252f94a0e117055314793c550569820e6687fbd5a60e80d7e026bf1d6f6afffd0d0778da023727d5f5b7aae45e2b8848539fe3485bcd64b58556d2a60d10e74e1ec541d5871f012960a669415a50ed291b4d9e50cc695ff0458573acda2881aa00f50fbe48a59f5f518416022bd073bea49df9940cbeb97fcdd2fe13957bc410950d0c9e971d6a6da197e5090d9821785e7b756ec56dc059b65d2fd3fa8f02595cd292ec10c0ca680e36ea89a62deb71fce778e0a603ed345adf03c3bc55e3d85c211aea3a15aee67fabe1e3081736280e3b54037e8ab5211bf9e8e27b61656f597843dc7be6464705e341e2a6b2fa96df10fd569c62d04dd9515cf1cf452e76c4f5147c125e0b5a5a54af141f492423370c9b41bc9259e4d9cc35553252d71fcc0c37c6f025afb1b11503499fa5f6f7dae9378ec1f8f749836e23f40326209194ab2779b6069f74cb562d1fbd83a7c7147549d866c3c71e0dade3e1d74dee457cbd3fcac11be8e71ce6039b3a9b60e3a4c707d725e2e43a456c4cdfe272ac1a63ac0cde984d81469903d9420c2902de121e9104126c89ab589698208926360bf052b84a4cb6504f4da763355080fdd80a100002000642544355534400000000001213446572696269742d4254432d32395345503232" val attestmentHex = @@ -39,7 +41,8 @@ class DLCUtilTest extends BitcoinSUnitTest { val attestment = OracleAttestmentV0TLV.fromHex(attestmentHex) val oracleSigs = DLCUtil.buildOracleSignaturesNaive( announcements = OrderedAnnouncements(Vector(announcement)), - attestments = Vector(attestment)) + attestments = Vector(attestment) + ) val oracleSig = oracleSigs.head assert(oracleSig.sigs == attestment.unsortedSignatures) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/RoundingIntervalsTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/RoundingIntervalsTest.scala index a1289201ac..4ae48d8349 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/RoundingIntervalsTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/dlc/RoundingIntervalsTest.scala @@ -33,7 +33,8 @@ class RoundingIntervalsTest extends BitcoinSUnitTest { IntervalStart(50, 5), IntervalStart(100, 10), IntervalStart(1000, 100) - )) + ) + ) assert(roundingInterval.round(15, Satoshis(12345)) == Satoshis(12345)) @@ -81,7 +82,8 @@ class RoundingIntervalsTest extends BitcoinSUnitTest { IntervalStart(50, 5), IntervalStart(100, 10), IntervalStart(1000, 100) - )) + ) + ) assert(roundingInterval.round(15, Satoshis(-12345)) == Satoshis(-12345)) @@ -136,7 +138,8 @@ class RoundingIntervalsTest extends BitcoinSUnitTest { IntervalStart(14, 3), IntervalStart(15, 7), IntervalStart(16, 1) - )) + ) + ) val roundingIntervals2 = RoundingIntervals( Vector( IntervalStart(1, 2), @@ -145,7 +148,8 @@ class RoundingIntervalsTest extends BitcoinSUnitTest { IntervalStart(5, 2), IntervalStart(6, 3), IntervalStart(11, 5) - )) + ) + ) val expected = RoundingIntervals( Vector( IntervalStart(2, 2), @@ -161,7 +165,8 @@ class RoundingIntervalsTest extends BitcoinSUnitTest { IntervalStart(14, 3), IntervalStart(15, 5), IntervalStart(16, 1) - )) + ) + ) assert(roundingIntervals1.minRoundingWith(roundingIntervals2) == expected) } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnHumanReadablePartTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnHumanReadablePartTest.scala index 22a3cc29cb..e0f068d08c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnHumanReadablePartTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnHumanReadablePartTest.scala @@ -17,13 +17,17 @@ class LnHumanReadablePartTest extends BitcoinSUnitTest { LnHumanReadablePart(SigNet) must be(LnHumanReadablePart(LnBitcoinSigNet)) LnHumanReadablePart(MainNet, mBtc) must be( - LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt)) + LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt) + ) LnHumanReadablePart(TestNet3, mBtc) must be( - LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt)) + LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt) + ) LnHumanReadablePart(RegTest, mBtc) must be( - LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt)) + LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt) + ) LnHumanReadablePart(SigNet, mBtc) must be( - LnHumanReadablePart(LnBitcoinSigNet, mBtcOpt)) + LnHumanReadablePart(LnBitcoinSigNet, mBtcOpt) + ) } it must "correctly serialize the hrp to string" in { @@ -50,22 +54,30 @@ class LnHumanReadablePartTest extends BitcoinSUnitTest { it must "deserialize hrp from string" in { LnHumanReadablePart.fromString("lnbc") must be( - LnHumanReadablePart(LnBitcoinMainNet)) + LnHumanReadablePart(LnBitcoinMainNet) + ) LnHumanReadablePart.fromString("lntb") must be( - LnHumanReadablePart(LnBitcoinTestNet)) + LnHumanReadablePart(LnBitcoinTestNet) + ) LnHumanReadablePart.fromString("lnbcrt") must be( - LnHumanReadablePart(LnBitcoinRegTest)) + LnHumanReadablePart(LnBitcoinRegTest) + ) LnHumanReadablePart.fromString("lntbs") must be( - LnHumanReadablePart(LnBitcoinSigNet)) + LnHumanReadablePart(LnBitcoinSigNet) + ) LnHumanReadablePart.fromString("lnbc1m") must be( - LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt)) + LnHumanReadablePart(LnBitcoinMainNet, mBtcOpt) + ) LnHumanReadablePart.fromString("lntb1m") must be( - LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt)) + LnHumanReadablePart(LnBitcoinTestNet, mBtcOpt) + ) LnHumanReadablePart.fromString("lnbcrt1m") must be( - LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt)) + LnHumanReadablePart(LnBitcoinRegTest, mBtcOpt) + ) LnHumanReadablePart.fromString("lntbs1m") must be( - LnHumanReadablePart(LnBitcoinSigNet, mBtcOpt)) + LnHumanReadablePart(LnBitcoinSigNet, mBtcOpt) + ) } it must "fail to deserialize hrp from invalid string" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceSignatureTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceSignatureTest.scala index 67af5b5cf7..2e95fa6b00 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceSignatureTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceSignatureTest.scala @@ -15,9 +15,11 @@ class LnInvoiceSignatureTest extends BitcoinSUnitTest { it must "have serialization symmetry for raw r,s,recovId" in { forAll(CryptoGenerators.digitalSignature, LnInvoiceGen.signatureVersion) { case (ecSig, recovId) => - val lnSig = LnInvoiceSignature.fromRS(r = ecSig.r.bigInteger, - s = ecSig.s.bigInteger, - recovId = recovId) + val lnSig = LnInvoiceSignature.fromRS( + r = ecSig.r.bigInteger, + s = ecSig.s.bigInteger, + recovId = recovId + ) val serialized = lnSig.hex diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceUnitTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceUnitTest.scala index 88ebef1506..293842d2bb 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceUnitTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/LnInvoiceUnitTest.scala @@ -42,7 +42,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val time = UInt64(1496314658) val paymentHash = Sha256Digest.fromHex( - "0001020304050607080900010203040506070809000102030405060708090102") + "0001020304050607080900010203040506070809000102030405060708090102" + ) val paymentTag = LnTag.PaymentHashTag(paymentHash) val description = { @@ -55,12 +56,14 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val descpriptionHashTag = Right(LnTag.DescriptionHashTag(descriptionHash)) it must "parse BOLT11 example 1" in { - //BOLT11 Example #1 + // BOLT11 Example #1 val descriptionTagE = Left(LnTag.DescriptionTag("Please consider supporting this project")) - val lnTags = LnTaggedFields(paymentHash = paymentTag, - descriptionOrHash = descriptionTagE) + val lnTags = LnTaggedFields( + paymentHash = paymentTag, + descriptionOrHash = descriptionTagE + ) val sigData = "6c6e62630b25fe64410d00004080c1014181c20240004080c1014181c20240004080c1014181c202404081a1fa83632b0b9b29031b7b739b4b232b91039bab83837b93a34b733903a3434b990383937b532b1ba0" @@ -68,7 +71,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { "c3d4e83f646fa79a393d75277b1d858db1d1f7ab7137dcb7835db2ecd518e1c9")*/ val signature = ECDigitalSignature.fromRS( - "38ec6891345e204145be8a3a99de38e98a39d6a569434e1845c8af7205afcfcc7f425fcd1463e93c32881ead0d6e356d467ec8c02553f9aab15e5738b11f127f") + "38ec6891345e204145be8a3a99de38e98a39d6a569434e1845c8af7205afcfcc7f425fcd1463e93c32881ead0d6e356d467ec8c02553f9aab15e5738b11f127f" + ) val version = UInt8.zero val lnSig = LnInvoiceSignature(version, signature) @@ -78,7 +82,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val serialized = invoice.toString serialized must be( - "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w") + "lnbc1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq8rkx3yf5tcsyz3d73gafnh3cax9rn449d9p5uxz9ezhhypd0elx87sjle52x86fux2ypatgddc6k63n7erqz25le42c4u4ecky03ylcqca784w" + ) val deserialized = LnInvoice.fromStringT(serialized) @@ -86,16 +91,19 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { } it must "parse BOLT11 example 2" in { - //BOLT11 Example #2 + // BOLT11 Example #2 val descriptionTagE = Left(LnTag.DescriptionTag("1 cup coffee")) val expiryTimeTag = LnTag.ExpiryTimeTag(UInt32(60)) - val lnTags = LnTaggedFields(paymentTag, - descriptionOrHash = descriptionTagE, - expiryTime = Some(expiryTimeTag)) + val lnTags = LnTaggedFields( + paymentTag, + descriptionOrHash = descriptionTagE, + expiryTime = Some(expiryTimeTag) + ) val signature = ECDigitalSignature.fromRS( - "e89639ba6814e36689d4b91bf125f10351b55da057b00647a8dabaeb8a90c95f160f9d5a6e0f79d1fc2b964238b944e2fa4aa677c6f020d466472ab842bd750e") + "e89639ba6814e36689d4b91bf125f10351b55da057b00647a8dabaeb8a90c95f160f9d5a6e0f79d1fc2b964238b944e2fa4aa677c6f020d466472ab842bd750e" + ) val version = UInt8.one val lnSig = LnInvoiceSignature(version, signature) @@ -104,7 +112,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val serialized = invoice.toString serialized must be( - "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp") + "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaztrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspfj9srp" + ) val deserialized = LnInvoice.fromStringT(serialized) @@ -112,7 +121,7 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { } it must "parse BOLT11 example 3" in { - //BOLT11 Example #3 - Description field does not encode correctly due to Japanese letters + // BOLT11 Example #3 - Description field does not encode correctly due to Japanese letters val descriptionTagE = Left(LnTag.DescriptionTag("ナンセンス 1杯")) val expiryTag = LnTag.ExpiryTimeTag(UInt32(60)) @@ -129,7 +138,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { ) val signature = ECDigitalSignature.fromRS( - "259f04511e7ef2aa77f6ff04d51b4ae9209504843e5ab9672ce32a153681f687515b73ce57ee309db588a10eb8e41b5a2d2bc17144ddf398033faa49ffe95ae6") + "259f04511e7ef2aa77f6ff04d51b4ae9209504843e5ab9672ce32a153681f687515b73ce57ee309db588a10eb8e41b5a2d2bc17144ddf398033faa49ffe95ae6" + ) val version = UInt8.zero val lnSig = LnInvoiceSignature(version, signature) @@ -138,7 +148,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val serialized = invoice.toString invoice.toString must be( - "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny") + "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpquwpc4curk03c9wlrswe78q4eyqc7d8d0xqzpuyk0sg5g70me25alkluzd2x62aysf2pyy8edtjeevuv4p2d5p76r4zkmneet7uvyakky2zr4cusd45tftc9c5fh0nnqpnl2jfll544esqchsrny" + ) val deserialized = LnInvoice.fromStringT(serialized) @@ -146,21 +157,25 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { } it must "parse BOLT11 example 4" in { - //BOLT11 Example #4 + // BOLT11 Example #4 val descriptionHash = Sha256Digest.fromHex( - "3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1") + "3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1" + ) val descriptionHashTagE = Right(LnTag.DescriptionHashTag(descriptionHash)) - val lnTags = LnTaggedFields(paymentHash = paymentTag, - descriptionOrHash = descriptionHashTagE, - None, - None, - None, - None, - None) + val lnTags = LnTaggedFields( + paymentHash = paymentTag, + descriptionOrHash = descriptionHashTagE, + None, + None, + None, + None, + None + ) val signature = ECDigitalSignature.fromRS( - "c63486e81f8c878a105bc9d959af1973854c4dc552c4f0e0e0c7389603d6bdc67707bf6be992a8ce7bf50016bb41d8a9b5358652c4960445a170d049ced4558c") + "c63486e81f8c878a105bc9d959af1973854c4dc552c4f0e0e0c7389603d6bdc67707bf6be992a8ce7bf50016bb41d8a9b5358652c4960445a170d049ced4558c" + ) val version = UInt8.zero val lnSig = LnInvoiceSignature(version, signature) @@ -169,7 +184,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val serialized = invoice.toString invoice.toString must be( - "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7") + "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7" + ) val deserialized = LnInvoice.fromStringT(serialized) @@ -177,20 +193,25 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { } it must "parse BOLT11 example 5" in { - //BOLT11 Example #5 + // BOLT11 Example #5 val descriptionHash = Sha256Digest.fromHex( - "3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1") + "3925b6f67e2c340036ed12093dd44e0368df1b6ea26c53dbe4811f58fd5db8c1" + ) val descriptionHashTagE = Right(LnTag.DescriptionHashTag(descriptionHash)) val fallbackAddr = LnTag.FallbackAddressTag( - P2PKHAddress.fromString("mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP")) + P2PKHAddress.fromString("mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP") + ) - val lnTags = LnTaggedFields(paymentHash = paymentTag, - descriptionOrHash = descriptionHashTagE, - fallbackAddress = Some(fallbackAddr)) + val lnTags = LnTaggedFields( + paymentHash = paymentTag, + descriptionOrHash = descriptionHashTagE, + fallbackAddress = Some(fallbackAddr) + ) val signature = ECDigitalSignature.fromRS( - "b6c42b8a61e0dc5823ea63e76ff148ab5f6c86f45f9722af0069c7934daff70d5e315893300774c897995e3a7476c8193693d144a36e2645a0851e6ebafc9d0a") + "b6c42b8a61e0dc5823ea63e76ff148ab5f6c86f45f9722af0069c7934daff70d5e315893300774c897995e3a7476c8193693d144a36e2645a0851e6ebafc9d0a" + ) val version = UInt8.one val lnSig = LnInvoiceSignature(version, signature) @@ -199,10 +220,11 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val serialized = invoice.toString serialized must be( - "lntb20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3x9et2e20v6pu37c5d9vax37wxq72un98kmzzhznpurw9sgl2v0nklu2g4d0keph5t7tj9tcqd8rexnd07ux4uv2cjvcqwaxgj7v4uwn5wmypjd5n69z2xm3xgksg28nwht7f6zsp2mh7qm") - //In example #5, the order in which tags are encoded in the invoice has been changed to demonstrate the ability to move tags as needed. - //For that reason, the example #5 output we are matching against has been modified to fit the order in which we encode our invoices. - //TODO: Add checksum data to check + "lntb20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3x9et2e20v6pu37c5d9vax37wxq72un98kmzzhznpurw9sgl2v0nklu2g4d0keph5t7tj9tcqd8rexnd07ux4uv2cjvcqwaxgj7v4uwn5wmypjd5n69z2xm3xgksg28nwht7f6zsp2mh7qm" + ) + // In example #5, the order in which tags are encoded in the invoice has been changed to demonstrate the ability to move tags as needed. + // For that reason, the example #5 output we are matching against has been modified to fit the order in which we encode our invoices. + // TODO: Add checksum data to check val deserialized = LnInvoice.fromStringT(serialized) @@ -213,16 +235,19 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { "lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqj9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qqdhhwkj" val fallbackAddr = LnTag.FallbackAddressTag( - P2PKHAddress.fromString("1RustyRX2oai4EYYDpQGWvEL62BBGqN9T")) + P2PKHAddress.fromString("1RustyRX2oai4EYYDpQGWvEL62BBGqN9T") + ) val signature = ECDigitalSignature.fromRS( - "91675cb3fad8e9d915343883a49242e074474e26d42c7ed914655689a8074553733e8e4ea5ce9b85f69e40d755a55014536b12323f8b220600c94ef2b9c51428") + "91675cb3fad8e9d915343883a49242e074474e26d42c7ed914655689a8074553733e8e4ea5ce9b85f69e40d755a55014536b12323f8b220600c94ef2b9c51428" + ) val lnInvoiceSig = LnInvoiceSignature(recoverId = UInt8.zero, signature = signature) val route1 = LnRoute( pubkey = ECPublicKey.fromHex( - "029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"), + "029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255" + ), shortChannelID = ShortChannelId.fromHex("0102030405060708"), feeBaseMsat = FeeBaseMSat(MilliSatoshis.one), feePropMilli = FeeProportionalMillionths(UInt32(20)), @@ -231,7 +256,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val route2 = LnRoute( pubkey = ECPublicKey.fromHex( - "039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255"), + "039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255" + ), shortChannelID = ShortChannelId.fromHex("030405060708090a"), feeBaseMsat = FeeBaseMSat(MilliSatoshis(2)), feePropMilli = FeeProportionalMillionths(UInt32(30)), @@ -240,15 +266,19 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val route = LnTag.RoutingInfo(Vector(route1, route2)) - val lnTags = LnTaggedFields(paymentHash = paymentTag, - descriptionOrHash = descpriptionHashTag, - fallbackAddress = Some(fallbackAddr), - routingInfo = Some(route)) + val lnTags = LnTaggedFields( + paymentHash = paymentTag, + descriptionOrHash = descpriptionHashTag, + fallbackAddress = Some(fallbackAddr), + routingInfo = Some(route) + ) - val lnInvoice = LnInvoice(hrp = hrpMilli, - timestamp = time, - lnTags = lnTags, - signature = lnInvoiceSig) + val lnInvoice = LnInvoice( + hrp = hrpMilli, + timestamp = time, + lnTags = lnTags, + signature = lnInvoiceSig + ) val serialized = lnInvoice.toString serialized must be(expected) @@ -266,20 +296,26 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { "4nvjcpxlekvmxl6qcs9j3tz0469gqsjurz5" val fallbackAddr = LnTag.FallbackAddressTag( - P2SHAddress.fromString("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX")) + P2SHAddress.fromString("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX") + ) - val lnTags = LnTaggedFields(paymentHash = paymentTag, - descriptionOrHash = descpriptionHashTag, - fallbackAddress = Some(fallbackAddr)) + val lnTags = LnTaggedFields( + paymentHash = paymentTag, + descriptionOrHash = descpriptionHashTag, + fallbackAddress = Some(fallbackAddr) + ) val signature = ECDigitalSignature.fromRS( - "b6c6860fc6ff41bafba1745b538b6a7c6c2c0234f76bf817bf567be88cf2c632492c9dd279470841cd1e21a33ae7ed59b25809bf9b3366fe81881651589f5d15") + "b6c6860fc6ff41bafba1745b538b6a7c6c2c0234f76bf817bf567be88cf2c632492c9dd279470841cd1e21a33ae7ed59b25809bf9b3366fe81881651589f5d15" + ) val lnInvoiceSig = LnInvoiceSignature(signature = signature, recoverId = UInt8.zero) - val lnInvoice = LnInvoice(hrp = hrpMilli, - timestamp = time, - lnTags = lnTags, - signature = lnInvoiceSig) + val lnInvoice = LnInvoice( + hrp = hrpMilli, + timestamp = time, + lnTags = lnTags, + signature = lnInvoiceSig + ) val serialized = lnInvoice.toString @@ -291,7 +327,7 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { } it must "parse BOLT11 example 7 (p2wpkh fallback addr)" in { - //this test does not pass because bitcoin-s does not support p2wpkh currently + // this test does not pass because bitcoin-s does not support p2wpkh currently val expected = "lnbc20m1pvjluez" + "pp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq" + @@ -302,22 +338,28 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val fallbackAddr = LnTag.FallbackAddressTag( Bech32Address - .fromString("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")) + .fromString("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4") + ) - val lnTags = LnTaggedFields(paymentHash = paymentTag, - descriptionOrHash = descpriptionHashTag, - fallbackAddress = Some(fallbackAddr)) + val lnTags = LnTaggedFields( + paymentHash = paymentTag, + descriptionOrHash = descpriptionHashTag, + fallbackAddress = Some(fallbackAddr) + ) val signature = ECDigitalSignature.fromRS( - "c8583b8f65853d7cc90f0eb4ae0e92a606f89caf4f7d65048142d7bbd4e5f3623ef407a75458e4b20f00efbc734f1c2eefc419f3a2be6d51038016ffb35cd613") + "c8583b8f65853d7cc90f0eb4ae0e92a606f89caf4f7d65048142d7bbd4e5f3623ef407a75458e4b20f00efbc734f1c2eefc419f3a2be6d51038016ffb35cd613" + ) val lnInvoiceSig = LnInvoiceSignature(signature = signature, recoverId = UInt8.zero) - val lnInvoice = LnInvoice(hrp = hrpMilli, - timestamp = time, - lnTags = lnTags, - signature = lnInvoiceSig) + val lnInvoice = LnInvoice( + hrp = hrpMilli, + timestamp = time, + lnTags = lnTags, + signature = lnInvoiceSig + ) val serialized = lnInvoice.toString @@ -339,22 +381,29 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val fallbackAddr = LnTag.FallbackAddressTag( Bech32Address .fromString( - "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3")) + "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3" + ) + ) - val lnTags = LnTaggedFields(paymentHash = paymentTag, - descriptionOrHash = descpriptionHashTag, - fallbackAddress = Some(fallbackAddr)) + val lnTags = LnTaggedFields( + paymentHash = paymentTag, + descriptionOrHash = descpriptionHashTag, + fallbackAddress = Some(fallbackAddr) + ) val signature = ECDigitalSignature.fromRS( - "51e4f6446e410a164a6da9f39507e730c26241b4456ab6ea28d1b12c71ef8ca20c9cfe3dffc07d9f8db671ecaa4d20beedb193bda8ce37c59f85f82773a55d47") + "51e4f6446e410a164a6da9f39507e730c26241b4456ab6ea28d1b12c71ef8ca20c9cfe3dffc07d9f8db671ecaa4d20beedb193bda8ce37c59f85f82773a55d47" + ) val lnInvoiceSig = LnInvoiceSignature(signature = signature, recoverId = UInt8.zero) - val lnInvoice = LnInvoice(hrp = hrpMilli, - timestamp = time, - lnTags = lnTags, - signature = lnInvoiceSig) + val lnInvoice = LnInvoice( + hrp = hrpMilli, + timestamp = time, + lnTags = lnTags, + signature = lnInvoiceSig + ) val serialized = lnInvoice.toString @@ -370,29 +419,38 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqqq4u9s93jtgysm3mrwll70zr697y3mf902hvxwej0v7c62rsltw83ng0pu8w3j230sluc5gxkdmm9dvpy9y6ggtjd2w544mzdrcs42t7sqdkcy8h" val signature = ECDigitalSignature.fromHex( - "3045022100af0b02c64b4121b8ec6efffcf10f45f123b495eabb0cecc9ecf634a1c3eb71e30220343c3c3ba32545f0ff31441acddecad60485269085c9aa752b5d89a3c42aa5fa") + "3045022100af0b02c64b4121b8ec6efffcf10f45f123b495eabb0cecc9ecf634a1c3eb71e30220343c3c3ba32545f0ff31441acddecad60485269085c9aa752b5d89a3c42aa5fa" + ) val lnInvoiceSig = LnInvoiceSignature(recoverId = UInt8.zero, signature = signature) val descriptionTag = LnTag.DescriptionTag("coffee beans") val paymentSecret = Some( - LnTag.SecretTag(PaymentSecret.fromHex( - "1111111111111111111111111111111111111111111111111111111111111111"))) + LnTag.SecretTag( + PaymentSecret.fromHex( + "1111111111111111111111111111111111111111111111111111111111111111" + ) + ) + ) val features = Some( - LnTag.FeaturesTag(ByteVector.fromValidHex("800000000000000000000800"))) + LnTag.FeaturesTag(ByteVector.fromValidHex("800000000000000000000800")) + ) val lnTags = LnTaggedFields( - Vector(paymentTag, descriptionTag, paymentSecret.get, features.get)) + Vector(paymentTag, descriptionTag, paymentSecret.get, features.get) + ) val hrpMilli = LnHumanReadablePart(LnBitcoinMainNet, Some(MilliBitcoins(25))) - val lnInvoice = LnInvoice(hrp = hrpMilli, - timestamp = time, - lnTags = lnTags, - signature = lnInvoiceSig) + val lnInvoice = LnInvoice( + hrp = hrpMilli, + timestamp = time, + lnTags = lnTags, + signature = lnInvoiceSig + ) val serialized = lnInvoice.toString // TODO uncomment when https://github.com/bitcoin-s/bitcoin-s/issues/1064 is fixed @@ -405,7 +463,7 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { } it must "deserialize and reserialize a invoice with a explicity expiry time" in { - //from eclair + // from eclair val bech32 = "lnbcrt1m1pd6ssf3pp5mqcepx6yzx7uu0uagw5x3c7kqhnpwr3mfn844hjux8tlza6ztr7sdqqxqrrss0rl3gzer9gfc54fs84rd4xk6g8nf0syharnnyljc9za933memdzxrjz0v2v94ntuhdxduk3z0nlmpmznryvvvl4gzgu28kjkm4ey98gpmyhjfa" @@ -432,14 +490,17 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { intercept[IllegalArgumentException] { val sig = EmptyDigitalSignature val tags = - LnTaggedFields(paymentHash = paymentTag, - descriptionOrHash = - Right(LnTag.DescriptionHashTag(descriptionHash))) + LnTaggedFields( + paymentHash = paymentTag, + descriptionOrHash = Right(LnTag.DescriptionHashTag(descriptionHash)) + ) val lnSig = LnInvoiceSignature(recoverId = UInt8.zero, signature = sig) - LnInvoice(hrp = hrpEmpty, - timestamp = UInt64.zero, - lnTags = tags, - signature = lnSig) + LnInvoice( + hrp = hrpEmpty, + timestamp = UInt64.zero, + lnTags = tags, + signature = lnSig + ) } } @@ -447,9 +508,10 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val privKey = ECPrivateKey.freshPrivateKey val tags = - LnTaggedFields(paymentHash = paymentTag, - descriptionOrHash = - Right(LnTag.DescriptionHashTag(descriptionHash))) + LnTaggedFields( + paymentHash = paymentTag, + descriptionOrHash = Right(LnTag.DescriptionHashTag(descriptionHash)) + ) val invoice = LnInvoice.build(hrp = hrpEmpty, lnTags = tags, privateKey = privKey) @@ -458,7 +520,7 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { } it must "handle the weird case if sigdata being exactly on a byte boundary, which means we need to pad the sigdata with a zero byte" in { - //https://github.com/bitcoin-s/bitcoin-s-core/issues/277 + // https://github.com/bitcoin-s/bitcoin-s-core/issues/277 val expected = "03fad6c016f998e85d03ce0b7358b3b6a38ebc7fd60030340d0245fea0d95c8c12" val expectedHash = @@ -470,12 +532,15 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { invoice.lnTags.paymentHash.hash.hex must be(expectedHash) invoice.signature.hex must be( - "00f469f9abb10d678eff29ed1cc2d082e9e3f1d7e3688f84b0601556b5df401c2d30bc4fb60fc8727f8df3fb891cea4487e38094c0ef0533995aea35bd2ad04600") + "00f469f9abb10d678eff29ed1cc2d082e9e3f1d7e3688f84b0601556b5df401c2d30bc4fb60fc8727f8df3fb891cea4487e38094c0ef0533995aea35bd2ad04600" + ) invoice.signature.signature.hex must be( - "3044022000f469f9abb10d678eff29ed1cc2d082e9e3f1d7e3688f84b0601556b5df401c02202d30bc4fb60fc8727f8df3fb891cea4487e38094c0ef0533995aea35bd2ad046") + "3044022000f469f9abb10d678eff29ed1cc2d082e9e3f1d7e3688f84b0601556b5df401c02202d30bc4fb60fc8727f8df3fb891cea4487e38094c0ef0533995aea35bd2ad046" + ) invoice.lnTags.description.get.string must be( - "{\"duration\":10000,\"channel\":\"trades\",\"event\":\"subscribe\",\"uuid\":\"00112233-4455-6677-8899-aabbccddeeff\",\"exchange\":\"bitfinex\",\"symbol\":\"BTCUSD\"}") + "{\"duration\":10000,\"channel\":\"trades\",\"event\":\"subscribe\",\"uuid\":\"00112233-4455-6677-8899-aabbccddeeff\",\"exchange\":\"bitfinex\",\"symbol\":\"BTCUSD\"}" + ) invoice.timestamp must be(UInt64(1546180450)) @@ -486,7 +551,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { invoice.isValidSignature must be(true) invoice.signatureData.toHex must be( - "6c6e74623130306e0b851aec410d1ae02e6dcc82f0480d4d39e3e1ada8ca5170d6ad19391d7b403a4b1ee61d57e741a72bd91323ab930ba34b7b7111d1898181818161131b430b73732b6111d113a3930b232b991161132bb32b73a111d1139bab139b1b934b1329116113abab4b2111d111818189899191999969a1a1a9a969b1b1b9b969c1c1c9c96b0b0b13131b1b23232b2b33311161132bc31b430b733b2911d113134ba3334b732bc11161139bcb6b137b6111d11212a21aaa9a2113e8c018e100") + "6c6e74623130306e0b851aec410d1ae02e6dcc82f0480d4d39e3e1ada8ca5170d6ad19391d7b403a4b1ee61d57e741a72bd91323ab930ba34b7b7111d1898181818161131b430b73732b6111d113a3930b232b991161132bb32b73a111d1139bab139b1b934b1329116113abab4b2111d111818189899191999969a1a1a9a969b1b1b9b969c1c1c9c96b0b0b13131b1b23232b2b33311161132bc31b430b733b2911d113134ba3334b732bc11161139bcb6b137b6111d11212a21aaa9a2113e8c018e100" + ) invoice.toString must be(str) @@ -499,10 +565,17 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { "lnbcrt10n1p0px7lfpp5ghc2y7ttnwy58jx0dfcsdxy7ey0qfryn0wcmm04ckud0qw73kt9sdq9vehk7xqrrss9qypqqqsp5qlf6efygd26y03y66jdqqfmlxthplnu5cc8648fgn88twhpyvmgqg9k5kd0k8vv3xvvqpkhkt9chdl579maq45gvck4g0yd0eggmvfkzgvjmwn29r99p57tgyl3l3s82hlc4e97at55xl5lyzpfk6n36yyqqxeem8q" val invoice = LnInvoice.fromStringT(serialized).get invoice.lnTags.secret must be( - Some(LnTag.SecretTag(PaymentSecret.fromHex( - "07d3aca4886ab447c49ad49a00277f32ee1fcf94c60faa9d2899ceb75c2466d0")))) + Some( + LnTag.SecretTag( + PaymentSecret.fromHex( + "07d3aca4886ab447c49ad49a00277f32ee1fcf94c60faa9d2899ceb75c2466d0" + ) + ) + ) + ) invoice.lnTags.features must be( - Some(LnTag.FeaturesTag(ByteVector.fromValidHex("0800")))) + Some(LnTag.FeaturesTag(ByteVector.fromValidHex("0800"))) + ) invoice.toString must be(serialized) } @@ -520,7 +593,8 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { val unknownTag = LnTag.UnknownTag( LnTagPrefix.Unknown('z'), - Bech32.from8bitTo5bit(ByteVector.fromValidHex("cafebabe"))) + Bech32.from8bitTo5bit(ByteVector.fromValidHex("cafebabe")) + ) val descriptionTag = LnTag.DescriptionTag("Please consider supporting this project") @@ -569,10 +643,12 @@ class LnInvoiceUnitTest extends BitcoinSUnitTest { it must "build an invoice with a recoverable pub key" in { val priv = ECPrivateKey.fromBytes( - hex"deeb3f23a850090b9033e3400584923a281d3c7d914a6d1587369abe2071d8c5") + hex"deeb3f23a850090b9033e3400584923a281d3c7d914a6d1587369abe2071d8c5" + ) val hrp = LnHumanReadablePart.fromLnParams(LnParams.LnBitcoinRegTest) val tags = LnTaggedFields( - Vector(PaymentHashTag(Sha256Digest.empty), DescriptionTag("test"))) + Vector(PaymentHashTag(Sha256Digest.empty), DescriptionTag("test")) + ) val invoice = LnInvoice.build(hrp, tags, priv) assert(invoice.nodeId == NodeId(priv.publicKey)) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/channel/ShortChannelIdTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/channel/ShortChannelIdTest.scala index 63df23308a..68d0e8f67f 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/channel/ShortChannelIdTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/channel/ShortChannelIdTest.scala @@ -7,20 +7,25 @@ class ShortChannelIdTest extends BitcoinSUnitTest { it must "convert short channel id to and from human readable form" in { // BOLT example ShortChannelId.fromHumanReadableString("539268x845x1") must be( - ShortChannelId.fromHex("83a8400034d0001")) + ShortChannelId.fromHex("83a8400034d0001") + ) ShortChannelId.fromHex("83a8400034d0001").toHumanReadableString must be( - "539268x845x1") + "539268x845x1" + ) // min value ShortChannelId.fromHumanReadableString("0x0x0") must be( - ShortChannelId.fromHex("0")) + ShortChannelId.fromHex("0") + ) ShortChannelId.fromHex("0").toHumanReadableString must be("0x0x0") // max value ShortChannelId.fromHumanReadableString("16777215x16777215x65535") must be( - ShortChannelId.fromHex("ffffffffffffffff")) + ShortChannelId.fromHex("ffffffffffffffff") + ) ShortChannelId.fromHex("ffffffffffffffff").toHumanReadableString must be( - "16777215x16777215x65535") + "16777215x16777215x65535" + ) } it must "validate short channel id components" in { @@ -39,7 +44,8 @@ class ShortChannelIdTest extends BitcoinSUnitTest { an[IllegalArgumentException] must be thrownBy ShortChannelId .fromHumanReadableString("1x1x1x1") ShortChannelId.fromHumanReadableString("cafebabe") must be( - ShortChannelId.fromHex("cafebabe")) + ShortChannelId.fromHex("cafebabe") + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnitTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnitTest.scala index f8f801dc80..e562ca3bd5 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnitTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnitTest.scala @@ -139,8 +139,11 @@ class LnCurrencyUnitTest extends BitcoinSUnitTest { it must "have Long syntax" in { forAll( - Gen.choose(LnPolicy.minMilliBitcoins.toLong, - LnPolicy.maxMilliBitcoins.toLong)) { num => + Gen.choose( + LnPolicy.minMilliBitcoins.toLong, + LnPolicy.maxMilliBitcoins.toLong + ) + ) { num => assert(num.millibitcoins == MilliBitcoins(num)) assert(num.millibitcoin == MilliBitcoins(num)) assert(num.mBTC == MilliBitcoins(num)) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshisTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshisTest.scala index cbb2e0733f..d5c4b19367 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshisTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshisTest.scala @@ -93,9 +93,9 @@ class MilliSatoshisTest extends BitcoinSUnitTest { it must "covert from a ln currency unit -> millisatoshis -> lnCurrencyUnit" in { forAll(LnCurrencyUnitGen.positivePicoBitcoin) { pb => val underlying = pb.toBigInt - //we lose the last digit of precision converting - //PicoBitcoins -> MilliSatoshis - //this is the expected answer + // we lose the last digit of precision converting + // PicoBitcoins -> MilliSatoshis + // this is the expected answer val expected = (underlying / 10) * 10 val expectedPico = PicoBitcoins(expected) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/CLTVScriptPubKeyTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/CLTVScriptPubKeyTest.scala index de84eee001..05e9de0507 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/CLTVScriptPubKeyTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/CLTVScriptPubKeyTest.scala @@ -20,22 +20,26 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class CLTVScriptPubKeyTest extends BitcoinSUnitTest { val expectedAsm: Seq[ScriptToken] = - List(OP_DUP, - OP_HASH160, - BytesToPushOntoStack(20), - ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), - OP_EQUALVERIFY, - OP_CHECKSIG) - //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + List( + OP_DUP, + OP_HASH160, + BytesToPushOntoStack(20), + ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), + OP_EQUALVERIFY, + OP_CHECKSIG + ) + // from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val rawScriptPubKey = TestUtil.rawP2PKHScriptPubKey val scriptPubKey = ScriptPubKey(rawScriptPubKey) "CLTVScriptPubKey" must "return the expected asm from hex" in { val expectedCLTVAsm: Seq[ScriptToken] = - List(BytesToPushOntoStack(4), - ScriptConstant("2b07ae57"), - OP_CHECKLOCKTIMEVERIFY, - OP_DROP) ++ expectedAsm + List( + BytesToPushOntoStack(4), + ScriptConstant("2b07ae57"), + OP_CHECKLOCKTIMEVERIFY, + OP_DROP + ) ++ expectedAsm val cltv = CLTVScriptPubKey(ScriptNumber(1471022891), scriptPubKey) cltv.asm must be(expectedCLTVAsm) } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/CSVScriptPubKeyTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/CSVScriptPubKeyTest.scala index 6aeb50fe72..4a2746aa6d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/CSVScriptPubKeyTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/CSVScriptPubKeyTest.scala @@ -20,22 +20,26 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class CSVScriptPubKeyTest extends BitcoinSUnitTest { val expectedAsm: Seq[ScriptToken] = - List(OP_DUP, - OP_HASH160, - BytesToPushOntoStack(20), - ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), - OP_EQUALVERIFY, - OP_CHECKSIG) - //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + List( + OP_DUP, + OP_HASH160, + BytesToPushOntoStack(20), + ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), + OP_EQUALVERIFY, + OP_CHECKSIG + ) + // from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val rawScriptPubKey = TestUtil.rawP2PKHScriptPubKey val scriptPubKey = ScriptPubKey(rawScriptPubKey) "CSVScriptPubKey" must "return the expected asm from hex" in { val expectedCSVAsm: Seq[ScriptToken] = - List(BytesToPushOntoStack(4), - ScriptConstant("6202b257"), - OP_CHECKSEQUENCEVERIFY, - OP_DROP) ++ expectedAsm + List( + BytesToPushOntoStack(4), + ScriptConstant("6202b257"), + OP_CHECKSEQUENCEVERIFY, + OP_DROP + ) ++ expectedAsm val csv = CSVScriptPubKey(ScriptNumber(1471283810), scriptPubKey) csv.asm must be(expectedCSVAsm) } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ConditionalScriptPubKeyTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ConditionalScriptPubKeyTest.scala index 656c14ea76..76aae44b5f 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ConditionalScriptPubKeyTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ConditionalScriptPubKeyTest.scala @@ -9,7 +9,7 @@ class ConditionalScriptPubKeyTest extends BitcoinSJvmTest { behavior of "ConditionalScriptPubKey" it must "be able to parse a conditional spk with a nested p2sh script" in { - //see: https://github.com/bitcoin-s/bitcoin-s/issues/2962 + // see: https://github.com/bitcoin-s/bitcoin-s/issues/2962 val scriptSigHex = "48304502207ffb30631d837895ac1b415408b70a809090b25d4070198043299fe247f62d2602210089b52f0d243dea1e4313ef67723b0d0642ff77bb6ca05ea85296b2539c797f5c81513d632103184b16f5d6c01e2d6ded3f8a292e5b81608318ecb8e93aa3747bc88b8dbf256cac67a914f5862841f254a1483eab66909ae588e45d617c5e8768" @@ -23,7 +23,7 @@ class ConditionalScriptPubKeyTest extends BitcoinSJvmTest { } it must "consider a redeem script that contains OP_IF in it with a nested p2sh script pubkey in it" in { - //see: https://github.com/bitcoin-s/bitcoin-s/issues/2962 + // see: https://github.com/bitcoin-s/bitcoin-s/issues/2962 val hex = "632103184b16f5d6c01e2d6ded3f8a292e5b81608318ecb8e93aa3747bc88b8dbf256cac67a914f5862841f254a1483eab66909ae588e45d617c5e8768" val scriptPubKey = RawScriptPubKey.fromAsmHex(hex) @@ -41,7 +41,7 @@ class ConditionalScriptPubKeyTest extends BitcoinSJvmTest { assert(P2SHScriptSignature.isRedeemScript(constant)) - //we should be able to parse the tx that contains it with no problem + // we should be able to parse the tx that contains it with no problem val txHex = "010000000193983cb2f1f3d83615f10e1ca33f49c72250acbebd840793aaa8bc7a6b28b76b000000008848304502207ffb30631d837895ac1b415408b70a809090b25d4070198043299fe247f62d2602210089b52f0d243dea1e4313ef67723b0d0642ff77bb6ca05ea85296b2539c797f5c81513d632103184b16f5d6c01e2d6ded3f8a292e5b81608318ecb8e93aa3747bc88b8dbf256cac67a914f5862841f254a1483eab66909ae588e45d617c5e8768ffffffff01a0860100000000001976a914a07aa8415d34d0db44f220ff9522609641c0bfbf88ac00000000" assert(Transaction.fromHexT(txHex).isSuccess) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ConditionalScriptSignatureTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ConditionalScriptSignatureTest.scala index bc830b833f..cd9e28f3da 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ConditionalScriptSignatureTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ConditionalScriptSignatureTest.scala @@ -28,7 +28,9 @@ class ConditionalScriptSignatureTest extends BitcoinSUnitTest { conditionalScriptSignature => assert( ConditionalScriptSignature( - conditionalScriptSignature.bytes) == conditionalScriptSignature) + conditionalScriptSignature.bytes + ) == conditionalScriptSignature + ) } } @@ -46,7 +48,8 @@ class ConditionalScriptSignatureTest extends BitcoinSUnitTest { forAll(ScriptGenerators.conditionalScriptSignature) { conditionalScriptSignature => assert( - conditionalScriptSignature.signatures == conditionalScriptSignature.nestedScriptSig.signatures) + conditionalScriptSignature.signatures == conditionalScriptSignature.nestedScriptSig.signatures + ) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/LockTimeScriptSignatureTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/LockTimeScriptSignatureTest.scala index a6d09a7173..6be6ec839d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/LockTimeScriptSignatureTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/LockTimeScriptSignatureTest.scala @@ -23,7 +23,8 @@ class LockTimeScriptSignatureTest extends BitcoinSUnitTest { it should "have agreement with nested signatures" in { forAll(ScriptGenerators.lockTimeScriptSig) { lockTimeScriptSignature => assert( - lockTimeScriptSignature.signatures == lockTimeScriptSignature.scriptSig.signatures) + lockTimeScriptSignature.signatures == lockTimeScriptSignature.scriptSig.signatures + ) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/MultiSignatureScriptPubKeyTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/MultiSignatureScriptPubKeyTest.scala index 61e6ffbf09..9bfb505235 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/MultiSignatureScriptPubKeyTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/MultiSignatureScriptPubKeyTest.scala @@ -38,12 +38,16 @@ class MultiSignatureScriptPubKeyTest extends BitcoinSUnitTest { multiSigScriptPubKey.publicKeys must be( Seq( ECPublicKeyBytes( - "025878e270211662a27181cf4d6ad4d2cf0e69a98a3815c086f587c7e9388d8718"), + "025878e270211662a27181cf4d6ad4d2cf0e69a98a3815c086f587c7e9388d8718" + ), ECPublicKeyBytes( - "03fc85980e3fac1f3d8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906"), + "03fc85980e3fac1f3d8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906" + ), ECPublicKeyBytes( - "0215b5bd050869166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f") - )) + "0215b5bd050869166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f" + ) + ) + ) } @@ -74,7 +78,9 @@ class MultiSignatureScriptPubKeyTest extends BitcoinSUnitTest { case (multiSigScriptPubKey, _) => assert( MultiSignatureScriptPubKey( - multiSigScriptPubKey.hex) == multiSigScriptPubKey) + multiSigScriptPubKey.hex + ) == multiSigScriptPubKey + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/MultiSignatureScriptSignatureTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/MultiSignatureScriptSignatureTest.scala index f9407dc86f..756408768c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/MultiSignatureScriptSignatureTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/MultiSignatureScriptSignatureTest.scala @@ -23,7 +23,9 @@ class MultiSignatureScriptSignatureTest extends BitcoinSJvmTest { multiSigScriptSig => assert( MultiSignatureScriptSignature( - multiSigScriptSig.hex) == multiSigScriptSig) + multiSigScriptSig.hex + ) == multiSigScriptSig + ) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKHScriptSignatureTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKHScriptSignatureTest.scala index b84151e4c8..da25393d98 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKHScriptSignatureTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKHScriptSignatureTest.scala @@ -12,20 +12,23 @@ class P2PKHScriptSignatureTest extends BitcoinSJvmTest { "P2PKHScriptSignature" must "be able to identify it's own hash type" in { val p2pkhScriptSig = TestUtil.p2pkhScriptSig match { case s: P2PKHScriptSignature => s - case _ => throw new RuntimeException("Must be p2pkh scriptSig") + case _ => throw new RuntimeException("Must be p2pkh scriptSig") } HashType.fromBytes( - ByteVector.fromByte(p2pkhScriptSig.signatures.head.bytes.last)) must be( - HashType.sigHashAll) + ByteVector.fromByte(p2pkhScriptSig.signatures.head.bytes.last) + ) must be(HashType.sigHashAll) } it must "be able to identify the signature in a p2pkh scriptSig" in { val p2pkhScriptSig = TestUtil.p2pkhScriptSig match { case s: P2PKHScriptSignature => s - case _ => throw new RuntimeException("Must be p2pkh scriptSig") + case _ => throw new RuntimeException("Must be p2pkh scriptSig") } - p2pkhScriptSig.signature must be(ECDigitalSignature( - "3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01")) + p2pkhScriptSig.signature must be( + ECDigitalSignature( + "3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01" + ) + ) } it must "serialization symmetry" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKScriptPubKeyTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKScriptPubKeyTest.scala index 604d3a37f1..272135c47b 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKScriptPubKeyTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKScriptPubKeyTest.scala @@ -15,8 +15,11 @@ class P2PKScriptPubKeyTest extends BitcoinSUnitTest { throw new RuntimeException("should have been p2pk script pub key") } - p2pkScriptPubKey.publicKey must be(ECPublicKeyBytes( - "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")) + p2pkScriptPubKey.publicKey must be( + ECPublicKeyBytes( + "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8" + ) + ) } it must "serialization symmetry" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKScriptSignatureTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKScriptSignatureTest.scala index 2b766c3e80..0c9b33f786 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKScriptSignatureTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2PKScriptSignatureTest.scala @@ -12,10 +12,13 @@ class P2PKScriptSignatureTest extends BitcoinSUnitTest { "P2PKScriptSignature" must "find the signature inside of a p2pk scriptSig" in { val p2pkScriptSig = TestUtil.p2pkScriptSig match { case s: P2PKScriptSignature => s - case _ => throw new RuntimeException("SHould have been a p2pk scriptSig") + case _ => throw new RuntimeException("SHould have been a p2pk scriptSig") } - p2pkScriptSig.signature must be(ECDigitalSignature( - "304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001")) + p2pkScriptSig.signature must be( + ECDigitalSignature( + "304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001" + ) + ) } it must "serialization symmetry" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2SHScriptSignatureTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2SHScriptSignatureTest.scala index a71a976dd3..08bb16597c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2SHScriptSignatureTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2SHScriptSignatureTest.scala @@ -18,15 +18,18 @@ class P2SHScriptSignatureTest extends BitcoinSJvmTest { val p2shScriptSig: P2SHScriptSignature = ScriptSignature(rawP2SHScriptSig) match { case x: P2SHScriptSignature => x - case y => throw new RuntimeException("Must be p2sh script sig: " + y) + case y => throw new RuntimeException("Must be p2sh script sig: " + y) } p2shScriptSig.publicKeys must be( Seq( ECPublicKeyBytes( - "0369d26ebd086523384a0f89f293d4c327a65fa73332d8efd1097cb35231295b83"), + "0369d26ebd086523384a0f89f293d4c327a65fa73332d8efd1097cb35231295b83" + ), ECPublicKeyBytes( - "02480863e5c4a4e9763f5380c44fcfe6a3b7787397076cf9ea1049303a9d34f721") - )) + "02480863e5c4a4e9763f5380c44fcfe6a3b7787397076cf9ea1049303a9d34f721" + ) + ) + ) } @@ -34,7 +37,7 @@ class P2SHScriptSignatureTest extends BitcoinSJvmTest { val p2shScriptSig = TestUtil.p2shInputScript2Of2 match { case s: P2SHScriptSignature => s - case _ => throw new RuntimeException("Should be p2sh scriptSig") + case _ => throw new RuntimeException("Should be p2sh scriptSig") } p2shScriptSig.scriptSignatureNoRedeemScript.asm must be( @@ -42,11 +45,14 @@ class P2SHScriptSignatureTest extends BitcoinSJvmTest { OP_0, BytesToPushOntoStack(71), ScriptConstant( - "304402207d764cb90c9fd84b74d33a47cf3a0ffead9ded98333776becd6acd32c4426dac02203905a0d064e7f53d07793e86136571b6e4f700c1cfb888174e84d78638335b8101"), + "304402207d764cb90c9fd84b74d33a47cf3a0ffead9ded98333776becd6acd32c4426dac02203905a0d064e7f53d07793e86136571b6e4f700c1cfb888174e84d78638335b8101" + ), BytesToPushOntoStack(72), ScriptConstant( - "3045022100906aaca39f022acd8b7a38fd2f92aca9e9f35cfeaee69a6f13e1d083ae18222602204c9ed96fc6c4de56fd85c679fc59c16ee1ccc80c42563b86174e1a506fc007c801") - )) + "3045022100906aaca39f022acd8b7a38fd2f92aca9e9f35cfeaee69a6f13e1d083ae18222602204c9ed96fc6c4de56fd85c679fc59c16ee1ccc80c42563b86174e1a506fc007c801" + ) + ) + ) } it must "symmetrical serialization" in { @@ -62,7 +68,8 @@ class P2SHScriptSignatureTest extends BitcoinSJvmTest { val p2shScriptSig = P2SHScriptSignature(witScriptPubKey) assert(p2shScriptSig.redeemScript == witScriptPubKey) assert( - p2shScriptSig.scriptSignatureNoRedeemScript == EmptyScriptSignature) + p2shScriptSig.scriptSignatureNoRedeemScript == EmptyScriptSignature + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2WSHWitnessSPKV0Test.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2WSHWitnessSPKV0Test.scala index 90e15028cc..7ba3e65f1b 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2WSHWitnessSPKV0Test.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/P2WSHWitnessSPKV0Test.scala @@ -13,9 +13,11 @@ class P2WSHWitnessSPKV0Test extends BitcoinSUnitTest { val p2pk = P2PKScriptPubKey(asmP2PK) val asmMultisig = - Seq(OP_1) ++ pushOps ++ Seq(ScriptConstant(uncompressed.bytes), - OP_1, - OP_CHECKMULTISIG) + Seq(OP_1) ++ pushOps ++ Seq( + ScriptConstant(uncompressed.bytes), + OP_1, + OP_CHECKMULTISIG + ) val multisig = MultiSignatureScriptPubKey.fromAsm(asmMultisig) "P2WPKHWitnessSPKV0" must "fail to be created with an uncompressed public key" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptPubKeyFactoryTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptPubKeyFactoryTest.scala index 2715c6ddd0..24100da4d8 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptPubKeyFactoryTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptPubKeyFactoryTest.scala @@ -9,7 +9,7 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class ScriptPubKeyFactoryTest extends BitcoinSUnitTest { "ScriptPubKeyFactory" must "create a scriptPubKey from a sequences of bytes and hex and get the same thing" in { - //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + // from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val rawScriptPubKey = TestUtil.rawP2PKHScriptPubKey val scriptPubKeyFromBytes = ScriptPubKey(BytesUtil.decodeHex(rawScriptPubKey)) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptPubKeyTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptPubKeyTest.scala index 5426dba20d..9718eb880f 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptPubKeyTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptPubKeyTest.scala @@ -16,13 +16,15 @@ import scodec.bits.ByteVector class ScriptPubKeyTest extends BitcoinSUnitTest { val expectedAsm: Seq[ScriptToken] = - List(OP_DUP, - OP_HASH160, - BytesToPushOntoStack(20), - ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), - OP_EQUALVERIFY, - OP_CHECKSIG) - //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + List( + OP_DUP, + OP_HASH160, + BytesToPushOntoStack(20), + ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), + OP_EQUALVERIFY, + OP_CHECKSIG + ) + // from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val rawScriptPubKey: String = TestUtil.rawP2PKHScriptPubKey val scriptPubKey: ScriptPubKey = ScriptPubKey(rawScriptPubKey) @@ -47,11 +49,12 @@ class ScriptPubKeyTest extends BitcoinSUnitTest { } it must "fail to construct a valid witness spk v1 when the coordinate is not on the curve" in { - //all zeroes + // all zeroes val pubKey = ByteVector.fill(32)(0.toByte) - //reconstruct asm + // reconstruct asm val asm = OP_1 +: (BitcoinScriptUtil.calculatePushOp(pubKey) ++ Vector( - ScriptConstant(pubKey))) + ScriptConstant(pubKey) + )) assertThrows[IllegalArgumentException] { TaprootScriptPubKey.fromAsm(asm) @@ -60,7 +63,8 @@ class ScriptPubKeyTest extends BitcoinSUnitTest { it must "determine the correct descriptors" in { val key = ECPublicKey( - "02c48670493ca813cd2d1bf8177df3d3d7c8e97fc7eb74cd21f71ea2ba416aee54") + "02c48670493ca813cd2d1bf8177df3d3d7c8e97fc7eb74cd21f71ea2ba416aee54" + ) // p2pk val p2pk = P2PKScriptPubKey(key) assert(p2pk.toString == s"pk(${key.hex})") @@ -72,19 +76,21 @@ class ScriptPubKeyTest extends BitcoinSUnitTest { // multi val multi = MultiSignatureScriptPubKey(2, Seq(key, key)) assert( - multi.toString == "multi(2,02c48670493ca813cd2d1bf8177df3d3d7c8e97fc7eb74cd21f71ea2ba416aee54,02c48670493ca813cd2d1bf8177df3d3d7c8e97fc7eb74cd21f71ea2ba416aee54)") + multi.toString == "multi(2,02c48670493ca813cd2d1bf8177df3d3d7c8e97fc7eb74cd21f71ea2ba416aee54,02c48670493ca813cd2d1bf8177df3d3d7c8e97fc7eb74cd21f71ea2ba416aee54)" + ) // p2sh val p2sh = P2SHScriptPubKey(p2pkh) assert(p2sh.toString == "sh(2a941c7a3e92c7f5fe149a641cae6b417989c411)") - //p2wpkh + // p2wpkh val p2wpkh = P2WPKHWitnessSPKV0(key) assert(p2wpkh.toString == "wpkh(63fe7c47cf475802b1c4ec2d34d1ef33e6b0fc63)") // p2wsh val wsh = P2WSHWitnessSPKV0(p2pkh) assert( - wsh.toString == "wsh(c0ad050ea2824ca0b938dd1c998f7160793034f321a307aae990786c0c029317)") + wsh.toString == "wsh(c0ad050ea2824ca0b938dd1c998f7160793034f321a307aae990786c0c029317)" + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureFactoryTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureFactoryTest.scala index 7f3c8478ce..598a264105 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureFactoryTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureFactoryTest.scala @@ -48,7 +48,7 @@ class ScriptSignatureFactoryTest extends BitcoinSUnitTest { it must "parse a p2sh scriptSignature from a raw scriptSig" in { val result = TestUtil.p2shInputScript2Of2 match { case _: P2SHScriptSignature => true - case y => throw new RuntimeException("Should be p2sh input: " + y) + case y => throw new RuntimeException("Should be p2sh input: " + y) } result must be(true) } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureTest.scala index d780a23c26..03ea286f35 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptSignatureTest.scala @@ -25,20 +25,21 @@ class ScriptSignatureTest extends BitcoinSJvmTest { "ScriptSignature" must "find the digital signature for the transaction inside of a p2pkh script signature" in { val scriptSig = ScriptSignature(TestUtil.rawScriptSig) scriptSig.signatures.head.hex must be( - "3045022100ad8e961fe3c22b2647d92b078f4c0cf81b3106ea5bf8b900ab8646aa4430216f022071d4edc2b5588be20ac4c2d07edd8ed069e10b2402d3dce2d3b835ccd075f28301") + "3045022100ad8e961fe3c22b2647d92b078f4c0cf81b3106ea5bf8b900ab8646aa4430216f022071d4edc2b5588be20ac4c2d07edd8ed069e10b2402d3dce2d3b835ccd075f28301" + ) } it must "derive the signature hash type from the signature" in { HashType( - ByteVector.fromByte( - TestUtil.scriptSig.signatures.head.bytes.last)) must be( - HashType.sigHashAll) + ByteVector.fromByte(TestUtil.scriptSig.signatures.head.bytes.last) + ) must be(HashType.sigHashAll) } it must "find the digital signature for a p2sh script signature" in { val scriptSig = TestUtil.p2shInputScript scriptSig.signatures.head.hex must be( - "304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f001") + "304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f001" + ) } it must "find the digital signatures for a p2sh script signature for a 2/3 p2sh address" in { @@ -46,10 +47,13 @@ class ScriptSignatureTest extends BitcoinSJvmTest { scriptSig.signatures must be( Seq( ECDigitalSignature( - "304402207d764cb90c9fd84b74d33a47cf3a0ffead9ded98333776becd6acd32c4426dac02203905a0d064e7f53d07793e86136571b6e4f700c1cfb888174e84d78638335b8101"), + "304402207d764cb90c9fd84b74d33a47cf3a0ffead9ded98333776becd6acd32c4426dac02203905a0d064e7f53d07793e86136571b6e4f700c1cfb888174e84d78638335b8101" + ), ECDigitalSignature( - "3045022100906aaca39f022acd8b7a38fd2f92aca9e9f35cfeaee69a6f13e1d083ae18222602204c9ed96fc6c4de56fd85c679fc59c16ee1ccc80c42563b86174e1a506fc007c801") - )) + "3045022100906aaca39f022acd8b7a38fd2f92aca9e9f35cfeaee69a6f13e1d083ae18222602204c9ed96fc6c4de56fd85c679fc59c16ee1ccc80c42563b86174e1a506fc007c801" + ) + ) + ) } it must "find all the digital signatures for a p2sh script signature with a large amount of sigs" in { @@ -58,34 +62,42 @@ class ScriptSignatureTest extends BitcoinSJvmTest { scriptSig.signatures must be( Seq( ECDigitalSignature( - "3045022100a077d4fe9a81411ecb796c254d8b4e0bc73ff86a42288bc3b3ecfa1ef26c00dd02202389bf96cf38c14c3a6ccb8c688339f3fd880b724322862547a8ee3b547a9df901"), + "3045022100a077d4fe9a81411ecb796c254d8b4e0bc73ff86a42288bc3b3ecfa1ef26c00dd02202389bf96cf38c14c3a6ccb8c688339f3fd880b724322862547a8ee3b547a9df901" + ), ECDigitalSignature( - "304402207c0692464998e7f3869f8501cdd25bbcd9d32b6fd34ae8aeae643b422a8dfd42022057eb16f8ca1f34e88babc9f8beb4c2521eb5c4dea41f8902a70d045f1c132a4401"), + "304402207c0692464998e7f3869f8501cdd25bbcd9d32b6fd34ae8aeae643b422a8dfd42022057eb16f8ca1f34e88babc9f8beb4c2521eb5c4dea41f8902a70d045f1c132a4401" + ), ECDigitalSignature( - "3044022024233923253c73569f4b34723a5495698bc124b099c5542a5997d13fba7d18a802203c317bddc070276c6f6c79cb3415413e608af30e4759e31b0d53eab3ca0acd4e01"), + "3044022024233923253c73569f4b34723a5495698bc124b099c5542a5997d13fba7d18a802203c317bddc070276c6f6c79cb3415413e608af30e4759e31b0d53eab3ca0acd4e01" + ), ECDigitalSignature( - "30450221009b9f0d8b945717d2fca3685093d547a3928d122b8894903ed51e2248303213bc022008b376422c9f2cd713b9d10b5b106d1c56c5893dcc01ae300253ed2234bdb63f01"), + "30450221009b9f0d8b945717d2fca3685093d547a3928d122b8894903ed51e2248303213bc022008b376422c9f2cd713b9d10b5b106d1c56c5893dcc01ae300253ed2234bdb63f01" + ), ECDigitalSignature( - "30440220257b57cb09386d82c4328461f8fe200c2f381d6b635e2a2f4ea40c8d945e9ec102201ec67d58d51a309af4d8896e9147a42944e9f9833a456f733ea5fa6954ed2fed01") - )) + "30440220257b57cb09386d82c4328461f8fe200c2f381d6b635e2a2f4ea40c8d945e9ec102201ec67d58d51a309af4d8896e9147a42944e9f9833a456f733ea5fa6954ed2fed01" + ) + ) + ) } it must "find the hash type for a p2sh script signature" in { HashType( ByteVector.fromByte( - TestUtil.p2shInputScript2Of2.signatures.head.bytes.last)) must be( - HashType.sigHashAll) + TestUtil.p2shInputScript2Of2.signatures.head.bytes.last + ) + ) must be(HashType.sigHashAll) } it must "find the digital signature and hash type for a SIGHASH_SINGLE" in { TestUtil.p2shInputScriptSigHashSingle.signatures.head.hex must be( - "3045022100dfcfafcea73d83e1c54d444a19fb30d17317f922c19e2ff92dcda65ad09cba24022001e7a805c5672c49b222c5f2f1e67bb01f87215fb69df184e7c16f66c1f87c2903") + "3045022100dfcfafcea73d83e1c54d444a19fb30d17317f922c19e2ff92dcda65ad09cba24022001e7a805c5672c49b222c5f2f1e67bb01f87215fb69df184e7c16f66c1f87c2903" + ) HashType( - TestUtil.p2shInputScriptSigHashSingle.signatures.head.bytes.last) must be( - HashType.sigHashSingle) + TestUtil.p2shInputScriptSigHashSingle.signatures.head.bytes.last + ) must be(HashType.sigHashSingle) } it must "find the hash type for the weird occurrence of hash type being 0 on the blockchain" in { - //from this tx https://btc.blockr.io/api/v1/tx/raw/c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73 + // from this tx https://btc.blockr.io/api/v1/tx/raw/c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73 val hex = "8c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5" val scriptSig: ScriptSignature = RawScriptSignatureParser.read(hex) @@ -131,24 +143,29 @@ class ScriptSignatureTest extends BitcoinSJvmTest { val output = TransactionOutput(CurrencyUnits.zero, testCase.script) val txSigComponent = testCase.transaction match { case btx: NonWitnessTransaction => - BaseTxSigComponent(btx, - testCase.inputIndex, - output, - Policy.standardFlags) + BaseTxSigComponent( + btx, + testCase.inputIndex, + output, + Policy.standardFlags + ) case wtx: WitnessTransaction => val outPoint = wtx.inputs(testCase.inputIndex.toInt).previousOutput val outputMap = PreviousOutputMap(Map(outPoint -> output)) - WitnessTxSigComponent(wtx, - inputIndex = testCase.inputIndex, - output, - outputMap, - Policy.standardFlags) + WitnessTxSigComponent( + wtx, + inputIndex = testCase.inputIndex, + output, + outputMap, + Policy.standardFlags + ) } val hashForSig = TransactionSignatureSerializer.hashForSignature( txSigComponent = txSigComponent, hashType = testCase.hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) val flipHash = BytesUtil.flipEndianness(testCase.hash.hex) hashForSig == DoubleSha256Digest(flipHash) } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptWitnessSpec.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptWitnessSpec.scala index d0fa6681fb..ea13971e46 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptWitnessSpec.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/ScriptWitnessSpec.scala @@ -24,8 +24,10 @@ class ScriptWitnessSpec extends BitcoinSUnitTest { } it must "pull script signature out of p2wsh witness" in { - forAll(ScriptGenerators.rawScriptPubKey, - ScriptGenerators.rawScriptSignature) { case ((spk, _), scriptSig) => + forAll( + ScriptGenerators.rawScriptPubKey, + ScriptGenerators.rawScriptSignature + ) { case ((spk, _), scriptSig) => assert(P2WSHWitnessV0(spk, scriptSig).scriptSignature == scriptSig) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/TaprootWitnessTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/TaprootWitnessTest.scala index 42d5634d5f..21d9ac6cad 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/TaprootWitnessTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/TaprootWitnessTest.scala @@ -9,8 +9,8 @@ class TaprootWitnessTest extends BitcoinSUnitTest { behavior of "TaprootWitness" - //from this test case in script_assets.json with this comment 'tapscript/input80limit' - //in script_assets.json + // from this test case in script_assets.json with this comment 'tapscript/input80limit' + // in script_assets.json val controlBlockHex = "c1a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a3668f9a4ccdffcf778da624dca2dd" + "a0b08e763ec52fd4ad403ec7563a3504d0cc168b9a77a410029e01dac89567c9b2e6cd726e840351df3f2f58fefe976200a19244150d04153" + @@ -32,15 +32,18 @@ class TaprootWitnessTest extends BitcoinSUnitTest { val merkleRoot = Sha256Digest.fromHex(merkleRootHex) val tapLeafHash = Sha256Digest.fromHex( - "8d76c657582b87b087f36579a9ea78816d7e2a94098bc3e3c6113ed4b6315bb4") + "8d76c657582b87b087f36579a9ea78816d7e2a94098bc3e3c6113ed4b6315bb4" + ) val taprootSPK = TaprootScriptPubKey.fromHex( - "2251201ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc") + "2251201ebe8b90363bd097aa9f352c8b21914e1886bc09fe9e70c09f33ef2d2abdf4bc" + ) val internalPubKey: XOnlyPubKey = XOnlyPubKey.fromHex( - "a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a36") + "a7957acbaaf7b444c53d9e0c9436e8a8a3247fd515095d66ddf6201918b40a36" + ) it must "compute a tap leaf hash correctly" in { - //from this test case in script_assets.json with this comment 'tapscript/input80limit' + // from this test case in script_assets.json with this comment 'tapscript/input80limit' val expected = "8d76c657582b87b087f36579a9ea78816d7e2a94098bc3e3c6113ed4b6315bb4" val asmHex = @@ -53,7 +56,7 @@ class TaprootWitnessTest extends BitcoinSUnitTest { } it must "compute a merkle root for a tapscript tree" in { - //expected from the 'compute a tap leaf hash correctly' test case referenced above + // expected from the 'compute a tap leaf hash correctly' test case referenced above val merkleRoot = TaprootScriptPath.computeTaprootMerkleRoot(controlBlock, tapLeafHash) @@ -68,9 +71,11 @@ class TaprootWitnessTest extends BitcoinSUnitTest { } it must "verify a taproot commitment" in { val result = - TaprootScriptPath.verifyTaprootCommitment(controlBlock = controlBlock, - program = taprootSPK, - tapLeafHash = tapLeafHash) + TaprootScriptPath.verifyTaprootCommitment( + controlBlock = controlBlock, + program = taprootSPK, + tapLeafHash = tapLeafHash + ) assert(result) } @@ -86,7 +91,8 @@ class TaprootWitnessTest extends BitcoinSUnitTest { val taprootScriptPath = TaprootScriptPath.fromStack(stack.reverse) assert(taprootScriptPath.annexOpt.isDefined) assert( - taprootScriptPath.annexOpt.get.toHex == "503bd07ecabe591664d9eaac4218fc1d079126033a09e6596a01778f67354f788b12777f96b42168299d453dc6eca16e3d48d7804725926c0dc735622e2a3f7fb6d7f3ac156537b9e649bf0313698d20597713d1fb11601eb658b76076ee44f3878d7ac6d984c8928bfeaac518d758e5d3affd75978f179baeb90aa8440bc7a48e0937fae42cafef7669c5cdbf0d439e511d829466debc8994b68d6f7914536f2fdc7ca88b3fd396c2da5992e9e507a74739e5bc9534000f281fde16b6a2f5e3b03aac139099536ff52649b4a7da13c4148afa7af1831f877f7b951d60a0812f790bf5739d84ef9c3e8a8655ec71237a3c93f10115d63ed2d01572991973baf6a1ef50b3f8d1d465ca54356620c5171a21054ab3bb61d349db6fbdb2b4d6e1e94ae3415fb780a8a7df4cea3ba9d9caa15c275962e7ffc6634436ba0296f7c61be9b98b19857c6f0750d366ff8f7b39fd09f2794e5414032fd93b0056326c156be4cd842c7ae446c57fa1ed6dc83e257bdf5027cf9e39011cd76c01bd1c5a57082b214e347764594752790eb649cd8ac0a3a52f47aad28254dfdb72253fd957d46ad4158daa16cd9f24add4faf73a2bd26417ebfa937681d534614f8e089d2d0aff5815ba2db4018dac77dbaa32da3ecd51e5eb05e398146d17a5db2c7470bd0b85fb5717dfc9a259b4f2e147ea666aa939acb316d5da5a9fa56f129b03dad2ba58627de562d0f04ea98c7b722130052e2dd435b0b0a6586fba4f48a5df53d6e046e80d1a11") + taprootScriptPath.annexOpt.get.toHex == "503bd07ecabe591664d9eaac4218fc1d079126033a09e6596a01778f67354f788b12777f96b42168299d453dc6eca16e3d48d7804725926c0dc735622e2a3f7fb6d7f3ac156537b9e649bf0313698d20597713d1fb11601eb658b76076ee44f3878d7ac6d984c8928bfeaac518d758e5d3affd75978f179baeb90aa8440bc7a48e0937fae42cafef7669c5cdbf0d439e511d829466debc8994b68d6f7914536f2fdc7ca88b3fd396c2da5992e9e507a74739e5bc9534000f281fde16b6a2f5e3b03aac139099536ff52649b4a7da13c4148afa7af1831f877f7b951d60a0812f790bf5739d84ef9c3e8a8655ec71237a3c93f10115d63ed2d01572991973baf6a1ef50b3f8d1d465ca54356620c5171a21054ab3bb61d349db6fbdb2b4d6e1e94ae3415fb780a8a7df4cea3ba9d9caa15c275962e7ffc6634436ba0296f7c61be9b98b19857c6f0750d366ff8f7b39fd09f2794e5414032fd93b0056326c156be4cd842c7ae446c57fa1ed6dc83e257bdf5027cf9e39011cd76c01bd1c5a57082b214e347764594752790eb649cd8ac0a3a52f47aad28254dfdb72253fd957d46ad4158daa16cd9f24add4faf73a2bd26417ebfa937681d534614f8e089d2d0aff5815ba2db4018dac77dbaa32da3ecd51e5eb05e398146d17a5db2c7470bd0b85fb5717dfc9a259b4f2e147ea666aa939acb316d5da5a9fa56f129b03dad2ba58627de562d0f04ea98c7b722130052e2dd435b0b0a6586fba4f48a5df53d6e046e80d1a11" + ) val expectedAnnexHash = { "1c0aaaf600682c151456bc3c56b49f1a28afd49344c04d88393fe589106ec22e" } @@ -96,7 +102,8 @@ class TaprootWitnessTest extends BitcoinSUnitTest { it must "construct a taproot keypath witness with an annex" in { val vec = Vector( "c2bdc23435c7bbdce741081181eecd31865f7d94fad6c49c8b1f4619aad72b83354530dbc9446243ff81e0dac2e77b2d437b9d53d279b535a23fb8c599454b3e02", - "50ba") + "50ba" + ) val stack = vec.map(ByteVector.fromValidHex(_)) val tr = TaprootWitness.fromStack(stack.reverse) assert(tr.isInstanceOf[TaprootKeyPath]) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/WitnessCommitmentTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/WitnessCommitmentTest.scala index e87559865f..253f618156 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/WitnessCommitmentTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/WitnessCommitmentTest.scala @@ -7,7 +7,7 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest */ class WitnessCommitmentTest extends BitcoinSUnitTest { - //witness commitment from https://www.blocktrail.com/tBTC/block/00000000000002f59cc8b806b2cf6bbe37a367a085de60f9e5e3386081abbb48 + // witness commitment from https://www.blocktrail.com/tBTC/block/00000000000002f59cc8b806b2cf6bbe37a367a085de60f9e5e3386081abbb48 val hex = "356a24aa21a9ed309cfb38d1015c266667d5b7888c83def872a531b8ac277fe8df623c32b562b50e6d696e65642062792062636f696e" "WitnessCommitment" must "be able to parse a witness commitment from testnet3" in { @@ -18,7 +18,8 @@ class WitnessCommitmentTest extends BitcoinSUnitTest { it must "find the correct witness root hash in a witness commitment" in { val commitment = WitnessCommitment(hex) commitment.witnessRootHash.hex must be( - "309cfb38d1015c266667d5b7888c83def872a531b8ac277fe8df623c32b562b5") + "309cfb38d1015c266667d5b7888c83def872a531b8ac277fe8df623c32b562b5" + ) } it must "serialization symmetry" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/WitnessScriptPubKeySpec.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/WitnessScriptPubKeySpec.scala index 28549fe20b..7b64aae006 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/WitnessScriptPubKeySpec.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/WitnessScriptPubKeySpec.scala @@ -36,7 +36,9 @@ class WitnessScriptPubKeySpec extends BitcoinSUnitTest { case (unassignedWitScriptPubKey, _) => assert( UnassignedWitnessScriptPubKey( - unassignedWitScriptPubKey.hex) == unassignedWitScriptPubKey) + unassignedWitScriptPubKey.hex + ) == unassignedWitScriptPubKey + ) } } @@ -45,7 +47,9 @@ class WitnessScriptPubKeySpec extends BitcoinSUnitTest { case (unassignedWitScriptPubKey, _) => assert( UnassignedWitnessScriptPubKey.fromAsm( - unassignedWitScriptPubKey.asm) == unassignedWitScriptPubKey) + unassignedWitScriptPubKey.asm + ) == unassignedWitScriptPubKey + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorChecksumTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorChecksumTest.scala index 4e44e37dfc..b755a4e994 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorChecksumTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorChecksumTest.scala @@ -10,7 +10,8 @@ class DescriptorChecksumTest extends BitcoinSUnitTest { val descriptor0 = RawDescriptor( RawScriptExpression(NonStandardScriptPubKey.fromAsmHex("deadbeef")), - None) + None + ) it must "calculate correct checksums from BIP380 examples" in { val str0 = "raw(deadbeef)#89f8spxm" val split0 = str0.split("#") @@ -19,31 +20,33 @@ class DescriptorChecksumTest extends BitcoinSUnitTest { assert(Descriptor.isValidChecksum(descriptor0, Some(checksum))) - //expression with nochecksum should be valid + // expression with nochecksum should be valid assert(Descriptor.isValidChecksum(descriptor0, None)) val descriptor1 = Descriptor.fromString( - "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)") + "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)" + ) val checksum1 = "cjjspncu" assert(Descriptor.isValidChecksum(descriptor1, Some(checksum1))) assert(Descriptor.createChecksum(descriptor1) == checksum1) } it must "fail when a bad checksum is given" in { - //Missing checksum + // Missing checksum assert(!Descriptor.isValidChecksum(descriptor0, Some("#"))) - //Too long checksum (9 chars) + // Too long checksum (9 chars) assert(!Descriptor.isValidChecksum(descriptor0, Some("89f8spxmx"))) - //Too short checksum (7 chars) + // Too short checksum (7 chars) assert(!Descriptor.isValidChecksum(descriptor0, Some("89f8spx"))) - //Error in payload + // Error in payload val bad = RawDescriptor( RawScriptExpression(NonStandardScriptPubKey.fromAsmHex("deedbeef")), - None) + None + ) assert(!Descriptor.isValidChecksum(bad, Some("89f8spxm"))) - //Error in checksum + // Error in checksum assert(!Descriptor.isValidChecksum(descriptor0, Some("#9f8spxm"))) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorTest.scala index 654fb19a20..343a800855 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorTest.scala @@ -77,7 +77,7 @@ class DescriptorTest extends BitcoinSUnitTest { val expected12 = "76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac" runTest(str12, expected12) - //invalid hardened derivation, needs to be removed from BIP381 + // invalid hardened derivation, needs to be removed from BIP381 /* val str13 = "pkh(xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/2147483647'/0)" val expected13 = "76a914ebdc90806a9c4356c1c88e42216611e1cb4c1c1788ac" @@ -132,23 +132,29 @@ class DescriptorTest extends BitcoinSUnitTest { val str3 = "wpkh([ffffffff/13']xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/1/2/*)" - val expected3 = Vector("0014326b2249e3a25d5dc60935f044ee835d090ba859", - "0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7", - "00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27") + val expected3 = Vector( + "0014326b2249e3a25d5dc60935f044ee835d090ba859", + "0014af0bd98abc2f2cae66e36896a39ffe2d32984fb7", + "00141fa798efd1cbf95cebf912c031b8a4a6e9fb9f27" + ) runDerivationTest(str3, expected3) val str4 = "sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))" - val expected4 = Vector("a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87", - "a914bed59fc0024fae941d6e20a3b44a109ae740129287", - "a9148483aa1116eb9c05c482a72bada4b1db24af654387") + val expected4 = Vector( + "a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87", + "a914bed59fc0024fae941d6e20a3b44a109ae740129287", + "a9148483aa1116eb9c05c482a72bada4b1db24af654387" + ) runDerivationTest(str4, expected4) val str5 = "sh(wpkh(xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi/10/20/30/40/*'))" - val expected5 = Vector("a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87", - "a914bed59fc0024fae941d6e20a3b44a109ae740129287", - "a9148483aa1116eb9c05c482a72bada4b1db24af654387") + val expected5 = Vector( + "a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87", + "a914bed59fc0024fae941d6e20a3b44a109ae740129287", + "a9148483aa1116eb9c05c482a72bada4b1db24af654387" + ) runDerivationTest(str5, expected5) val str6 = "wsh(pkh(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1))" @@ -453,7 +459,7 @@ class DescriptorTest extends BitcoinSUnitTest { } it must "have fidelity with the type of hardened derivation used as input" in { - //note using h instead of ' for hardened derivation path + // note using h instead of ' for hardened derivation path val str = "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)" val desc = Descriptor.fromString(str) @@ -468,7 +474,8 @@ class DescriptorTest extends BitcoinSUnitTest { @tailrec private def parseExtKeyExpression( - expression: ScriptExpression): ExtECPublicKeyExpression = { + expression: ScriptExpression + ): ExtECPublicKeyExpression = { expression match { case x: KeyExpressionScriptExpression[_] => x.source match { @@ -487,7 +494,8 @@ class DescriptorTest extends BitcoinSUnitTest { parseExtKeyExpression(x.source) case x: RawScriptExpression => sys.error( - s"RawScriptExpression cannot be used in runDerivationTest(), got=$x") + s"RawScriptExpression cannot be used in runDerivationTest(), got=$x" + ) case x: ScriptPathTreeExpression => x.source.leafs.head.source .asInstanceOf[P2PKScriptExpression[_]] @@ -499,7 +507,8 @@ class DescriptorTest extends BitcoinSUnitTest { def runDerivationTest( descriptor: String, - expectedSPKs: Vector[String]): Assertion = { + expectedSPKs: Vector[String] + ): Assertion = { val desc = ScriptDescriptor.fromString(descriptor) assert(desc.toString == descriptor) val extKeyDesc = parseExtKeyExpression(desc.expression) @@ -537,7 +546,8 @@ class DescriptorTest extends BitcoinSUnitTest { private def runMultisigDerivationTest( descriptor: String, - expectedSPKs: Vector[String]): Assertion = { + expectedSPKs: Vector[String] + ): Assertion = { val desc: ScriptDescriptor = ScriptDescriptor.fromString(descriptor) val expression: MultisigScriptExpression = desc.expression match { case m: MultisigScriptExpression => m @@ -574,7 +584,8 @@ class DescriptorTest extends BitcoinSUnitTest { (P2WSHWitnessSPKV0(multisig), P2WSHWitnessSPKV0.fromAsmHex(s)) case x => sys.error( - s"Invalid descriptor type=$x for runMultisigDerivationTest()") + s"Invalid descriptor type=$x for runMultisigDerivationTest()" + ) } } @@ -593,7 +604,8 @@ class DescriptorTest extends BitcoinSUnitTest { private def runComboTest( descriptor: String, - expectedSPKs: Vector[String]): Assertion = { + expectedSPKs: Vector[String] + ): Assertion = { val desc = ComboDescriptor.fromString(descriptor) expectedSPKs.zipWithIndex.foreach { case (s, idx) => if (idx == 0) { @@ -621,7 +633,8 @@ class DescriptorTest extends BitcoinSUnitTest { private def runComboDerivationTest( descriptor: String, - expectedSPKsNested: Vector[Vector[String]]): Assertion = { + expectedSPKsNested: Vector[Vector[String]] + ): Assertion = { val desc = ComboDescriptor.fromString(descriptor) expectedSPKsNested.zipWithIndex.foreach { case (expectedSPKs, idx) => val extKey = desc.expression.source.asInstanceOf[ExtECPublicKeyExpression] diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/KeyExpressionTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/KeyExpressionTest.scala index ecf401a33d..018aaf8cd9 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/KeyExpressionTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/descriptor/KeyExpressionTest.scala @@ -70,7 +70,7 @@ class KeyExpressionTest extends BitcoinSUnitTest { val str6 = "[deadbeef/0'/1'/2']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3/4/5/*" - //in the BIP380 test vectors, but cannot produce valid keys due to hardened derivations + // in the BIP380 test vectors, but cannot produce valid keys due to hardened derivations // val str7 = // "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/3'/4'/5'/*" @@ -87,9 +87,9 @@ class KeyExpressionTest extends BitcoinSUnitTest { assert(KeyExpression.fromString(str4).toString == str4) assert(KeyExpression.fromString(str5).toString == str5) assert(KeyExpression.fromString(str6).toString == str6) - //assert(KeyExpression.fromString(str7).toString == str7) - //assert(KeyExpression.fromString(str8).toString == str8) - //assert(KeyExpression.fromString(str9).toString == str9) + // assert(KeyExpression.fromString(str7).toString == str7) + // assert(KeyExpression.fromString(str8).toString == str8) + // assert(KeyExpression.fromString(str9).toString == str9) } it must "fail invalid key expressions in BIP380" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/script/testprotocol/SignatureHashTestCase.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/script/testprotocol/SignatureHashTestCase.scala index 999d75ddcf..739a0920a4 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/script/testprotocol/SignatureHashTestCase.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/script/testprotocol/SignatureHashTestCase.scala @@ -14,7 +14,8 @@ case class SignatureHashTestCase( inputIndex: UInt32, hashTypeNum: Int32, hashType: HashType, - hash: DoubleSha256Digest) + hash: DoubleSha256Digest +) object SignatureHashTestCase { @@ -24,7 +25,8 @@ object SignatureHashTestCase { case array: Arr => array case _: Value => throw new RuntimeException( - "Script signature hash test case must be in Arr format") + "Script signature hash test case must be in Arr format" + ) } val elements: Vector[Value] = Arr.value.toVector val transaction: Transaction = @@ -36,11 +38,13 @@ object SignatureHashTestCase { val hashType: HashType = HashType(hashTypeNum.toInt) val hash: DoubleSha256Digest = DoubleSha256Digest(elements.last.str) - SignatureHashTestCase(transaction, - script, - inputIndex, - hashTypeNum, - hashType, - hash) + SignatureHashTestCase( + transaction, + script, + inputIndex, + hashTypeNum, + hashType, + hash + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/EventDescriptorTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/EventDescriptorTest.scala index da61b3792c..f4ceaaa9e2 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/EventDescriptorTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/EventDescriptorTest.scala @@ -20,24 +20,30 @@ class EventDescriptorTest extends BitcoinSUnitTest { it must "be illegal to have num digits be zero" in { intercept[IllegalArgumentException] { - UnsignedDigitDecompositionEventDescriptor(base = UInt16(10), - numDigits = UInt16.zero, - unit = "BTC/USD", - precision = Int32.zero) + UnsignedDigitDecompositionEventDescriptor( + base = UInt16(10), + numDigits = UInt16.zero, + unit = "BTC/USD", + precision = Int32.zero + ) } intercept[IllegalArgumentException] { - SignedDigitDecompositionEventDescriptor(base = UInt16(10), - numDigits = UInt16.zero, - unit = "test_unit", - precision = Int32.zero) + SignedDigitDecompositionEventDescriptor( + base = UInt16(10), + numDigits = UInt16.zero, + unit = "test_unit", + precision = Int32.zero + ) } } it must "create a unsigned digit decomposition event" in { val descriptor = - UnsignedDigitDecompositionEventDescriptor(base = UInt16(10), - numDigits = UInt16(1), - unit = "BTC/USD", - precision = Int32.zero) + UnsignedDigitDecompositionEventDescriptor( + base = UInt16(10), + numDigits = UInt16(1), + unit = "BTC/USD", + precision = Int32.zero + ) assert(descriptor.maxNum == 9) assert(descriptor.minNum == 0) @@ -62,7 +68,9 @@ class EventDescriptorTest extends BitcoinSUnitTest { assert(expectedString2.forall(descriptor2.contains(_))) assert( Vector(0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9).forall( - descriptor2.containsPreciseOutcome(_))) + descriptor2.containsPreciseOutcome(_) + ) + ) val descriptor3 = descriptor.copy(precision = Int32.negOne, numDigits = UInt16(2)) @@ -73,7 +81,8 @@ class EventDescriptorTest extends BitcoinSUnitTest { assert(descriptor3.minToPrecision == 0.0) val expected3 = NumericRange[BigDecimal](start = 0.0, end = 10.0, step = 0.1)( - BigDecimalAsIfIntegral).toVector + BigDecimalAsIfIntegral + ).toVector assert(expected3.forall(descriptor3.containsPreciseOutcome(_))) val expectedOutcomes3: Vector[Int] = @@ -84,10 +93,12 @@ class EventDescriptorTest extends BitcoinSUnitTest { it must "create a signed digit decomposition event" in { val descriptor = - SignedDigitDecompositionEventDescriptor(base = UInt16(10), - numDigits = UInt16(1), - unit = "BTC/USD", - precision = Int32.zero) + SignedDigitDecompositionEventDescriptor( + base = UInt16(10), + numDigits = UInt16(1), + unit = "BTC/USD", + precision = Int32.zero + ) val descriptorOutcomeNums: Vector[Int] = -9.until(10).toVector @@ -98,7 +109,8 @@ class EventDescriptorTest extends BitcoinSUnitTest { val expected = NumericRange[BigDecimal](start = -0.9, end = 1.0, step = 0.1)( - BigDecimalAsIfIntegral).toVector + BigDecimalAsIfIntegral + ).toVector assert(descriptor1.maxNum == 9) assert(descriptor1.maxToPrecision == 0.9) @@ -113,7 +125,8 @@ class EventDescriptorTest extends BitcoinSUnitTest { assert(descriptor2.maxToPrecision == 0.09) val expected2 = NumericRange[BigDecimal](start = -0.09, end = 0.1, step = 0.01)( - BigDecimalAsIfIntegral).toVector + BigDecimalAsIfIntegral + ).toVector assert(expected2.forall(descriptor2.containsPreciseOutcome(_))) assert(-9.until(10).toVector.forall(descriptor2.contains(_))) @@ -125,14 +138,16 @@ class EventDescriptorTest extends BitcoinSUnitTest { assert(descriptor3.maxToPrecision == 0.99) val expected3 = NumericRange[BigDecimal](start = -0.99, end = 1, step = 0.01)( - BigDecimalAsIfIntegral).toVector + BigDecimalAsIfIntegral + ).toVector assert(expected3.forall(descriptor3.containsPreciseOutcome(_))) assert( -99 .until(100) .toVector - .forall(descriptor3.contains(_))) + .forall(descriptor3.contains(_)) + ) val descriptor4 = descriptor3.copy(numDigits = UInt16(3), precision = Int32(-1)) @@ -144,14 +159,16 @@ class EventDescriptorTest extends BitcoinSUnitTest { val expected4 = NumericRange[BigDecimal](start = -99.9, end = 100, step = 0.1)( - BigDecimalAsIfIntegral).toVector + BigDecimalAsIfIntegral + ).toVector assert(expected4.forall(descriptor4.containsPreciseOutcome(_))) assert( -999 .until(1000) .toVector - .forall(descriptor4.contains(_))) + .forall(descriptor4.contains(_)) + ) assert(!descriptor4.containsPreciseOutcome(13.55)) assert(descriptor4.containsPreciseOutcome(13.5)) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/LnMessageTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/LnMessageTest.scala index e956891ae9..ae30144c1a 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/LnMessageTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/LnMessageTest.scala @@ -28,20 +28,29 @@ class LnMessageTest extends BitcoinSUnitTest { } "InitMessage" must "parse correctly" in { - assert(Try(LnMessage( - "001000022200000302aaa2012006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f")).isSuccess) + assert( + Try( + LnMessage( + "001000022200000302aaa2012006226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" + ) + ).isSuccess + ) } - /** @see https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#appendix-c-message-extension */ + /** @see + * https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#appendix-c-message-extension + */ "InitMessage" must "pass static test vectors" in { assert(Try(LnMessageFactory(InitTLV)(hex"001000000000")).isSuccess) assert( - Try(LnMessageFactory(InitTLV)(hex"00100000000001012a030104")).isSuccess) + Try(LnMessageFactory(InitTLV)(hex"00100000000001012a030104")).isSuccess + ) assert(Try(LnMessageFactory(InitTLV)(hex"00100000000001")).isFailure) assert(Try(LnMessageFactory(InitTLV)(hex"001000000000ca012a")).isFailure) assert( - Try(LnMessageFactory(InitTLV)(hex"001000000000010101010102")).isFailure) + Try(LnMessageFactory(InitTLV)(hex"001000000000010101010102")).isFailure + ) } "ErrorMessage" must "have serialization symmetry" in { @@ -65,7 +74,9 @@ class LnMessageTest extends BitcoinSUnitTest { "PongMessage" must "parse correctly" in { assert( LnMessage("001300020000") == LnMessage( - PongTLV.forIgnored(ByteVector.fromValidHex("0000")))) + PongTLV.forIgnored(ByteVector.fromValidHex("0000")) + ) + ) } "DLCOfferMessage" must "have serialization symmetry" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/TLVTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/TLVTest.scala index a00f0413b8..fb81cd58e3 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/TLVTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/tlv/TLVTest.scala @@ -144,7 +144,9 @@ class TLVTest extends BitcoinSUnitTest { forAll(TLVGen.contractDescriptorV0TLV) { contractDescriptorV0TLV => assert( ContractDescriptorV0TLV( - contractDescriptorV0TLV.bytes) == contractDescriptorV0TLV) + contractDescriptorV0TLV.bytes + ) == contractDescriptorV0TLV + ) assert(TLV(contractDescriptorV0TLV.bytes) == contractDescriptorV0TLV) } } @@ -153,7 +155,9 @@ class TLVTest extends BitcoinSUnitTest { forAll(TLVGen.contractDescriptorV1TLV) { contractDescriptorV1TLV => assert( ContractDescriptorV1TLV( - contractDescriptorV1TLV.bytes) == contractDescriptorV1TLV) + contractDescriptorV1TLV.bytes + ) == contractDescriptorV1TLV + ) assert(TLV(contractDescriptorV1TLV.bytes) == contractDescriptorV1TLV) } } @@ -215,11 +219,11 @@ class TLVTest extends BitcoinSUnitTest { } it must "parse a contract info pre 144" in { - //this was a contract info created before we implemented support for - //https://github.com/discreetlogcontracts/dlcspecs/pull/144 + // this was a contract info created before we implemented support for + // https://github.com/discreetlogcontracts/dlcspecs/pull/144 val oldHex = "fdd82efd032500000000000186a0fda720540011fda72648000501000000000000000000000001fd9c400000000000000000000001fda604000000000000c350000001fdafc800000000000186a0000001fe0001ffff00000000000186a00000fda724020000fda712fd02bffdd824fd02b9659e890eef1b223ba45c9993f88c7997859302fd5510ac23f4cac0d4ee8232a77ecbdf50c07f093794370e6a506a836f6b0fb54b45f1fb662e1307166d2e57030574f77305826939fa9124d19bfa8a8b2f00f000586b8c58c79ee8b77969a949fdd822fd025300114762c188048a953803f0edeeeb68c69e6cdc1d371ba8d517003accfe05afc4d6588c3ea326512bc66c26a841adffa68330b8c723da442792e731fb19fda94274a7766bb48e520f118c100bbe62dc3806a8d05a63d92e23683a04b0b8c24148cd166585a6b33b995b3d6c083523a8435b156c05100d88f449f4754310d5574d5e88aad09af1b8ba942cfd305e728044ec6360d847254453ec05b1b518a36660e2238360e02f3a004663a7f3a3534973d8b66a2646c1386779aa820672b6361b88a8696395c0add87840b460dfd8a8c0d520017efc6bf58267d4c9d2a225c5d0e5719068a7dda5d630d7432239b6c9d921d5f3842b584503460ca52612ac2e64337d299513690372e8f4770eb8a28080e8d7c29920ca32af470d65d6f916ee81e3ac15ce02684ba6d2522a9ffea1de7e202b4b699ef7ec4f089dda07f3de5b7d1f853b2c56471999be4efca82674a651c80f047ba3a2b9e6f9999f0cd4062c533d1ae29cab2a5e33cbe98728b7b4271c67f7c5cd6e12e39128b9971e08496cbd84cfa99c77c88867d33e73acef37022ba4422a5221776991d45416db71fb54bc6c104f6a8e50e8905161709215104a7e7b97e866f32cf43233ffd615cab66699832ec607cf59c85a7f56fa957aa5f5d7ec9f46d84d5d4b777122d41ad76c6f4968aeedca243f2030d4f502e58f4181130e9afb75309ac21637bcfd0717528bfb82ffe1b6c9fadee6ba70357210990539184bcc913a0ec65837a736733a2fb6172d601b3900fdd80a11000200074254432f55534400000000001117626974636f696e2d732d70726963652d6578616d706c65" - //https://test.oracle.suredbits.com/contract/numeric/d4d4df2892fb2cfd2e8f030f0e69a568e19668b5d355e7713f69853db09a4c33 + // https://test.oracle.suredbits.com/contract/numeric/d4d4df2892fb2cfd2e8f030f0e69a568e19668b5d355e7713f69853db09a4c33 assert(ContractInfo.fromHexOpt(oldHex).isDefined) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionInputTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionInputTest.scala index 97c3b6c8d2..3fb1433bfe 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionInputTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionInputTest.scala @@ -43,12 +43,14 @@ class TransactionInputTest extends BitcoinSUnitTest { it must "serialize and deserialize a coinbase input" in { val c = CoinbaseInput( P2PKScriptSignature( - "4847304502210092d4e6183970b5e082d87563afbcfb3e1f38e801d89f036fd2935c394d6cc364022032b2a419e19f00b6f32f88c4427cf5e2a97f298b7d4e45efb5f723d84257ca03"), + "4847304502210092d4e6183970b5e082d87563afbcfb3e1f38e801d89f036fd2935c394d6cc364022032b2a419e19f00b6f32f88c4427cf5e2a97f298b7d4e45efb5f723d84257ca03" + ), TransactionConstants.sequence ) TransactionInput(c.previousOutput, c.scriptSignature, c.sequence) must be(c) c.hex must be( - TransactionInput(c.previousOutput, c.scriptSignature, c.sequence).hex) + TransactionInput(c.previousOutput, c.scriptSignature, c.sequence).hex + ) } it must "serialization symmetry" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionOutPointTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionOutPointTest.scala index b266c18e2c..6cf1fa5781 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionOutPointTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionOutPointTest.scala @@ -11,7 +11,8 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class TransactionOutPointTest extends BitcoinSUnitTest { "TransactionOutPoint" must "define an empty transaction outpoint" in { EmptyTransactionOutPoint.txId.hex must be( - "0000000000000000000000000000000000000000000000000000000000000000") + "0000000000000000000000000000000000000000000000000000000000000000" + ) EmptyTransactionOutPoint.vout must be(UInt32.max) } @@ -23,7 +24,8 @@ class TransactionOutPointTest extends BitcoinSUnitTest { it must "read a transaction outpoint from string" in { val txIdBE = DoubleSha256DigestBE( - "1d8a6f050746882216518afac933f5c0139e288fbdc3fea8de627b886b0d68cf") + "1d8a6f050746882216518afac933f5c0139e288fbdc3fea8de627b886b0d68cf" + ) val string = s"${txIdBE.hex}:1" val expected = TransactionOutPoint(txIdBE, UInt32.one) diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala index 163851d27b..e16eb15da6 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala @@ -49,12 +49,14 @@ class TransactionTest extends BitcoinSUnitTest { it must "derive the correct txid from the transaction contents" in { - //https://btc.blockr.io/api/v1/tx/raw/cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a + // https://btc.blockr.io/api/v1/tx/raw/cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a val tx = BaseTransaction( - "01000000020df1e23002ddf909aec026b1cf0c3b6b7943c042f22e25dbd0441855e6b39ee900000000fdfd00004730440220028c02f14654a0cc12c7e3229adb09d5d35bebb6ba1057e39adb1b2706607b0d0220564fab12c6da3d5acef332406027a7ff1cbba980175ffd880e1ba1bf40598f6b014830450221009362f8d67b60773745e983d07ba10efbe566127e244b724385b2ca2e47292dda022033def393954c320653843555ddbe7679b35cc1cacfe1dad923977de8cd6cc6d7014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53aeffffffffd11533b0f283fca193e361a91ca7ddfc66592e20fd6eaf5dc0f1ef5fed05818000000000fdfe0000483045022100b4062edd75b5b3117f28ba937ed737b10378f762d7d374afabf667180dedcc62022005d44c793a9d787197e12d5049da5e77a09046014219b31e9c6b89948f648f1701483045022100b3b0c0273fc2c531083701f723e03ea3d9111e4bbca33bdf5b175cec82dcab0802206650462db37f9b4fe78da250a3b339ab11e11d84ace8f1b7394a1f6db0960ba4014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53aeffffffff02500f1e00000000001976a9147ecaa33ef3cd6169517e43188ad3c034db091f5e88ac204e0000000000001976a914321908115d8a138942f98b0b53f86c9a1848501a88ac00000000") + "01000000020df1e23002ddf909aec026b1cf0c3b6b7943c042f22e25dbd0441855e6b39ee900000000fdfd00004730440220028c02f14654a0cc12c7e3229adb09d5d35bebb6ba1057e39adb1b2706607b0d0220564fab12c6da3d5acef332406027a7ff1cbba980175ffd880e1ba1bf40598f6b014830450221009362f8d67b60773745e983d07ba10efbe566127e244b724385b2ca2e47292dda022033def393954c320653843555ddbe7679b35cc1cacfe1dad923977de8cd6cc6d7014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53aeffffffffd11533b0f283fca193e361a91ca7ddfc66592e20fd6eaf5dc0f1ef5fed05818000000000fdfe0000483045022100b4062edd75b5b3117f28ba937ed737b10378f762d7d374afabf667180dedcc62022005d44c793a9d787197e12d5049da5e77a09046014219b31e9c6b89948f648f1701483045022100b3b0c0273fc2c531083701f723e03ea3d9111e4bbca33bdf5b175cec82dcab0802206650462db37f9b4fe78da250a3b339ab11e11d84ace8f1b7394a1f6db0960ba4014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53aeffffffff02500f1e00000000001976a9147ecaa33ef3cd6169517e43188ad3c034db091f5e88ac204e0000000000001976a914321908115d8a138942f98b0b53f86c9a1848501a88ac00000000" + ) tx.txId.flip.bytes must be( - hex"cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a") + hex"cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a" + ) } it must "have an empty transaction with the correct fields" in { @@ -62,13 +64,14 @@ class TransactionTest extends BitcoinSUnitTest { EmptyTransaction.outputs.isEmpty must be(true) EmptyTransaction.lockTime must be(TransactionConstants.lockTime) EmptyTransaction.txId.hex must be( - "0000000000000000000000000000000000000000000000000000000000000000") + "0000000000000000000000000000000000000000000000000000000000000000" + ) } it must "calculate the size of a transaction correctly" in { val rawTx = TestUtil.rawTransaction val tx = Transaction(rawTx) - //size is in bytes so divide by 2 + // size is in bytes so divide by 2 assert(tx.byteSize == tx.totalSize) tx.byteSize must be(rawTx.size / 2) } @@ -81,12 +84,12 @@ class TransactionTest extends BitcoinSUnitTest { } it must "deserialize and serialize a base transaction with no inputs" in { - //this should be considered a base transaction since there is no script witnesses - val hex = "02000000" + //version - "0001" + //0 inputs, 1 output - "00e1f50500000000" + //1BTC - "17a9148fe46e05e329badba1c390a5ea2c0ad7de2059cd87" + //spk - "00000000" //locktime + // this should be considered a base transaction since there is no script witnesses + val hex = "02000000" + // version + "0001" + // 0 inputs, 1 output + "00e1f50500000000" + // 1BTC + "17a9148fe46e05e329badba1c390a5ea2c0ad7de2059cd87" + // spk + "00000000" // locktime val btx = Transaction.fromHex(hex) btx.isInstanceOf[BaseTransaction] must be(true) btx.hex must be(hex) @@ -101,7 +104,7 @@ class TransactionTest extends BitcoinSUnitTest { } it must "calculate the correct txid and wtxid for a witness transaction" in { - //from http://tapi.qbit.ninja/tx/d869f854e1f8788bcff294cc83b280942a8c728de71eb709a2c29d10bfe21b7c + // from http://tapi.qbit.ninja/tx/d869f854e1f8788bcff294cc83b280942a8c728de71eb709a2c29d10bfe21b7c val bytes = hex"0100000000010115e180dc28a2327e687facc33f10f2a20da717e5548406f7ae8b4c811072f8560100000000ffffffff0100b4f505000000001976a9141d7cd6c75c2e86f4cbf98eaed221b30bd9a0b92888ac02483045022100df7b7e5cda14ddf91290e02ea10786e03eb11ee36ec02dd862fe9a326bbcb7fd02203f5b4496b667e6e281cc654a2da9e4f08660c620a1051337fa8965f727eb19190121038262a6c6cec93c2d3ecd6c6072efea86d02ff8e3328bbd0242b20af3425990ac00000000" val wtx = WitnessTransaction.fromBytes(bytes) @@ -114,7 +117,7 @@ class TransactionTest extends BitcoinSUnitTest { } it must "parse a witness coinbase tx correctly" in { - //txid is b3974ba615f60f48b4c558a4080810fa5064cfcb88e59b843e7fd552b3f4b3d1 on testnet + // txid is b3974ba615f60f48b4c558a4080810fa5064cfcb88e59b843e7fd552b3f4b3d1 on testnet val hex = "010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2003e02e10130e6d696e65642062792062636f696e585bd0620000000006d50200ffffffff03cddf17000000000017a9146859969825bb2787f803a3d0eeb632998ce4f50187848c3b090000000017a9146859969825bb2787f803a3d0eeb632998ce4f501870000000000000000356a24aa21a9ed309cfb38d1015c266667d5b7888c83def872a531b8ac277fe8df623c32b562b50e6d696e65642062792062636f696e0120000000000000000000000000000000000000000000000000000000000000000000000000" val tx = Transaction(hex) @@ -127,14 +130,14 @@ class TransactionTest extends BitcoinSUnitTest { } it must "calculate weight and vsize correctly" in { - //non segwit 27fd54c26042e72210eb519d631cec0fa93e676d8cf996ec5423bc7e2d14359d + // non segwit 27fd54c26042e72210eb519d631cec0fa93e676d8cf996ec5423bc7e2d14359d val hex = "0200000008c590221c1971757a12de2c65cd49f38c6cac48e59a60bb7062cb0b26fb142c7a000000006a47304402200bf1b5d42ae0b860aaf77e91bf9e0f5d95662080b462ffaeaef3fdd4528cd42e02201a400b2adc6672c77068306e063f0421731d3f4aa4b9160837a30446d4c8c12f01210321da332a698189f31e188d7b735a8871ad816ea81b375336c273e7fec5dc9c2e00000000060e343f7cba7c38b1aea0a5eb38095c6c1eb21aaa1d3de7019abea433a62f76010000006a47304402207b2ed3ac323a63cba132556f2120d0669207f661a71212cbbf2b5f89a5f2d0360220651fbf59b5b5da0452146d95fbeedaf0c91101af221b818361421aa75b562616012102fa61b8d3acbd3b1364cd48fb70b5a84bd16e8087c421169bdc458f950f95c4ae00000000ea3c63b3e9e8f8cce011d607ffcd14b83ccdf7c1fd5df02354701ecd8223e600000000006a473044022034fea16d8db904437aab1c2bc4e3874f43bbc21eea9819a805f44a38eb51401a022050f0b321e05e204c22035772f161c6a1782628d14f7ac7ce464064645e027bb2012103294607de1909df8c7c70405b661b15db23373bb01cb17cc591cf19e3e184bc70000000001559693b1207392115bcafa76dc244038b4202bdd84a25312e3a10e4f3a66cb6010000006a473044022049df75532fa7db44f166f3b3c1dca3fce882444246e4a2451a1df56805b06ebc022079f8ffc02e16cda2f5340f3ed04a7d9e53366de5ee5739989dddda155202137901210356fc739e39c3554265af065963e9d1ba4983569b0235e03734f063bb6dd7283f00000000e47ef81325dc635f3d327027842a3fd6ef8cccf8eb12fadc31f2e4ea53300d08000000006a47304402206383a91058d6ac67fb1c0f2feca6e694d32bf6ea4b1320118a3d222fe77aa89102201cc9386c5ad21a7c3a2c504b4bebe0757c4c327d554caccda51afb2c15b8ff9c012103a1f9c896e58fe1130fd99562e76eb34767c1d58e5b0535c3ac1464964cf1c74700000000414e174eed5931d7627d76a18213d234866652d0c791c41013b5439e407b8933010000006a47304402203b4db0a1888752b5fdc37ad24ad864282b13a6a898237341fc4ecbfbb88db1f202203d1e6e6ce9692a1a8a5aa72f2a11bb0f16bf149a303e0a8d4f4e042124507bb3012102f60bdfbb626916965b8c7c9b7e03300cc52afb7bec7843898b6822c4d94296c800000000a67cb436ece24d133a731ae71545bbda68518fc119a7a09f83ef65052f01df04010000006b483045022100e6dba05a228da5c44a16c7f2936e0056bd0b27106b91632d0a975ddf3d0b022a0220552605ef5936c6af9e15c6f81cda980afd088564bfb63560db572cae5baf38750121033d91b05ab07af5e58179cd26b806efe3671ab03bfde80a75f56ce4bcc5458d9800000000f424d7c0714fa8fd66049eaaec80868084343bc0e9889afc72b6debdf33498a7000000006a47304402206b48ffbca3abdcb95067949b6db6ea89f6b17deb2adea930ad512db5b1fa5f9c02204025fc165bc4c95400689b03037324358e55d69410b5b94277f004035caa58c50121036ba893997c092e90dba979b224b878e8c3c21b5fd5b737ba55d5f6a5196a4c210000000001c0860e00000000001976a914a8fc6e80e43c99e0918f8e043f0e3a48e842095088ac00000000" val tx = Transaction(hex) tx.weight must be(4884) tx.vsize must be(1221) - //segwit c586389e5e4b3acb9d6c8be1c19ae8ab2795397633176f5a6442a261bbdefc3a (sipa 3rd segwit tx) + // segwit c586389e5e4b3acb9d6c8be1c19ae8ab2795397633176f5a6442a261bbdefc3a (sipa 3rd segwit tx) val hex2 = "0200000000010140d43a99926d43eb0e619bf0b3d83b4a31f60c176beecfb9d35bf45e54d0f7420100000017160014a4b4ca48de0b3fffc15404a1acdc8dbaae226955ffffffff0100e1f5050000000017a9144a1154d50b03292b3024370901711946cb7cccc387024830450221008604ef8f6d8afa892dee0f31259b6ce02dd70c545cfcfed8148179971876c54a022076d771d6e91bed212783c9b06e0de600fab2d518fad6f15a2b191d7fbd262a3e0121039d25ab79f41f75ceaf882411fd41fa670a4c672c23ffaf0e361a969cde0692e800000000" val tx2 = WitnessTransaction(hex2) @@ -177,30 +180,36 @@ class TransactionTest extends BitcoinSUnitTest { case p2sh: P2SHScriptPubKey => tx match { case btx: NonWitnessTransaction => - BaseTxSigComponent(transaction = btx, - inputIndex = UInt32(inputIndex), - output = TransactionOutput(amount, p2sh), - flags = testCase.flags) + BaseTxSigComponent( + transaction = btx, + inputIndex = UInt32(inputIndex), + output = TransactionOutput(amount, p2sh), + flags = testCase.flags + ) case wtx: WitnessTransaction => - WitnessTxSigComponentP2SH(transaction = wtx, - inputIndex = UInt32(inputIndex), - output = - TransactionOutput(amount, p2sh), - flags = testCase.flags) + WitnessTxSigComponentP2SH( + transaction = wtx, + inputIndex = UInt32(inputIndex), + output = TransactionOutput(amount, p2sh), + flags = testCase.flags + ) } case wit: WitnessScriptPubKey => tx match { case btx: NonWitnessTransaction => - BaseTxSigComponent(transaction = btx, - inputIndex = UInt32(inputIndex), - output = TransactionOutput(amount, wit), - flags = testCase.flags) + BaseTxSigComponent( + transaction = btx, + inputIndex = UInt32(inputIndex), + output = TransactionOutput(amount, wit), + flags = testCase.flags + ) case wtx: WitnessTransaction => - WitnessTxSigComponentRaw(transaction = wtx, - inputIndex = UInt32(inputIndex), - output = - TransactionOutput(amount, wit), - flags = testCase.flags) + WitnessTxSigComponentRaw( + transaction = wtx, + inputIndex = UInt32(inputIndex), + output = TransactionOutput(amount, wit), + flags = testCase.flags + ) } case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey | _: P2PKWithTimeoutScriptPubKey | _: MultiSignatureScriptPubKey | @@ -216,7 +225,8 @@ class TransactionTest extends BitcoinSUnitTest { transaction = tx, inputIndex = UInt32(inputIndex), output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - flags = testCase.flags) + flags = testCase.flags + ) } val program = PreExecutionScriptProgram(txSigComponent) withClue(s"${testCase.raw} input index: $inputIndex") { @@ -251,28 +261,32 @@ class TransactionTest extends BitcoinSUnitTest { transaction = btx, inputIndex = UInt32(inputIndex), output = TransactionOutput(amount, scriptPubKey), - flags = testCase.flags) + flags = testCase.flags + ) case wtx: WitnessTransaction => WitnessTxSigComponentP2SH( transaction = wtx, inputIndex = UInt32(inputIndex), output = TransactionOutput(amount, scriptPubKey), - flags = testCase.flags) + flags = testCase.flags + ) } case wit: WitnessScriptPubKey => tx match { case btx: NonWitnessTransaction => - BaseTxSigComponent(transaction = btx, - inputIndex = UInt32(inputIndex), - output = - TransactionOutput(amount, wit), - flags = testCase.flags) + BaseTxSigComponent( + transaction = btx, + inputIndex = UInt32(inputIndex), + output = TransactionOutput(amount, wit), + flags = testCase.flags + ) case wtx: WitnessTransaction => - WitnessTxSigComponentRaw(transaction = wtx, - inputIndex = UInt32(inputIndex), - output = - TransactionOutput(amount, wit), - flags = testCase.flags) + WitnessTxSigComponentRaw( + transaction = wtx, + inputIndex = UInt32(inputIndex), + output = TransactionOutput(amount, wit), + flags = testCase.flags + ) } case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey | _: P2PKWithTimeoutScriptPubKey | @@ -280,17 +294,20 @@ class TransactionTest extends BitcoinSUnitTest { _: CSVScriptPubKey | _: CLTVScriptPubKey | _: ConditionalScriptPubKey | _: NonStandardScriptPubKey | _: WitnessCommitment | EmptyScriptPubKey) => - BaseTxSigComponent(transaction = tx, - inputIndex = UInt32(inputIndex), - output = TransactionOutput(amount, x), - flags = testCase.flags) + BaseTxSigComponent( + transaction = tx, + inputIndex = UInt32(inputIndex), + output = TransactionOutput(amount, x), + flags = testCase.flags + ) } case None => BaseTxSigComponent( transaction = tx, inputIndex = UInt32(inputIndex), output = TransactionOutput(CurrencyUnits.zero, scriptPubKey), - flags = testCase.flags) + flags = testCase.flags + ) } val program = PreExecutionScriptProgram(txSigComponent) ScriptInterpreter.run(program) == ScriptOk @@ -299,7 +316,7 @@ class TransactionTest extends BitcoinSUnitTest { } } withClue(testCase.raw) { - //only one input is required to be false to make the transaction invalid + // only one input is required to be false to make the transaction invalid txInputValidity.contains(false) must be(true) } } @@ -313,14 +330,19 @@ class TransactionTest extends BitcoinSUnitTest { } it must "construct a base transaction that pays to a taproot address" in { - val output = TransactionOutput(Bitcoins.one, - TransactionTestUtil.bech32mAddr.scriptPubKey) + val output = TransactionOutput( + Bitcoins.one, + TransactionTestUtil.bech32mAddr.scriptPubKey + ) val btx = BaseTransaction( TransactionConstants.validLockVersion, Vector( - TransactionInput(EmptyTransactionOutPoint, - ScriptSignature.empty, - UInt32.max)), + TransactionInput( + EmptyTransactionOutPoint, + ScriptSignature.empty, + UInt32.max + ) + ), Vector(output), TransactionConstants.lockTime ) @@ -328,12 +350,17 @@ class TransactionTest extends BitcoinSUnitTest { } it must "construct a witness transaction that pays to a taproot address" in { - val output = TransactionOutput(Bitcoins.one, - TransactionTestUtil.bech32mAddr.scriptPubKey) + val output = TransactionOutput( + Bitcoins.one, + TransactionTestUtil.bech32mAddr.scriptPubKey + ) val inputs: Vector[TransactionInput] = Vector( - TransactionInput(EmptyTransactionOutPoint, - ScriptSignature.empty, - UInt32.max)) + TransactionInput( + EmptyTransactionOutPoint, + ScriptSignature.empty, + UInt32.max + ) + ) val pubKeyWit = ECPublicKey.freshPublicKey val p2WPKHWitnessV0 = P2WPKHWitnessV0(pubKeyWit) @@ -355,7 +382,8 @@ class TransactionTest extends BitcoinSUnitTest { "014104720fcb29324a375b02b26c30cd45526dc7bdf668a59a4340f8bcf89275fafac91d0f763945373d17210650d717f5a1c465046c44c0ba2da74d6a76f61d1c370100000000" val tx = Transaction.fromHex(hex) assert( - tx.txIdBE.hex == "66cc4de192001d970244ffe32896282a1994fef80f01d35b216033aeacac1651") + tx.txIdBE.hex == "66cc4de192001d970244ffe32896282a1994fef80f01d35b216033aeacac1651" + ) assert(tx.hex == hex) } @@ -364,13 +392,14 @@ class TransactionTest extends BitcoinSUnitTest { "02000000000102d003fe1e06554e70a8e6a7026407c54f9ad1c3ca29a5486fd9825c74534cf338070000006a47304402200fa8b5e8d4b32aaf060ceb1de381d2cb9481b95591ac086f548869dabe2b625402207e347389e0a92f48c3f7fd3f4ae0e05878c7fa55584941dec3f347fa9c87ea8c0121039766e910a95b9be9b6504bfc1585c1c739a295f29099c9ee20d8fd91f58191bfffffffff22c93527a49ee479e05fb00023430f519402ee70c1d1871c5df0f896be70bb1f0000000000ffffffff02fd423800000000001976a91425ff4d7161289d9950d332a93b226abf429ff97188ac62060000000000001600144b109941eba2e10e5feb034342e9124c9edf9d310002473044022034b207e3008680ca7e3785d1a4fcbbd4f167ee8dad86a506ef886928f5072ce3022055647f8a2352e1c09fd9127fffc91c7918f90c5a8870e07760a744a4412df701012102dfac2fa93040d21e83c98f3b2d6b0a1dc95921c301118a6597e373d5ba6bc08300000000" val tx = Transaction.fromHex(hex) assert( - tx.txIdBE.hex == "e597ad88c1366e53743ac201d0156abda38cde9720b80baf7328ce9fa677772d") + tx.txIdBE.hex == "e597ad88c1366e53743ac201d0156abda38cde9720b80baf7328ce9fa677772d" + ) assert(tx.hex == hex) } it must "parse 37d5ec4bca7bd077992a6dd8679ab676a22986e63ebaf2c6ea1aebe5e5f5e817" in { - //has an invalid x coordinate in the wit v1 spk - //https://blockstream.info/tx/37d5ec4bca7bd077992a6dd8679ab676a22986e63ebaf2c6ea1aebe5e5f5e817 + // has an invalid x coordinate in the wit v1 spk + // https://blockstream.info/tx/37d5ec4bca7bd077992a6dd8679ab676a22986e63ebaf2c6ea1aebe5e5f5e817 val hex = "0100000001a76e1bb0e40d989cf3613c5b73bff552adaa09bdf79264cc0c44b968502db3be01000000fdfd000047304402200b0e9309480146ed5923a14cb3cd607facf9cf7b4f51ac9d448e0c8c3030aa5602201850641a5dd1c002e6ed9b723404a069a002608f45f77af1e3eb96e911d17afd01483045022100c7063f26164395e0ac8127b827cf6ad6a472fa8516197ef9ff565d7465b08dff022073329ded25b9559ce0dfef313ed084f9e294da47ddc814d2eab8839a8a4a9f16014c69522102b09c72ee2fa77abc24613b227d1cb6944c70af7f96711d5f1c4675daaa7554d221029787faf77569cdc59db5a34e0e9f552b9950b61d593e797ae12ac1d69eb5f98821022e9df5da07c71f7e8f5f639a28900d967714f2ae72b096c69c93fd76837b01a753aeffffffff02204e000000000000225120658204033e46a1fa8cceb84013cfe2d376ca72d5f595319497b95b08aa64a97014be00000000000017a914d06f57927ef98f7dfd25e9abdf5de65e1e7215698700000000" @@ -380,21 +409,23 @@ class TransactionTest extends BitcoinSUnitTest { } it must "parse a05213473724e2e7f489ae0cbe1d17eef4f6c1b9806e33e5115d85e71d81e994" in { - //cause of https://github.com/bitcoin-s/bitcoin-s/issues/4455 + // cause of https://github.com/bitcoin-s/bitcoin-s/issues/4455 val hex = "02000000000101df1d56ff246619d49d9f416ae742c4fc0fc247729748818cae2cd869394ff04500000000003b0000000163120000000000002200200dfe4629adca8af581bf9d8fc8384b9c2ee898a39707930017b419cf31b965d7014050795800afc8005c6d57ddb994ffa8d0e343549b4abd2ce38671cf14c92769091deee4eaa7704e84536f8e0de52789c8cc8e679d21c4ec060f5d92d51ed9562e00000000" val tx = Transaction.fromHex(hex) assert( - tx.txIdBE.hex == "a05213473724e2e7f489ae0cbe1d17eef4f6c1b9806e33e5115d85e71d81e994") + tx.txIdBE.hex == "a05213473724e2e7f489ae0cbe1d17eef4f6c1b9806e33e5115d85e71d81e994" + ) } it must "parse f6991ce32ff870ae692571764e628dec9c633bf63a7190d52fc5a0ced6c5203b" in { - //cause of https://github.com/bitcoin-s/bitcoin-s/issues/4489 + // cause of https://github.com/bitcoin-s/bitcoin-s/issues/4489 val hex = "02000000000101eb7a5073cc587ccab25b97fee2ff9c08f9461da9240ce69fcf133bacf6afdcd40000000000ffffffff0100000000000000001e6a1c53656520616e6e657821204c6f6f6b206d61206d6f72652064617461054184c66fe6dac66f09290320e31f2851b9dbe3849041f0eca2549faf92f4ae142ae7f9134b7cd4b9be97c1b26bfa6ec61c2e32b340c65c6aee8c3d1a5398f4a523014059155471452f00c6ccc869a4db103985036fe98b5d9e11b95d3fd01396e231dc791a56eee707149629df569f113263a92b9daf4336f3acd6c6f34208895ec5974420febe583fa77e49089f89b78fa8c116710715d6e40cc5f5a075ef1681550dd3c4ad20d0fa46cb883e940ac3dc5421f05b03859972639f51ed2eccbf3dc5a62e2e1b15ac41c02e44c9e47eaeb4bb313adecd11012dfad435cd72ce71f525329f24d75c5b9432774e148e9209baf3f1656a46986d5f38ddf4e20912c6ac28f48d6bf747469fb1075073656372657400000000" val tx = Transaction.fromHex(hex) assert( - tx.txIdBE.hex == "f6991ce32ff870ae692571764e628dec9c633bf63a7190d52fc5a0ced6c5203b") + tx.txIdBE.hex == "f6991ce32ff870ae692571764e628dec9c633bf63a7190d52fc5a0ced6c5203b" + ) } it must "parse 4b662a144400fa2d47d94f7380b50f299de8de541713a3efd8f79e6450640968" in { @@ -427,7 +458,7 @@ class TransactionTest extends BitcoinSUnitTest { } it must "parse 3a8dd04bc1f8179d0b85c8e1a1e89d058833ae64a9a8c3681da3ca329297beb1" in { - //from testnet + // from testnet val hex = "0100000001e2643a9a0c05870ef7acdd91dce45ab3622d7a37302b9bbe87841c1d732cc3c4000000006a473044022043b5e41451ef06608dff4293249132a4f79184729505fbbdc45a5058442c418702207fbc1302fd3aa6c5e45787e8acdc9b79e0b54c60e10f8c5ecf9f192c24ef1a570121028c15a48d980aa15a48ca50636c88cbb2b4d38c549945842fb3fde2a5725d5ec3ffffffff033069c901000000001976a914b594f541ea352015c97f26413d46a2c31c28551c88ac0c030000000000002551211c434e54525052545900000000000000000000000100000000000927c00000000052ae0c030000000000001976a914f1f57da6302ad32eecada4b144d532122dea59dd88ac00000000" val tx = Transaction.fromHex(hex) @@ -436,7 +467,8 @@ class TransactionTest extends BitcoinSUnitTest { private def findInput( tx: Transaction, - outPoint: TransactionOutPoint): Option[(TransactionInput, Int)] = { + outPoint: TransactionOutPoint + ): Option[(TransactionInput, Int)] = { tx.inputs.zipWithIndex.find { case (input, _) => input.previousOutput == outPoint } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TxUtilTest.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TxUtilTest.scala index eb227c2be6..dbabcb9ad0 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TxUtilTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TxUtilTest.scala @@ -23,13 +23,16 @@ class TxUtilTest extends BitcoinSUnitTest { TransactionInput(outPoint, EmptyScriptSignature, UInt32.zero) private val output = TransactionOutput(Bitcoins.one, EmptyScriptPubKey) - private val tx = BaseTransaction(TransactionConstants.validLockVersion, - Vector(input), - Vector(output), - UInt32.zero) + private val tx = BaseTransaction( + TransactionConstants.validLockVersion, + Vector(input), + Vector(output), + UInt32.zero + ) private val inputInfos = Vector( - EmptyInputInfo(outPoint, Bitcoins.one + Bitcoins.one)) + EmptyInputInfo(outPoint, Bitcoins.one + Bitcoins.one) + ) private val feeRate = SatoshisPerVirtualByte(Satoshis.one) it should "detect a bad fee on the tx" in { @@ -53,22 +56,28 @@ class TxUtilTest extends BitcoinSUnitTest { assert( TxUtil .sanityAmountChecks(isSigned = true, inputInfos, feeRate, highFeeTx) - .isFailure) + .isFailure + ) } it should "detect dust outputs" in { val newOutput = TransactionOutput(Satoshis(999), EmptyScriptPubKey) val ignoredOutput = - TransactionOutput(Bitcoins.one, - NonStandardScriptPubKey(Vector(OP_RETURN))) - val dustTx = BaseTransaction(tx.version, - tx.inputs, - Vector(ignoredOutput, newOutput), - tx.lockTime) + TransactionOutput( + Bitcoins.one, + NonStandardScriptPubKey(Vector(OP_RETURN)) + ) + val dustTx = BaseTransaction( + tx.version, + tx.inputs, + Vector(ignoredOutput, newOutput), + tx.lockTime + ) assert( TxUtil .sanityAmountChecks(isSigned = true, inputInfos, feeRate, dustTx) - .isFailure) + .isFailure + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/testprotocol/CoreTransactionTestCase.scala b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/testprotocol/CoreTransactionTestCase.scala index 90ca1ee7b5..b20ed48b44 100644 --- a/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/testprotocol/CoreTransactionTestCase.scala +++ b/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/testprotocol/CoreTransactionTestCase.scala @@ -12,36 +12,36 @@ import org.bitcoins.crypto.DoubleSha256Digest import ujson._ import upickle.default._ -/** Created by chris on 5/4/16. - * Used to represent the test cases found inside of tx_valid.json & tx_invalid.json - * from bitcoin core +/** Created by chris on 5/4/16. Used to represent the test cases found inside of + * tx_valid.json & tx_invalid.json from bitcoin core */ case class CoreTransactionTestCase( creditingTxsInfo: Seq[ - (TransactionOutPoint, ScriptPubKey, Option[CurrencyUnit])], + (TransactionOutPoint, ScriptPubKey, Option[CurrencyUnit]) + ], spendingTx: Transaction, flags: Seq[ScriptFlag], - raw: String) + raw: String +) object CoreTransactionTestCase { - implicit val coreTransactionTestCaseR: Reader[ - Option[CoreTransactionTestCase]] = + implicit val coreTransactionTestCaseR + : Reader[Option[CoreTransactionTestCase]] = reader[Value].map { value => val arr: Arr = value match { case array: Arr => array case _: Value => throw new RuntimeException( - "Core test case must be in the format of js array") + "Core test case must be in the format of js array" + ) } val elements: Vector[Value] = arr.value.toVector if (elements.size < 3) None else { - val creditingTxsInfo: Seq[( - TransactionOutPoint, - ScriptPubKey, - Option[CurrencyUnit])] = + val creditingTxsInfo + : Seq[(TransactionOutPoint, ScriptPubKey, Option[CurrencyUnit])] = elements.head match { case array: Arr => parseOutPointsScriptPubKeysAmount(array) case _: Value => @@ -52,15 +52,19 @@ object CoreTransactionTestCase { ScriptFlagFactory.fromList(elements(2).str) Some( - CoreTransactionTestCase(creditingTxsInfo.reverse, - spendingTx, - flags, - elements.toString)) + CoreTransactionTestCase( + creditingTxsInfo.reverse, + spendingTx, + flags, + elements.toString + ) + ) } } - private def parseOutPointsScriptPubKeysAmount(array: Arr): Seq[ - (TransactionOutPoint, ScriptPubKey, Option[CurrencyUnit])] = { + private def parseOutPointsScriptPubKeysAmount( + array: Arr + ): Seq[(TransactionOutPoint, ScriptPubKey, Option[CurrencyUnit])] = { val result = array.value.map { case array: Arr => val prevoutHashHex = @@ -86,7 +90,8 @@ object CoreTransactionTestCase { (outPoint, scriptPubKey, amount) case _: Value => throw new RuntimeException( - "All tx outpoint/scriptpubkey info must be array elements") + "All tx outpoint/scriptpubkey info must be array elements" + ) } result.toVector } diff --git a/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTSerializerTest.scala index 238b82cba0..5951969bc3 100644 --- a/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTSerializerTest.scala @@ -42,7 +42,8 @@ class PSBTSerializerTest extends BitcoinSUnitTest { it must "successfully serialize a PSBT's global data" in { val psbt = PSBT.fromBytes(validPsbts(5)) val tx = Transaction.fromBytes( - hex"02000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef13357900000000") + hex"02000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef13357900000000" + ) assert(psbt.transaction == tx) assert(psbt.inputMaps.size == tx.inputs.size && tx.inputs.size == 1) @@ -50,14 +51,16 @@ class PSBTSerializerTest extends BitcoinSUnitTest { assert( psbt.globalMap.elements.exists(record => PSBTGlobalKeyId - .fromByte(record.key.head) == PSBTGlobalKeyId.XPubKeyKeyId)) + .fromByte(record.key.head) == PSBTGlobalKeyId.XPubKeyKeyId) + ) val globalXPubs = psbt.globalMap.extendedPublicKeys assert(globalXPubs.size == 2) val xpub1 = ExtPublicKey .fromString( - "tpubDBkJeJo2X94Yq3RVz65DoUgyLUkaDrkfyrn2VcgyCRSKCRonvKvCF2FpYDGJWDkdRHBajXJGpc63GnumUt63ySvqCu2XaTRGVTKMYGuFk9H") + "tpubDBkJeJo2X94Yq3RVz65DoUgyLUkaDrkfyrn2VcgyCRSKCRonvKvCF2FpYDGJWDkdRHBajXJGpc63GnumUt63ySvqCu2XaTRGVTKMYGuFk9H" + ) val finger1 = hex"d90c6a4f" val path1 = BIP32Path.fromString("m/174'/0'") @@ -66,7 +69,8 @@ class PSBTSerializerTest extends BitcoinSUnitTest { val xpub2 = ExtPublicKey .fromString( - "tpubDBkJeJo2X94YsvtBEU1eKoibEWiNv51nW5iHhs6VZp59jsE6nen8KZMFyGHuGbCvqjRqirgeMcfpVBkttpUUT6brm4duzSGoZeTbhqCNUu6") + "tpubDBkJeJo2X94YsvtBEU1eKoibEWiNv51nW5iHhs6VZp59jsE6nen8KZMFyGHuGbCvqjRqirgeMcfpVBkttpUUT6brm4duzSGoZeTbhqCNUu6" + ) val finger2 = hex"d90c6a4f" val path2 = BIP32Path.fromString("m/174'/1'") @@ -85,9 +89,11 @@ class PSBTSerializerTest extends BitcoinSUnitTest { 2, Vector( ECPublicKey( - "029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c8871"), + "029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c8871" + ), ECPublicKey( - "03372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b") + "03372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b" + ) ) ) @@ -99,14 +105,16 @@ class PSBTSerializerTest extends BitcoinSUnitTest { assert(bip32paths.exists { path => path.pubKey == ECPublicKey( - "029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c8871") && + "029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c8871" + ) && path.masterFingerprint == hex"d90c6a4f" && path.path == BIP32Path.fromString("m/174'/0'/0") }) assert(bip32paths.exists { path => path.pubKey == ECPublicKey( - "03372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b") && + "03372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b" + ) && path.masterFingerprint == hex"d90c6a4f" && path.path == BIP32Path.fromString("m/174'/1'/0") }) @@ -130,7 +138,9 @@ class PSBTSerializerTest extends BitcoinSUnitTest { assert( bip32path.pubKey == ECPublicKey( - "039eff1f547a1d5f92dfa2ba7af6ac971a4bd03ba4a734b03156a256b8ad3a1ef9")) + "039eff1f547a1d5f92dfa2ba7af6ac971a4bd03ba4a734b03156a256b8ad3a1ef9" + ) + ) assert(bip32path.masterFingerprint == hex"ede45cc5") assert(bip32path.path == BIP32Path.fromString("m/0'/0'/1'")) } @@ -138,7 +148,8 @@ class PSBTSerializerTest extends BitcoinSUnitTest { it must "successfully serialize a PSBT with unknown types" in { val psbtWithUnknowns = PSBT.fromBytes(validPsbts(6)) val inputKey = PSBTInputKeyId.fromByte( - psbtWithUnknowns.inputMaps.head.elements.head.key.head) + psbtWithUnknowns.inputMaps.head.elements.head.key.head + ) assert(inputKey == PSBTInputKeyId.UnknownKeyId) } @@ -147,19 +158,23 @@ class PSBTSerializerTest extends BitcoinSUnitTest { val psbt = PSBT(validPsbts.head) val proofOfReservesCommitment = ProofOfReservesCommitment( - hex"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") + hex"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" + ) val inputElements = psbt.inputMaps.head.elements :+ proofOfReservesCommitment val psbtWithPoRC = - PSBT(psbt.globalMap, - psbt.inputMaps.updated(0, InputPSBTMap(inputElements)), - psbt.outputMaps) + PSBT( + psbt.globalMap, + psbt.inputMaps.updated(0, InputPSBTMap(inputElements)), + psbt.outputMaps + ) assert( psbtWithPoRC.inputMaps.head.proofOfReservesCommitmentOpt - .contains(proofOfReservesCommitment)) + .contains(proofOfReservesCommitment) + ) assert(psbtWithPoRC == PSBT(psbtWithPoRC.bytes)) } @@ -171,9 +186,11 @@ class PSBTSerializerTest extends BitcoinSUnitTest { val outputElements = psbt.outputMaps.head.elements :+ witScript val psbtWithPoRC = - PSBT(psbt.globalMap, - psbt.inputMaps, - psbt.outputMaps.updated(0, OutputPSBTMap(outputElements))) + PSBT( + psbt.globalMap, + psbt.inputMaps, + psbt.outputMaps.updated(0, OutputPSBTMap(outputElements)) + ) assert(psbtWithPoRC.outputMaps.head.witnessScriptOpt.contains(witScript)) assert(psbtWithPoRC == PSBT(psbtWithPoRC.bytes)) @@ -255,7 +272,8 @@ class PSBTSerializerTest extends BitcoinSUnitTest { it must "fail to get a record from a empty ByteVector" in { assertThrows[IllegalArgumentException]( - PSBTRecord.fromBytes(ByteVector.empty)) + PSBTRecord.fromBytes(ByteVector.empty) + ) } it must "produce an empty record" in { @@ -268,6 +286,7 @@ class PSBTSerializerTest extends BitcoinSUnitTest { it must "fail to serialize PSBT not in base64 format" in { assertThrows[IllegalArgumentException]( - PSBT.fromBase64("Never gonna give you up, never gonna let you down")) + PSBT.fromBase64("Never gonna give you up, never gonna let you down") + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTTest.scala b/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTTest.scala index 7346bc8320..6f246aa3e4 100644 --- a/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTTest.scala @@ -47,7 +47,8 @@ class PSBTTest extends BitcoinSUnitTest { val oppositeOutputs = outputs.zip(newOutputs).map { case (map, pruned) => OutputPSBTMap( - map.elements.filterNot(e => pruned.elements.contains(e))) + map.elements.filterNot(e => pruned.elements.contains(e)) + ) } val psbt2 = PSBT(oppositeGlobal, oppositeInputs, oppositeOutputs) @@ -70,8 +71,10 @@ class PSBTTest extends BitcoinSUnitTest { .addUTXOToInput(utxo.prevTransaction, index) .addSigHashTypeToInput(utxo.hashType, index) - (InputInfo.getRedeemScript(utxo.inputInfo), - InputInfo.getScriptWitness(utxo.inputInfo)) match { + ( + InputInfo.getRedeemScript(utxo.inputInfo), + InputInfo.getScriptWitness(utxo.inputInfo) + ) match { case (Some(redeemScript), Some(scriptWitness)) => partUpdatedPsbt .addRedeemOrWitnessScriptToInput(redeemScript, index) @@ -101,9 +104,11 @@ class PSBTTest extends BitcoinSUnitTest { val signedPSBT = infos.foldLeft(psbtNoSigs) { case (unsignedPSBT, (index, info)) => info.toSingles.foldLeft(unsignedPSBT) { (psbtToSign, singleInfo) => - psbtToSign.sign(index, - singleInfo.signer, - singleInfo.conditionalPath) + psbtToSign.sign( + index, + singleInfo.signer, + singleInfo.conditionalPath + ) } } val finalizedPsbtT = signedPSBT.finalizePSBT @@ -150,34 +155,37 @@ class PSBTTest extends BitcoinSUnitTest { } it must "correctly construct and finalize PSBTs from UTXOSpendingInfo" in { - forAll(CreditingTxGen.inputsAndOutputs(), - ScriptGenerators.scriptPubKey, - ChainParamsGenerator.bitcoinNetworkParams) { - case ((creditingTxsInfo, destinations), (changeSPK, _), _) => - val crediting = - creditingTxsInfo.foldLeft(0L)(_ + _.amount.satoshis.toLong) - val spending = destinations.foldLeft(0L)(_ + _.value.satoshis.toLong) - val maxFee = crediting - spending - val fee = GenUtil.sample(FeeUnitGen.feeUnit(maxFee)) + forAll( + CreditingTxGen.inputsAndOutputs(), + ScriptGenerators.scriptPubKey, + ChainParamsGenerator.bitcoinNetworkParams + ) { case ((creditingTxsInfo, destinations), (changeSPK, _), _) => + val crediting = + creditingTxsInfo.foldLeft(0L)(_ + _.amount.satoshis.toLong) + val spending = destinations.foldLeft(0L)(_ + _.value.satoshis.toLong) + val maxFee = crediting - spending + val fee = GenUtil.sample(FeeUnitGen.feeUnit(maxFee)) - val (psbt, _, _) = - PSBTGenerators.psbtAndBuilderFromInputs(finalized = false, - creditingTxsInfo = - creditingTxsInfo, - destinations = destinations, - changeSPK = changeSPK, - fee = fee) - val (expected, _, _) = - PSBTGenerators.psbtAndBuilderFromInputs(finalized = true, - creditingTxsInfo = - creditingTxsInfo, - destinations = destinations, - changeSPK = changeSPK, - fee = fee) + val (psbt, _, _) = + PSBTGenerators.psbtAndBuilderFromInputs( + finalized = false, + creditingTxsInfo = creditingTxsInfo, + destinations = destinations, + changeSPK = changeSPK, + fee = fee + ) + val (expected, _, _) = + PSBTGenerators.psbtAndBuilderFromInputs( + finalized = true, + creditingTxsInfo = creditingTxsInfo, + destinations = destinations, + changeSPK = changeSPK, + fee = fee + ) - val finalizedPsbtOpt = psbt.finalizePSBT - assert(finalizedPsbtOpt.isSuccess, psbt.hex) - assert(finalizedPsbtOpt.get == expected) + val finalizedPsbtOpt = psbt.finalizePSBT + assert(finalizedPsbtOpt.isSuccess, psbt.hex) + assert(finalizedPsbtOpt.get == expected) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTUnitTest.scala b/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTUnitTest.scala index c7fc30a7e9..a7b3085a1c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTUnitTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/psbt/PSBTUnitTest.scala @@ -27,32 +27,40 @@ class PSBTUnitTest extends BitcoinSUnitTest { it must "successfully create an empty PSBT" in { val tx = Transaction( - "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000") + "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000" + ) val emptyPsbt = PSBT.fromUnsignedTx(tx) val expectedPsbt = PSBT( - "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000") + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000" + ) assert(emptyPsbt == expectedPsbt) assert(expectedPsbt.nextRole == PSBTRole.UpdaterPSBTRole) } it must "fail to create a PSBT of an unknown version" in { - assertThrows[IllegalArgumentException](PSBT( - "70736274ff01fb040e00000001009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000")) + assertThrows[IllegalArgumentException]( + PSBT( + "70736274ff01fb040e00000001009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000" + ) + ) } it must "correctly retrieve the version of a PSBT" in { val emptyPsbt = PSBT( - "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000") + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000" + ) assert(emptyPsbt.version == UInt32.zero) val psbtWithVersion = - PSBT(GlobalPSBTMap(emptyPsbt.globalMap.elements :+ Version(UInt32(14))), - emptyPsbt.inputMaps, - emptyPsbt.outputMaps) + PSBT( + GlobalPSBTMap(emptyPsbt.globalMap.elements :+ Version(UInt32(14))), + emptyPsbt.inputMaps, + emptyPsbt.outputMaps + ) assert(psbtWithVersion.version == UInt32(14)) } @@ -60,14 +68,17 @@ class PSBTUnitTest extends BitcoinSUnitTest { it must "correctly update a PSBT" in { val start = PSBT.fromBytes( - hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000") + hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000" + ) val expected = PSBT( - hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f796500000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f796500000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) val extKey = ExtKey .fromString( - "tprv8ZgxMBicQKsPd9TeAdPADNnSyH9SSUUbTVeFszDE23Ki6TBB5nCefAdHkK8Fm3qMQR6sHwA56zqRmKmxnHk37JkiFzvncDqoKmPWubu7hDF") + "tprv8ZgxMBicQKsPd9TeAdPADNnSyH9SSUUbTVeFszDE23Ki6TBB5nCefAdHkK8Fm3qMQR6sHwA56zqRmKmxnHk37JkiFzvncDqoKmPWubu7hDF" + ) val bip32Paths = Vector( BIP32Path.fromString("m/0'/0'/0'"), @@ -85,26 +96,32 @@ class PSBTUnitTest extends BitcoinSUnitTest { val psbt = start .addUTXOToInput( Transaction( - "0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), + "0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000" + ), 0 ) .addUTXOToInput( Transaction( - "0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), + "0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000" + ), 1 ) .addRedeemOrWitnessScriptToInput( ScriptPubKey.fromAsmBytes( - hex"5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae"), + hex"5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae" + ), 0 ) .addRedeemOrWitnessScriptToInput( ScriptPubKey.fromAsmBytes( - hex"00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903"), - 1) + hex"00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903" + ), + 1 + ) .addRedeemOrWitnessScriptToInput( ScriptPubKey.fromAsmBytes( - hex"522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae"), + hex"522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae" + ), 1 ) .addKeyPathToInput(extKey, bip32Paths(0), keys(0), 0) @@ -121,7 +138,8 @@ class PSBTUnitTest extends BitcoinSUnitTest { .addSigHashTypeToInput(HashType.sigHashAll, 1) val nextExpected = PSBT( - hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000000103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000000103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) assert(psbtWithSigHash.bytes == nextExpected.bytes) assert(psbtWithSigHash.nextRole == PSBTRole.SignerPSBTRole) @@ -130,39 +148,52 @@ class PSBTUnitTest extends BitcoinSUnitTest { } it must "create a InputPSBTMap with both a NonWitness and Witness UTXO" in { - val nonWitnessOrUnknownUTXO = NonWitnessOrUnknownUTXO(Transaction( - "02000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef13357900000000")) + val nonWitnessOrUnknownUTXO = NonWitnessOrUnknownUTXO( + Transaction( + "02000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef13357900000000" + ) + ) val witnessUTXO = WitnessUTXO(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) val inputMap = InputPSBTMap(Vector(nonWitnessOrUnknownUTXO, witnessUTXO)) assert( - inputMap.bytes == hex"01005202000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef1335790000000001010901000000000000000000") + inputMap.bytes == hex"01005202000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef1335790000000001010901000000000000000000" + ) } it must "correctly filter a GlobalPSBTMap" in { val psbt = PSBT( - hex"70736274ff01009d0100000002710ea76ab45c5cb6438e607e59cc037626981805ae9e0dfd9089012abb0be5350100000000ffffffff190994d6a8b3c8c82ccbcfb2fba4106aa06639b872a8d447465c0d42588d6d670000000000ffffffff0200e1f505000000001976a914b6bc2c0ee5655a843d79afedd0ccc3f7dd64340988ac605af405000000001600141188ef8e4ce0449eaac8fb141cbf5a1176e6a088000000004f010488b21e039e530cac800000003dbc8a5c9769f031b17e77fea1518603221a18fd18f2b9a54c6c8c1ac75cbc3502f230584b155d1c7f1cd45120a653c48d650b431b67c5b2c13f27d7142037c1691027569c5031000080000000800000008000000000220202d20ca502ee289686d21815bd43a80637b0698e1fbcdbe4caed445f6c1a0a90ef1827569c50310000800000008000000080000000000400000000") + hex"70736274ff01009d0100000002710ea76ab45c5cb6438e607e59cc037626981805ae9e0dfd9089012abb0be5350100000000ffffffff190994d6a8b3c8c82ccbcfb2fba4106aa06639b872a8d447465c0d42588d6d670000000000ffffffff0200e1f505000000001976a914b6bc2c0ee5655a843d79afedd0ccc3f7dd64340988ac605af405000000001600141188ef8e4ce0449eaac8fb141cbf5a1176e6a088000000004f010488b21e039e530cac800000003dbc8a5c9769f031b17e77fea1518603221a18fd18f2b9a54c6c8c1ac75cbc3502f230584b155d1c7f1cd45120a653c48d650b431b67c5b2c13f27d7142037c1691027569c5031000080000000800000008000000000220202d20ca502ee289686d21815bd43a80637b0698e1fbcdbe4caed445f6c1a0a90ef1827569c50310000800000008000000080000000000400000000" + ) val records = psbt.globalMap.filterRecords(XPubKeyKeyId) assert(!records.exists(_.key.head == XPubKeyKeyId.byte)) - assert(GlobalPSBTMap( - records).bytes == hex"01009d0100000002710ea76ab45c5cb6438e607e59cc037626981805ae9e0dfd9089012abb0be5350100000000ffffffff190994d6a8b3c8c82ccbcfb2fba4106aa06639b872a8d447465c0d42588d6d670000000000ffffffff0200e1f505000000001976a914b6bc2c0ee5655a843d79afedd0ccc3f7dd64340988ac605af405000000001600141188ef8e4ce0449eaac8fb141cbf5a1176e6a0880000000000") + assert( + GlobalPSBTMap( + records + ).bytes == hex"01009d0100000002710ea76ab45c5cb6438e607e59cc037626981805ae9e0dfd9089012abb0be5350100000000ffffffff190994d6a8b3c8c82ccbcfb2fba4106aa06639b872a8d447465c0d42588d6d670000000000ffffffff0200e1f505000000001976a914b6bc2c0ee5655a843d79afedd0ccc3f7dd64340988ac605af405000000001600141188ef8e4ce0449eaac8fb141cbf5a1176e6a0880000000000" + ) } it must "successfully combine two PSBTs" in { // PSBT with 2 inputs, and empty outputs val expected = PSBT.fromBytes( - hex"70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffff8fc5f0af7763a570bdf3d0a55e661196e7cfa5613b260791812da3f8049990c30000000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000100df0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e13000001005301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0100e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc78700000000010416001485d13537f2e265405a34dbafa9e3dda01fb8230800220202ead596687ca806043edc3de116cdf29d5e9257c196cd055cf698c8d02bf24e9910b4a6ba670000008000000080020000800022020394f62be9df19952c5587768aeb7698061ad2c4a25c894f47d8c162b4d7213d0510b4a6ba6700000080010000800200008000") + hex"70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffff8fc5f0af7763a570bdf3d0a55e661196e7cfa5613b260791812da3f8049990c30000000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000100df0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e13000001005301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0100e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc78700000000010416001485d13537f2e265405a34dbafa9e3dda01fb8230800220202ead596687ca806043edc3de116cdf29d5e9257c196cd055cf698c8d02bf24e9910b4a6ba670000008000000080020000800022020394f62be9df19952c5587768aeb7698061ad2c4a25c894f47d8c162b4d7213d0510b4a6ba6700000080010000800200008000" + ) val psbt1 = - PSBT(expected.globalMap, - Vector(expected.inputMaps.head, InputPSBTMap(Vector.empty)), - expected.outputMaps) + PSBT( + expected.globalMap, + Vector(expected.inputMaps.head, InputPSBTMap(Vector.empty)), + expected.outputMaps + ) val psbt2 = - PSBT(expected.globalMap, - Vector(InputPSBTMap(Vector.empty), expected.inputMaps.last), - expected.outputMaps) + PSBT( + expected.globalMap, + Vector(InputPSBTMap(Vector.empty), expected.inputMaps.last), + expected.outputMaps + ) assert(psbt1.combinePSBT(psbt2) == expected) assert(psbt2.combinePSBT(psbt1) == expected) @@ -172,18 +203,22 @@ class PSBTUnitTest extends BitcoinSUnitTest { it must "successfully combine two PSBTs with unknown types" in { val psbt1 = PSBT( - "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f00") + "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f00" + ) val psbt2 = PSBT( - "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f00") + "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708100f0102030405060708090a0b0c0d0e0f00" + ) val expected = PSBT( - "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f00") + "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0a0f0102030405060708100f0102030405060708090a0b0c0d0e0f00" + ) assert(psbt1.combinePSBT(psbt2) == expected) } it must "correctly combine two GlobalPSBTMap with differing versions" in { val sharedTx = BaseTransaction( - "02000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef13357900000000") + "02000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef13357900000000" + ) val unsignedTxRecord = UnsignedTransaction(sharedTx) val version0 = Version(UInt32.zero) @@ -198,23 +233,32 @@ class PSBTUnitTest extends BitcoinSUnitTest { } it must "fail to combine two PSBTs with differing global transactions" in { - val psbt0 = PSBT.fromUnsignedTx(Transaction( - "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000")) + val psbt0 = PSBT.fromUnsignedTx( + Transaction( + "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000" + ) + ) - val psbt1 = PSBT.fromUnsignedTx(Transaction( - "02000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef13357900000000")) + val psbt1 = PSBT.fromUnsignedTx( + Transaction( + "02000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef13357900000000" + ) + ) assertThrows[IllegalArgumentException](psbt0.combinePSBT(psbt1)) assertThrows[IllegalArgumentException]( - psbt0.globalMap.combine(psbt1.globalMap)) + psbt0.globalMap.combine(psbt1.globalMap) + ) } it must "successfully extract a transaction from a finalized PSBT" in { val psbt = PSBT( - "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f796500000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f0000008000000080020000800107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f796500000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f0000008000000080020000800107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) val expected = Transaction.fromHex( - "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000") + "0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000" + ) val tx = psbt.extractTransaction assert(tx == expected) @@ -227,7 +271,8 @@ class PSBTUnitTest extends BitcoinSUnitTest { it must "finalize an already finalized input" in { val inputMap = InputPSBTMap( - "0x0100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae00") + "0x0100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae00" + ) val finalizedT = inputMap.finalize(EmptyTransactionInput) assert(finalizedT.isSuccess) assert(inputMap == finalizedT.get) @@ -242,18 +287,21 @@ class PSBTUnitTest extends BitcoinSUnitTest { it must "fail to extract a transaction from a non-finalized PSBT" in { val psbt = PSBT( - hex"70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffff8fc5f0af7763a570bdf3d0a55e661196e7cfa5613b260791812da3f8049990c30000000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000100df0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e13000001005301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0100e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc78700000000010416001485d13537f2e265405a34dbafa9e3dda01fb8230800220202ead596687ca806043edc3de116cdf29d5e9257c196cd055cf698c8d02bf24e9910b4a6ba670000008000000080020000800022020394f62be9df19952c5587768aeb7698061ad2c4a25c894f47d8c162b4d7213d0510b4a6ba6700000080010000800200008000") + hex"70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffff8fc5f0af7763a570bdf3d0a55e661196e7cfa5613b260791812da3f8049990c30000000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000100df0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e13000001005301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0100e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc78700000000010416001485d13537f2e265405a34dbafa9e3dda01fb8230800220202ead596687ca806043edc3de116cdf29d5e9257c196cd055cf698c8d02bf24e9910b4a6ba670000008000000080020000800022020394f62be9df19952c5587768aeb7698061ad2c4a25c894f47d8c162b4d7213d0510b4a6ba6700000080010000800200008000" + ) assertThrows[IllegalStateException](psbt.extractTransaction) } it must "successfully finalize a PSBT" in { val psbt = PSBT( - hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000002202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d201220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000002202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d201220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) assert(psbt.nextRole == PSBTRole.FinalizerPSBTRole) val expected = PSBT( - "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000000107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000000107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) psbt.finalizePSBT match { case Failure(exception) => fail(exception) @@ -265,21 +313,28 @@ class PSBTUnitTest extends BitcoinSUnitTest { private def getDummySigners( size: Int, - pubKey: ECPublicKey = ECPublicKey.freshPublicKey): Vector[Sign] = { + pubKey: ECPublicKey = ECPublicKey.freshPublicKey + ): Vector[Sign] = { Vector.fill(size)(Sign.dummySign(pubKey)) } it must "create a valid UTXOSpendingInfo" in { // PSBT with one P2WSH input of a 2-of-2 multisig. witnessScript, keypaths, and global xpubs are available. Contains no signatures. Outputs filled. val psbt = PSBT( - "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff05cd7e41ca0b7727e02bf505476e87858ebaa21fdb16802c7b3699d695a35e440000000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001005301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0100c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887000000000103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff05cd7e41ca0b7727e02bf505476e87858ebaa21fdb16802c7b3699d695a35e440000000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001005301000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff0100c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887000000000103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) val dummySigners = Vector( - Sign.dummySign(ECPublicKey( - "029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f")), Sign.dummySign( ECPublicKey( - "02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7")) + "029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f" + ) + ), + Sign.dummySign( + ECPublicKey( + "02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7" + ) + ) ) val spendingInfo = psbt.getSpendingInfoUsingSigners(index = 0, dummySigners) @@ -288,7 +343,9 @@ class PSBTUnitTest extends BitcoinSUnitTest { assert(spendingInfo.amount == Satoshis(50000000)) assert( spendingInfo.output.scriptPubKey == P2SHScriptPubKey( - Sha256Hash160Digest("0fb9463421696b82c833af241c78c17ddbde4934"))) + Sha256Hash160Digest("0fb9463421696b82c833af241c78c17ddbde4934") + ) + ) assert(spendingInfo.signers == dummySigners) assert(spendingInfo.hashType == HashType.sigHashAll) assert(InputInfo.getRedeemScript(spendingInfo.inputInfo).isDefined) @@ -297,25 +354,30 @@ class PSBTUnitTest extends BitcoinSUnitTest { 2, Vector( ECPublicKey( - "029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f"), + "029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f" + ), ECPublicKey( - "02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7") + "02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7" + ) ) ) assert( InputInfo .getRedeemScript(spendingInfo.inputInfo) - .get == expectedRedeemScript) + .get == expectedRedeemScript + ) assert(InputInfo.getScriptWitness(spendingInfo.inputInfo).isEmpty) assert(spendingInfo.conditionalPath == ConditionalPath.NoCondition) } it must "fail to create a valid UTXOSpendingInfo from a PSBTInputMap with insufficient data" in { val psbt1 = PSBT( - "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0000") + "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0000" + ) assertThrows[RuntimeException]( - psbt1.getSpendingInfoUsingSigners(index = 0, getDummySigners(size = 1))) + psbt1.getSpendingInfoUsingSigners(index = 0, getDummySigners(size = 1)) + ) } it must "fail to create an Unknown PSBTRecord from with a known KeyId" in { @@ -331,44 +393,53 @@ class PSBTUnitTest extends BitcoinSUnitTest { // Test case given in https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors it must "sign a PSBT" in { val unsignedPsbt = PSBT( - hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000000103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000000103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) assert(unsignedPsbt.nextRole == PSBTRole.SignerPSBTRole) val privKey0 = ECPrivateKeyUtil .fromWIFToPrivateKey( - "cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr") + "cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr" + ) .toPrivateKey val privKey1 = ECPrivateKeyUtil .fromWIFToPrivateKey( - "cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d") + "cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d" + ) .toPrivateKey // BCrypto does not use low r signing val (expectedPsbt0, expectedPsbt1) = CryptoUtil.cryptoContext match { case CryptoContext.LibSecp256k1 | CryptoContext.BouncyCastle => val psbt0 = PSBT( - hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) val psbt1 = PSBT( - hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d74730440220631a989fe738a92ad01986023312c19214fe2802b39e5cbc1ac3678806c692c3022039db6c387bd267716dfdb3d4d8da50b8e85d213326ba7c7daaa4c0ce41eb922301010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000002202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d74730440220631a989fe738a92ad01986023312c19214fe2802b39e5cbc1ac3678806c692c3022039db6c387bd267716dfdb3d4d8da50b8e85d213326ba7c7daaa4c0ce41eb922301010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000002202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) (psbt0, psbt1) case CryptoContext.BCrypto => val psbt0 = PSBT( - hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) val psbt1 = PSBT( - hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000002202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000") + hex"70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f000000800000008001000080000100f80200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f79650000002202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000" + ) (psbt0, psbt1) } val privKey2 = ECPrivateKeyUtil .fromWIFToPrivateKey( - "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au") + "cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au" + ) .toPrivateKey val privKey3 = ECPrivateKeyUtil .fromWIFToPrivateKey( - "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE") + "cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE" + ) .toPrivateKey val expectedPubKeyHashes = @@ -415,7 +486,8 @@ class PSBTUnitTest extends BitcoinSUnitTest { val input = TransactionInput( outPoint = TransactionOutPoint(txId = tx.txId, vout = UInt32.zero), scriptSignature = EmptyScriptSignature, - sequenceNumber = UInt32.zero) + sequenceNumber = UInt32.zero + ) val compressedInputMap = inputMap.compressMap(input) @@ -425,7 +497,8 @@ class PSBTUnitTest extends BitcoinSUnitTest { it must "do nothing when compressing a finalized InputPSBTMap" in { val finalizedInputMap = InputPSBTMap( - Vector(InputPSBTRecord.FinalizedScriptSig(EmptyScriptSignature))) + Vector(InputPSBTRecord.FinalizedScriptSig(EmptyScriptSignature)) + ) val compressedInputMap = finalizedInputMap.compressMap(EmptyTransactionInput) @@ -436,10 +509,15 @@ class PSBTUnitTest extends BitcoinSUnitTest { it must "be able to filter OutputPSBTMap records" in { val redeemScriptRecord = OutputPSBTRecord.RedeemScript(EmptyScriptPubKey) val outputMap = OutputPSBTMap( - Vector(redeemScriptRecord, - OutputPSBTRecord.BIP32DerivationPath(ECPublicKey.freshPublicKey, - ExtKey.masterFingerprint, - BIP32Path.empty))) + Vector( + redeemScriptRecord, + OutputPSBTRecord.BIP32DerivationPath( + ECPublicKey.freshPublicKey, + ExtKey.masterFingerprint, + BIP32Path.empty + ) + ) + ) val expectedElements = Vector(redeemScriptRecord) @@ -453,7 +531,8 @@ class PSBTUnitTest extends BitcoinSUnitTest { val psbt = dummyPSBT() val finalizedInputMap = InputPSBTMap( - Vector(InputPSBTRecord.FinalizedScriptSig(EmptyScriptSignature))) + Vector(InputPSBTRecord.FinalizedScriptSig(EmptyScriptSignature)) + ) val finalizedPSBT = PSBT(psbt.globalMap, Vector(finalizedInputMap), psbt.outputMaps) @@ -473,30 +552,41 @@ class PSBTUnitTest extends BitcoinSUnitTest { val psbtP2SH = dummyPSBT(spk = p2sh) assertThrows[IllegalArgumentException]( - psbtP2WSH.addRedeemOrWitnessScriptToOutput(script = badRedeemScript, - index = 0)) + psbtP2WSH.addRedeemOrWitnessScriptToOutput( + script = badRedeemScript, + index = 0 + ) + ) assertThrows[IllegalArgumentException]( - psbtP2SH.addRedeemOrWitnessScriptToOutput(script = badRedeemScript, - index = 0)) + psbtP2SH.addRedeemOrWitnessScriptToOutput( + script = badRedeemScript, + index = 0 + ) + ) } it must "fail to add an EmptyScriptWitness to an input" in { val psbt = dummyPSBT() assertThrows[IllegalArgumentException]( - psbt.addScriptWitnessToInput(EmptyScriptWitness, index = 0)) + psbt.addScriptWitnessToInput(EmptyScriptWitness, index = 0) + ) } it must "fail to addRedeemOrWitnessScriptToOutput when finalized" in { val psbt = dummyPSBT() val finalizedInputMap = InputPSBTMap( - Vector(InputPSBTRecord.FinalizedScriptSig(EmptyScriptSignature))) + Vector(InputPSBTRecord.FinalizedScriptSig(EmptyScriptSignature)) + ) val finalizedPsbt = PSBT(psbt.globalMap, Vector(finalizedInputMap), psbt.outputMaps) assertThrows[IllegalArgumentException]( - finalizedPsbt.addRedeemOrWitnessScriptToOutput(EmptyScriptPubKey, - index = 0)) + finalizedPsbt.addRedeemOrWitnessScriptToOutput( + EmptyScriptPubKey, + index = 0 + ) + ) } it must "addScriptWitnessToOutput correctly" in { @@ -504,13 +594,17 @@ class PSBTUnitTest extends BitcoinSUnitTest { val p2wshWitness = P2WSHWitnessV0(EmptyScriptPubKey) assertThrows[IllegalArgumentException]( - psbt.addScriptWitnessToOutput(p2wshWitness, index = -1)) + psbt.addScriptWitnessToOutput(p2wshWitness, index = -1) + ) assertThrows[IllegalArgumentException]( - psbt.addScriptWitnessToOutput(p2wshWitness, index = 1)) + psbt.addScriptWitnessToOutput(p2wshWitness, index = 1) + ) val p2wpkhPSBT = - psbt.addScriptWitnessToOutput(P2WPKHWitnessV0(ECPublicKey.freshPublicKey), - index = 0) + psbt.addScriptWitnessToOutput( + P2WPKHWitnessV0(ECPublicKey.freshPublicKey), + index = 0 + ) assert(p2wpkhPSBT == psbt) val p2wshPSBT = psbt.addScriptWitnessToOutput(p2wshWitness, index = 0) @@ -520,28 +614,34 @@ class PSBTUnitTest extends BitcoinSUnitTest { PSBT(psbt.globalMap, psbt.inputMaps, Vector(expectedOutputMap)) assert(p2wshPSBT == expectedPSBT) assertThrows[IllegalArgumentException]( - p2wshPSBT.addScriptWitnessToOutput(p2wshWitness, index = 0)) + p2wshPSBT.addScriptWitnessToOutput(p2wshWitness, index = 0) + ) assertThrows[IllegalArgumentException]( - psbt.addScriptWitnessToOutput(EmptyScriptWitness, index = 0)) + psbt.addScriptWitnessToOutput(EmptyScriptWitness, index = 0) + ) val finalizedInputMap = InputPSBTMap( - Vector(InputPSBTRecord.FinalizedScriptSig(EmptyScriptSignature))) + Vector(InputPSBTRecord.FinalizedScriptSig(EmptyScriptSignature)) + ) val finalizedPsbt = PSBT(psbt.globalMap, Vector(finalizedInputMap), psbt.outputMaps) assertThrows[IllegalArgumentException]( - finalizedPsbt.addScriptWitnessToOutput(p2wshWitness, index = 0)) + finalizedPsbt.addScriptWitnessToOutput(p2wshWitness, index = 0) + ) } it must "verify PSBT segwit inputs correctly without WitnessUTXO" in { val psbt = PSBT( - "70736274ff0100c50200000002a24b1b49ea1254b012a9c3df19b2d6402c308551fbc1c18bad0fef1a124f2dde0000000000ffffffff1a0219a04c444997abc3c7be01959456a1f81d200536a5f891666759bd2a627d0000000000ffffffff03a9c2eb0b00000000220020678c17924488e698d2b68bb423eb8e9af4887b572013704729ed41a4ec6592d52ee0f50500000000160014aca7c242226afe7ab436cf2bd060f516031cfb3f2ee0f50500000000160014d1bce3d788eb843a277fb693dd1822d8dfadc15900000000000001002902000000000100c2eb0b000000001600147e94acc71e93c253f9644394a9d3cfc83f6723b10000000001070001086b0247304402207364ea96d6ef6415e7a742f0c957cf6a3ddce787d5707abdcf1d7f806c80d06a02201dbbab252279de1b19ec85d652fdcfc162551980f19847dceae7fd8a59bc87570121035c32b574250d7e084fa920f8891c7016f2788dd7518ccb85b3f0ba6474a22c9600000000") + "70736274ff0100c50200000002a24b1b49ea1254b012a9c3df19b2d6402c308551fbc1c18bad0fef1a124f2dde0000000000ffffffff1a0219a04c444997abc3c7be01959456a1f81d200536a5f891666759bd2a627d0000000000ffffffff03a9c2eb0b00000000220020678c17924488e698d2b68bb423eb8e9af4887b572013704729ed41a4ec6592d52ee0f50500000000160014aca7c242226afe7ab436cf2bd060f516031cfb3f2ee0f50500000000160014d1bce3d788eb843a277fb693dd1822d8dfadc15900000000000001002902000000000100c2eb0b000000001600147e94acc71e93c253f9644394a9d3cfc83f6723b10000000001070001086b0247304402207364ea96d6ef6415e7a742f0c957cf6a3ddce787d5707abdcf1d7f806c80d06a02201dbbab252279de1b19ec85d652fdcfc162551980f19847dceae7fd8a59bc87570121035c32b574250d7e084fa920f8891c7016f2788dd7518ccb85b3f0ba6474a22c9600000000" + ) assert(psbt.verifyFinalizedInput(1)) } it must "verify PSBT p2sh(segwit) inputs correctly without WitnessUTXO" in { val psbt = PSBT( - "70736274ff01005502000000010e43b32dc23232b9c74bb0d4b940e6242c8acc875f41a6e4f6063e99dcbe4eda0000000000000000000180f0fa02000000001976a9149d936768e7338f716548af87b61ad83b80ea422188ac000000000001002a02000000000100e1f5050000000017a914e9b5fdcca093fde8d0424238a517034664c4715a8700000000010717160014cbcdc27013a54990a8e468dbdabf95166ca614e701086b024730440220489caebd034c1c1caf869d1463543248d78b9c8fde4cdd6044220c123ba9489c022007214b4ac24f5b4e278172b8af2fed27990fb10fa1961b3288dd0fc9226ef05d012102b38f6ec85730be3e8fa5a0da221209781de35c2e572e82f2d707e7b67be1b9c20000") + "70736274ff01005502000000010e43b32dc23232b9c74bb0d4b940e6242c8acc875f41a6e4f6063e99dcbe4eda0000000000000000000180f0fa02000000001976a9149d936768e7338f716548af87b61ad83b80ea422188ac000000000001002a02000000000100e1f5050000000017a914e9b5fdcca093fde8d0424238a517034664c4715a8700000000010717160014cbcdc27013a54990a8e468dbdabf95166ca614e701086b024730440220489caebd034c1c1caf869d1463543248d78b9c8fde4cdd6044220c123ba9489c022007214b4ac24f5b4e278172b8af2fed27990fb10fa1961b3288dd0fc9226ef05d012102b38f6ec85730be3e8fa5a0da221209781de35c2e572e82f2d707e7b67be1b9c20000" + ) assert(psbt.verifyFinalizedInput(0)) } @@ -565,7 +665,8 @@ class PSBTUnitTest extends BitcoinSUnitTest { assert( withUtxo.inputMaps.head.nonWitnessOrUnknownUTXOOpt .map(_.transactionSpent) - .contains(utxoTx)) + .contains(utxoTx) + ) } // -- BIP 371 tests -- diff --git a/core-test/src/test/scala/org/bitcoins/core/script/ScriptProgramFactoryTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/ScriptProgramFactoryTest.scala index e77caa1fb0..52cb26c86a 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/ScriptProgramFactoryTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/ScriptProgramFactoryTest.scala @@ -62,7 +62,8 @@ class ScriptProgramFactoryTest extends BitcoinSUnitTest { transaction = TestUtil.transaction, inputIndex = UInt32.zero, output = TransactionOutput(CurrencyUnits.zero, TestUtil.scriptPubKey), - ScriptFlagFactory.empty) + ScriptFlagFactory.empty + ) val inProgress = ExecutionInProgressScriptProgram( diff --git a/core-test/src/test/scala/org/bitcoins/core/script/ScriptProgramTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/ScriptProgramTest.scala index e845a9452a..b328eace54 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/ScriptProgramTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/ScriptProgramTest.scala @@ -12,8 +12,10 @@ class ScriptProgramTest extends BitcoinSUnitTest { val stack = List(ScriptNumber(1)) val script = List() val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) program.stackTopIsTrue must be(true) } @@ -21,14 +23,16 @@ class ScriptProgramTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List() val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) program.stackTopIsTrue must be(false) val program2 = program.updateStack(List(OP_0)) program2.stackTopIsTrue must be(false) - //stack top should not be true for negative zero + // stack top should not be true for negative zero val program3 = program.updateStack(List(ScriptNumber.negativeZero)) program3.stackTopIsTrue must be(false) } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/arithmetic/ArithmeticInterpreterTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/arithmetic/ArithmeticInterpreterTest.scala index 4ef12594e9..9c47c217ef 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/arithmetic/ArithmeticInterpreterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/arithmetic/ArithmeticInterpreterTest.scala @@ -22,8 +22,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.one, ScriptNumber(2)) val script = List(OP_ADD) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opAdd(program) newProgram.stack.head must be(ScriptNumber(3)) newProgram.script.isEmpty must be(true) @@ -33,8 +35,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List(OP_1ADD) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.op1Add(program) newProgram.stack.head must be(ScriptNumber.one) @@ -46,8 +50,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_1ADD) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(AI.op1Add(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -58,8 +64,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List(OP_1SUB) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.op1Sub(program) newProgram.stack.head must be(ScriptNumber(-1)) @@ -71,8 +79,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_1SUB) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(AI.op1Sub(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -82,8 +92,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.one, ScriptNumber.zero) val script = List(OP_SUB) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opSub(program) newProgram.stack.head must be(ScriptNumber(-1)) @@ -94,8 +106,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_SUB) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(AI.opSub(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -105,8 +119,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber(-1)) val script = List(OP_ABS) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opAbs(program) newProgram.stack.head must be(ScriptNumber.one) @@ -117,8 +133,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List(OP_ABS) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opAbs(program) newProgram.stack.head must be(ScriptNumber.zero) @@ -128,8 +146,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_ABS) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(AI.opAbs(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -139,8 +159,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List(OP_NEGATE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNegate(program) newProgram.stack.head must be(ScriptNumber.zero) @@ -151,8 +173,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.one) val script = List(OP_NEGATE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNegate(program) newProgram.stack.head must be(ScriptNumber(-1)) @@ -163,8 +187,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber(-1)) val script = List(OP_NEGATE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNegate(program) newProgram.stack.head must be(ScriptNumber.one) @@ -175,8 +201,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_NEGATE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(AI.opNegate(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -186,8 +214,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List(OP_NOT) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNot(program) newProgram.stackTopIsTrue must be(true) @@ -199,8 +229,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.one) val script = List(OP_NOT) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNot(program) newProgram.stackTopIsFalse must be(true) @@ -212,8 +244,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List(OP_0NOTEQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.op0NotEqual(program) newProgram.stack.head must be(OP_FALSE) @@ -224,8 +258,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.one) val script = List(OP_0NOTEQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.op0NotEqual(program) newProgram.stack.head must be(OP_TRUE) @@ -236,8 +272,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.zero) val script = List(OP_BOOLAND) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opBoolAnd(program) newProgram.stackTopIsFalse must be(true) @@ -255,8 +293,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, OP_1) val script = List(OP_BOOLAND) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opBoolAnd(program) newProgram.stackTopIsTrue must be(false) @@ -268,8 +308,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.one, ScriptNumber.one) val script = List(OP_BOOLOR) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opBoolOr(program) newProgram.stack.head must be(OP_TRUE) @@ -280,8 +322,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.zero) val script = List(OP_BOOLOR) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opBoolOr(program) newProgram.stack.head must be(OP_FALSE) @@ -292,8 +336,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.one) val script = List(OP_BOOLOR) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opBoolOr(program) newProgram.stack.head must be(OP_TRUE) @@ -304,8 +350,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.zero) val script = List(OP_NUMEQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNumEqual(program) newProgram.stackTopIsTrue must be(true) @@ -317,8 +365,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.zero) val script = List(OP_NUMEQUALVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNumEqualVerify(program) newProgram.isInstanceOf[ExecutionInProgressScriptProgram] must be(true) newProgram.stack.isEmpty must be(true) @@ -328,32 +378,40 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.one) val script = List(OP_NUMEQUALVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNumEqualVerify(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorVerify)) + Some(ScriptErrorVerify) + ) } it must "mark the script as invalid for OP_NUMEQAULVERIFY without two stack elements" in { val stack = List(ScriptNumber.zero) val script = List(OP_NUMEQUALVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNumEqualVerify(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "evaluate an OP_NUMNOTEQUAL for two numbers that are the same" in { val stack = List(ScriptNumber.zero, ScriptNumber.zero) val script = List(OP_NUMNOTEQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNumNotEqual(program) newProgram.stack.head must be(OP_FALSE) @@ -364,8 +422,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.one) val script = List(OP_NUMNOTEQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opNumNotEqual(program) newProgram.stack.head must be(OP_TRUE) @@ -376,8 +436,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.one) val script = List(OP_LESSTHAN) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opLessThan(program) newProgram.stack.head must be(OP_FALSE) @@ -387,8 +449,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val script1 = List(OP_LESSTHAN) TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, script) val program1 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack1, - script1) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack1, + script1 + ) val newProgram1 = AI.opLessThan(program1) newProgram1.stack.head must be(OP_FALSE) @@ -397,8 +461,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack2 = List(ScriptNumber.one, ScriptNumber.zero) val script2 = List(OP_LESSTHAN) val program2 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack2, - script2) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack2, + script2 + ) val newProgram2 = AI.opLessThan(program2) newProgram2.stack.head must be(OP_TRUE) @@ -409,8 +475,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.one) val script = List(OP_LESSTHANOREQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opLessThanOrEqual(program) newProgram.stack.head must be(OP_FALSE) @@ -420,8 +488,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val script1 = List(OP_LESSTHANOREQUAL) TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, script) val program1 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack1, - script1) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack1, + script1 + ) val newProgram1 = AI.opLessThanOrEqual(program1) newProgram1.stack.head must be(OP_TRUE) @@ -430,8 +500,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack2 = List(ScriptNumber.one, ScriptNumber.zero) val script2 = List(OP_LESSTHANOREQUAL) val program2 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack2, - script2) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack2, + script2 + ) val newProgram2 = AI.opLessThanOrEqual(program2) newProgram2.stack.head must be(OP_TRUE) @@ -442,8 +514,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.one) val script = List(OP_GREATERTHAN) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opGreaterThan(program) newProgram.stack.head must be(OP_TRUE) @@ -452,8 +526,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack1 = List(ScriptNumber.zero, ScriptNumber.zero) val script1 = List(OP_GREATERTHAN) val program1 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack1, - script1) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack1, + script1 + ) val newProgram1 = AI.opGreaterThan(program1) newProgram1.stack.head must be(OP_FALSE) @@ -462,8 +538,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack2 = List(ScriptNumber.one, ScriptNumber.zero) val script2 = List(OP_GREATERTHAN) val program2 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack2, - script2) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack2, + script2 + ) val newProgram2 = AI.opGreaterThan(program2) newProgram2.stack.head must be(OP_FALSE) @@ -474,8 +552,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.one) val script = List(OP_GREATERTHANOREQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opGreaterThanOrEqual(program) newProgram.stack.head must be(OP_TRUE) @@ -484,8 +564,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack1 = List(ScriptNumber.zero, ScriptNumber.zero) val script1 = List(OP_GREATERTHANOREQUAL) val program1 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack1, - script1) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack1, + script1 + ) val newProgram1 = AI.opGreaterThanOrEqual(program1) newProgram1.stack.head must be(OP_TRUE) @@ -494,8 +576,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack2 = List(ScriptNumber.one, ScriptNumber.zero) val script2 = List(OP_GREATERTHANOREQUAL) val program2 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack2, - script2) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack2, + script2 + ) val newProgram2 = AI.opGreaterThanOrEqual(program2) newProgram2.stack.head must be(OP_FALSE) @@ -506,8 +590,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero, ScriptNumber.one) val script = List(OP_MIN) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opMin(program) newProgram.stack must be(List(ScriptNumber.zero)) @@ -517,21 +603,26 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List(OP_MIN) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opMin(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "evaluate an OP_MAX correctly" in { val stack = List(ScriptNumber.zero, ScriptNumber.one) val script = List(OP_MAX) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opMax(program) newProgram.stack must be(List(ScriptNumber.one)) @@ -541,13 +632,16 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List(OP_MAX) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opMax(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "evaluate an OP_WITHIN correctly" in { @@ -574,12 +668,15 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber("00"), ScriptNumber.one, ScriptNumber.one) val script = List(OP_WITHIN) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opWithin(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorUnknownError)) + Some(ScriptErrorUnknownError) + ) } it must "mark the script as invalid for OP_WITHIN if one of the numbers is larger than 4 bytes" in { @@ -592,7 +689,8 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val newProgram = AI.opWithin(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorUnknownError)) + Some(ScriptErrorUnknownError) + ) } it must "mark the script as invalid for OP_WITHIN if we do not have 3 stack elements" in { @@ -604,7 +702,8 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val newProgram = AI.opWithin(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "interpret two script constants as numbers and then add them" in { @@ -613,8 +712,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(scriptConstant1, scriptConstant2) val script = List(OP_ADD) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = AI.opAdd(program) newProgram.stack must be(List(ScriptNumber.zero)) newProgram.script.isEmpty must be(true) @@ -624,8 +725,10 @@ class ArithmeticInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List() val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) Try(AI.opAdd(program)).isFailure must be(true) Try(AI.op1Add(program)).isFailure must be(true) Try(AI.op1Sub(program)).isFailure must be(true) diff --git a/core-test/src/test/scala/org/bitcoins/core/script/bitwise/BitwiseInterpreterTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/bitwise/BitwiseInterpreterTest.scala index 9a44f67115..25b4bbce79 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/bitwise/BitwiseInterpreterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/bitwise/BitwiseInterpreterTest.scala @@ -11,14 +11,17 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class BitwiseInterpreterTest extends BitcoinSUnitTest { private val pubKeyHash = ScriptConstant( - "5238C71458E464D9FF90299ABCA4A1D7B9CB76AB".toLowerCase) + "5238C71458E464D9FF90299ABCA4A1D7B9CB76AB".toLowerCase + ) val BI = BitwiseInterpreter "BitwiseInterpreter" must "evaluate OP_EQUAL" in { val stack = List(pubKeyHash, pubKeyHash) val script = List(OP_EQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = BI.opEqual(program) newProgram.stack.head must be(OP_TRUE) } @@ -27,8 +30,10 @@ class BitwiseInterpreterTest extends BitcoinSUnitTest { val stack = List(OP_1, OP_TRUE) val script = List(OP_EQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = BI.opEqual(program) newProgram.stack.head must be(OP_TRUE) } @@ -36,16 +41,18 @@ class BitwiseInterpreterTest extends BitcoinSUnitTest { it must "throw an exception for OP_EQUAL when we don't have enough items on the stack" in { intercept[IllegalArgumentException] { BI.opEqual( - TestUtil.testProgramExecutionInProgress.updateStackAndScript(List(), - List())) + TestUtil.testProgramExecutionInProgress + .updateStackAndScript(List(), List()) + ) } } it must "throw an exception for OP_EQUAL when we don't have enough items on the script stack" in { intercept[IllegalArgumentException] { BI.opEqual( - TestUtil.testProgramExecutionInProgress.updateStackAndScript(List(), - List())) + TestUtil.testProgramExecutionInProgress + .updateStackAndScript(List(), List()) + ) } } @@ -53,10 +60,12 @@ class BitwiseInterpreterTest extends BitcoinSUnitTest { val stack = List(pubKeyHash, pubKeyHash) val script = List(OP_EQUALVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val result = BI.opEqualVerify(program) - //if verification fails it will transform the script to a ExecutedProgram with an error set + // if verification fails it will transform the script to a ExecutedProgram with an error set result.isInstanceOf[ExecutedScriptProgram] must be(false) } @@ -65,8 +74,10 @@ class BitwiseInterpreterTest extends BitcoinSUnitTest { val stack = List(pubKeyHash, uniquePubKey) val script = List(OP_EQUALVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val result = BI.opEqualVerify(program) result.stackTopIsTrue must be(false) } @@ -75,15 +86,19 @@ class BitwiseInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber(2), ScriptConstant("02")) val script = List(OP_EQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) BI.opEqual(program).stack.head must be(OP_TRUE) val stack1 = List(ScriptConstant("02"), ScriptNumber(2)) val script1 = List(OP_EQUAL) val program1 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack1, - script1) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack1, + script1 + ) BI.opEqual(program1).stack.head must be(OP_TRUE) } @@ -91,8 +106,10 @@ class BitwiseInterpreterTest extends BitcoinSUnitTest { val stack = List(OP_0, ScriptNumber.zero) val script = List(OP_EQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) BI.opEqual(program).stack.head must be(OP_TRUE) } @@ -100,11 +117,14 @@ class BitwiseInterpreterTest extends BitcoinSUnitTest { val stack = List(OP_0) val script = List(OP_EQUALVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = BI.opEqualVerify(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/bitwise/BitwiseOperationsFactoryTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/bitwise/BitwiseOperationsFactoryTest.scala index d7d10cb35f..a4760d5ebb 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/bitwise/BitwiseOperationsFactoryTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/bitwise/BitwiseOperationsFactoryTest.scala @@ -9,7 +9,8 @@ class BitwiseOperationsFactoryTest extends BitcoinSUnitTest { "BitwiseOperationsFactory" must "match strings with bitwise operations" in { BitwiseOperation.fromStringOpt("OP_EQUAL") must be(Some(OP_EQUAL)) BitwiseOperation.fromStringOpt("OP_EQUALVERIFY") must be( - Some(OP_EQUALVERIFY)) + Some(OP_EQUALVERIFY) + ) BitwiseOperation.fromStringOpt("RANDOM") must be(None) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/constant/BytesToPushOntoStackFactoryTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/constant/BytesToPushOntoStackFactoryTest.scala index 37fab5418c..dea444d89f 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/constant/BytesToPushOntoStackFactoryTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/constant/BytesToPushOntoStackFactoryTest.scala @@ -8,9 +8,11 @@ class BytesToPushOntoStackFactoryTest extends BitcoinSUnitTest { "ScriptNumberFactory" must "represent the number 1" in { BytesToPushOntoStack.operations.contains(BytesToPushOntoStack(1)) must be( - true) + true + ) BytesToPushOntoStack.operations.contains(BytesToPushOntoStack(75)) must be( - true) + true + ) } it must "find the number two" in { @@ -30,7 +32,8 @@ class BytesToPushOntoStackFactoryTest extends BitcoinSUnitTest { it must "not allow creation of the script number -2" in { intercept[IllegalArgumentException] { BytesToPushOntoStack.operations.contains( - BytesToPushOntoStack(-2)) must be(false) + BytesToPushOntoStack(-2) + ) must be(false) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/constant/ConstantInterpreterTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/constant/ConstantInterpreterTest.scala index 95ab3d7b7e..0e123c0013 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/constant/ConstantInterpreterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/constant/ConstantInterpreterTest.scala @@ -21,14 +21,18 @@ class ConstantInterpreterTest extends BitcoinSUnitTest { val byteConstant = ByteVector(Array.fill(byteConstantSize)(0.toByte)) val scriptConstant = ScriptConstant(byteConstant) val stack = List() - val script = List(OP_PUSHDATA1, - ScriptNumber(byteConstantSize), - scriptConstant, - OP_7, - OP_EQUAL) + val script = List( + OP_PUSHDATA1, + ScriptNumber(byteConstantSize), + scriptConstant, + OP_7, + OP_EQUAL + ) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.opPushData1(program) newProgram.stack must be(List(scriptConstant)) newProgram.script must be(List(OP_7, OP_EQUAL)) @@ -42,8 +46,10 @@ class ConstantInterpreterTest extends BitcoinSUnitTest { val script = List(OP_PUSHDATA2, ScriptNumber(256), scriptConstant, OP_8, OP_EQUAL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.opPushData2(program) newProgram.stack must be(List(scriptConstant)) newProgram.script must be(List(OP_8, OP_EQUAL)) @@ -54,14 +60,18 @@ class ConstantInterpreterTest extends BitcoinSUnitTest { val byteConstant = ByteVector(Array.fill(byteConstantSize)(0.toByte)) val scriptConstant = ScriptConstant(byteConstant) val stack = List() - val script = List(OP_PUSHDATA4, - ScriptNumber(byteConstantSize), - scriptConstant, - OP_9, - OP_EQUAL) + val script = List( + OP_PUSHDATA4, + ScriptNumber(byteConstantSize), + scriptConstant, + OP_9, + OP_EQUAL + ) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.opPushData4(program) newProgram.stack must be(List(scriptConstant)) newProgram.script must be(List(OP_9, OP_EQUAL)) @@ -71,8 +81,10 @@ class ConstantInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(BytesToPushOntoStack(2), ScriptNumber.one, OP_0) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.pushScriptNumberBytesToStack(program) newProgram.script.isEmpty must be(true) newProgram.stack must be(List(ScriptConstant("0100"))) @@ -109,7 +121,7 @@ class ConstantInterpreterTest extends BitcoinSUnitTest { .updateStackAndScript(stack4, script4) .removeFlags() - //purposely call incorrect functions to mismatch opCodes + // purposely call incorrect functions to mismatch opCodes intercept[IllegalArgumentException] { CI.opPushData1(program2) } @@ -128,8 +140,10 @@ class ConstantInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_CHECKMULTISIGVERIFY, ScriptNumber.one, OP_0) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) intercept[IllegalArgumentException] { CI.pushScriptNumberBytesToStack(program) @@ -150,12 +164,15 @@ class ConstantInterpreterTest extends BitcoinSUnitTest { it must "push a constant onto the stack that is using OP_PUSHDATA1 where the pushop can be interpreted as a script number operation" in { val constant = ScriptConstant( "01000000010000000000000000000000000000000000000000000000000000000000000000" + - "ffffffff00ffffffff014a7afa8f7d52fd9e17a914b167f19394cd656c34f843ac2387e602007fd15b8700000000") + "ffffffff00ffffffff014a7afa8f7d52fd9e17a914b167f19394cd656c34f843ac2387e602007fd15b8700000000" + ) val stack = Nil val script = List(OP_PUSHDATA1, OP_3, constant) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.opPushData1(program) newProgram.stack must be(Seq(constant)) diff --git a/core-test/src/test/scala/org/bitcoins/core/script/constant/ScriptNumberUtilTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/constant/ScriptNumberUtilTest.scala index 23f2a39445..c3ee1ff94f 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/constant/ScriptNumberUtilTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/constant/ScriptNumberUtilTest.scala @@ -11,59 +11,59 @@ class ScriptNumberUtilTest extends BitcoinSUnitTest { val long = ScriptNumberUtil.toLong(hex) long must be(1) - //127 + // 127 val hex1 = "7f" val long1 = ScriptNumberUtil.toLong(hex1) long1 must be(127) - //128 + // 128 val hex2 = "8000" val long2 = ScriptNumberUtil.toLong(hex2) long2 must be(128) - //32767 + // 32767 val hex3 = "ff7f" val long3 = ScriptNumberUtil.toLong(hex3) long3 must be(32767) - //32768 + // 32768 val hex4 = "008000" val long4 = ScriptNumberUtil.toLong(hex4) long4 must be(32768) - //20 + // 20 val hex5 = "14" val long5 = ScriptNumberUtil.toLong(hex5) long5 must be(20) - //0 + // 0 val hex6 = "00" val long6 = ScriptNumberUtil.toLong(hex6) long6 must be(0) } it must "convert a negative hex number to its corresponding long number" in { - //-1 + // -1 val hex = "81" val long = ScriptNumberUtil.toLong(hex) long must be(-1) - //-127 + // -127 val hex1 = "ff" val long1 = ScriptNumberUtil.toLong(hex1) long1 must be(-127) - //-128 + // -128 val hex2 = "8080" val long2 = ScriptNumberUtil.toLong(hex2) long2 must be(-128) - //-32767 + // -32767 val hex3 = "ffff" val long3 = ScriptNumberUtil.toLong(hex3) long3 must be(-32767) - //-32768 + // -32768 val hex4 = "008080" val long4 = ScriptNumberUtil.toLong(hex4) long4 must be(-32768) @@ -74,7 +74,7 @@ class ScriptNumberUtilTest extends BitcoinSUnitTest { val hexIsPositive = ScriptNumberUtil.isPositive(hex) hexIsPositive must be(true) - //128 + // 128 val hex1 = "8000" val hexIsPositive1 = ScriptNumberUtil.isPositive(hex1) hexIsPositive1 must be(true) @@ -86,22 +86,22 @@ class ScriptNumberUtilTest extends BitcoinSUnitTest { } it must "determine if a hex string is a negative number" in { - //-1 + // -1 val hex = "81" val hexIsNegative = ScriptNumberUtil.isNegative(hex) hexIsNegative must be(true) - //-128 + // -128 val hex1 = "8080" val hexIsNegative1 = ScriptNumberUtil.isNegative(hex1) hexIsNegative1 must be(true) - //-32767 + // -32767 val hex2 = "ffff" val hexIsNegative2 = ScriptNumberUtil.isNegative(hex2) hexIsNegative2 must be(true) - //must also work for bytes + // must also work for bytes ScriptNumberUtil.isNegative(BytesUtil.decodeHex(hex2)) must be(true) } @@ -110,13 +110,15 @@ class ScriptNumberUtilTest extends BitcoinSUnitTest { val expectedHex = "7f" BytesUtil.encodeHex( ScriptNumberUtil - .changeSignBitToPositive(BytesUtil.decodeHex(hex))) must be(expectedHex) + .changeSignBitToPositive(BytesUtil.decodeHex(hex)) + ) must be(expectedHex) - //-32767 + // -32767 val hex1 = "ffff" val expectedHex1 = "7fff" BytesUtil.encodeHex(ScriptNumberUtil.changeSignBitToPositive(hex1)) must be( - expectedHex1) + expectedHex1 + ) } it must "change a sign bit from positive to negative" in { @@ -124,19 +126,22 @@ class ScriptNumberUtilTest extends BitcoinSUnitTest { val hex = "01" val expectedHex = "81" BytesUtil.encodeHex(ScriptNumberUtil.changeSignBitToNegative(hex)) must be( - expectedHex) + expectedHex + ) - //32767 + // 32767 val hex1 = "7fff" val expectedHex1 = "ffff" BytesUtil.encodeHex(ScriptNumberUtil.changeSignBitToNegative(hex1)) must be( - expectedHex1) + expectedHex1 + ) - //128 + // 128 val hex2 = "8000" val expectedHex2 = "8000" BytesUtil.encodeHex(ScriptNumberUtil.changeSignBitToNegative(hex2)) must be( - expectedHex2) + expectedHex2 + ) } it must "detect if the last two bytes are all zeros" in { @@ -205,8 +210,8 @@ class ScriptNumberUtilTest extends BitcoinSUnitTest { it must "convert a sequence of bytes to the min value for an int" in { val min = Int.MinValue + 1 - //the minimum number we can represent in ScriptNumbers i - //is Int.MinValue + 1 since we have a negative zero and zero + // the minimum number we can represent in ScriptNumbers i + // is Int.MinValue + 1 since we have a negative zero and zero ScriptNumberUtil.toInt("ffffffff") must be(min) } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/control/ControlOperationsInterpreterTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/control/ControlOperationsInterpreterTest.scala index 71f924cc49..7f2975e7b7 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/control/ControlOperationsInterpreterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/control/ControlOperationsInterpreterTest.scala @@ -28,21 +28,25 @@ class ControlOperationsInterpreterTest extends BitcoinSJvmTest { val stack = List(OP_TRUE) val script = List(OP_VERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val result = COI.opVerify(program) result.stack.isEmpty must be(true) result.script.isEmpty must be(true) } it must "have OP_VERIFY evaluate to true when there are multiple items on the stack that can be cast to an int" in { - //for this test case in bitcoin core's script test suite - //https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json#L21 + // for this test case in bitcoin core's script test suite + // https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json#L21 val stack = ScriptParser.fromString("0x09 0x00000000 0x00000000 0x10") val script = List(OP_VERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val result = COI.opVerify(program) result.stackTopIsTrue must be(true) } @@ -51,8 +55,10 @@ class ControlOperationsInterpreterTest extends BitcoinSJvmTest { val stack = List(OP_FALSE) val script = List(OP_VERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val result = COI.opVerify(program) result.stackTopIsFalse must be(true) } @@ -62,8 +68,10 @@ class ControlOperationsInterpreterTest extends BitcoinSJvmTest { val stack = List() val script = List(OP_VERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val result = ScriptProgramTestUtil.toExecutedScriptProgram(COI.opVerify(program)) result.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -76,8 +84,10 @@ class ControlOperationsInterpreterTest extends BitcoinSJvmTest { val stack = List(ScriptConstant("1")) val script = List() val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) COI.opVerify(program) } } @@ -88,14 +98,16 @@ class ControlOperationsInterpreterTest extends BitcoinSJvmTest { stack: List[ScriptToken], script: List[ScriptToken], shouldExecuteNextOperation: Boolean, - isInExecutionBranch: Boolean): org.scalatest.Assertion = { + isInExecutionBranch: Boolean + ): org.scalatest.Assertion = { program.stack must be(stack) program.script must be(script) program match { case programInProgress: ExecutionInProgressScriptProgram => programInProgress.shouldExecuteNextOperation must be( - shouldExecuteNextOperation) + shouldExecuteNextOperation + ) programInProgress.isInExecutionBranch must be(isInExecutionBranch) case executed: ExecutedScriptProgram => fail(s"Unexpected error: ${executed.error}") @@ -106,220 +118,276 @@ class ControlOperationsInterpreterTest extends BitcoinSJvmTest { val stack = List(OP_0) val script = List(OP_IF, OP_RESERVED, OP_ENDIF, OP_1) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = COI.opIf(program) - programMustBe(program = newProgram, - stack = Nil, - script = List(OP_RESERVED, OP_ENDIF, OP_1), - shouldExecuteNextOperation = false, - isInExecutionBranch = false) + programMustBe( + program = newProgram, + stack = Nil, + script = List(OP_RESERVED, OP_ENDIF, OP_1), + shouldExecuteNextOperation = false, + isInExecutionBranch = false + ) val newProgramInProgress = newProgram.asInstanceOf[ExecutionInProgressScriptProgram] val newNewProgram = newProgramInProgress.updateScript(newProgram.script.tail) - programMustBe(program = newNewProgram, - stack = Nil, - script = List(OP_ENDIF, OP_1), - shouldExecuteNextOperation = true, - isInExecutionBranch = false) + programMustBe( + program = newNewProgram, + stack = Nil, + script = List(OP_ENDIF, OP_1), + shouldExecuteNextOperation = true, + isInExecutionBranch = false + ) val afterIfProgram = COI.opEndIf(newNewProgram) - programMustBe(program = afterIfProgram, - stack = Nil, - script = List(OP_1), - shouldExecuteNextOperation = true, - isInExecutionBranch = true) + programMustBe( + program = afterIfProgram, + stack = Nil, + script = List(OP_1), + shouldExecuteNextOperation = true, + isInExecutionBranch = true + ) } it must "evaluate an OP_IF OP_ELSE OP_ENDIF block" in { val stack = List(OP_0) val script = List(OP_IF, OP_VER, OP_ELSE, OP_1, OP_ENDIF) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = COI.opIf(program) - programMustBe(program = newProgram, - stack = Nil, - script = List(OP_VER, OP_ELSE, OP_1, OP_ENDIF), - shouldExecuteNextOperation = false, - isInExecutionBranch = false) + programMustBe( + program = newProgram, + stack = Nil, + script = List(OP_VER, OP_ELSE, OP_1, OP_ENDIF), + shouldExecuteNextOperation = false, + isInExecutionBranch = false + ) val newProgramInProgress = newProgram.asInstanceOf[ExecutionInProgressScriptProgram] val elseProgram = newProgramInProgress.updateScript(newProgram.script.tail) - programMustBe(program = elseProgram, - stack = Nil, - script = List(OP_ELSE, OP_1, OP_ENDIF), - shouldExecuteNextOperation = true, - isInExecutionBranch = false) + programMustBe( + program = elseProgram, + stack = Nil, + script = List(OP_ELSE, OP_1, OP_ENDIF), + shouldExecuteNextOperation = true, + isInExecutionBranch = false + ) val afterElseProgram = COI.opElse(elseProgram) - programMustBe(program = afterElseProgram, - stack = Nil, - script = List(OP_1, OP_ENDIF), - shouldExecuteNextOperation = true, - isInExecutionBranch = true) + programMustBe( + program = afterElseProgram, + stack = Nil, + script = List(OP_1, OP_ENDIF), + shouldExecuteNextOperation = true, + isInExecutionBranch = true + ) } it must "evaluate an OP_IF block correctly if the stack top is true" in { val stack = List(ScriptNumber.one) val script = List(OP_IF, OP_1, OP_ELSE, OP_0, OP_ENDIF) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = COI.opIf(program) - programMustBe(program = newProgram, - stack = Nil, - script = List(OP_1, OP_ELSE, OP_0, OP_ENDIF), - shouldExecuteNextOperation = true, - isInExecutionBranch = true) + programMustBe( + program = newProgram, + stack = Nil, + script = List(OP_1, OP_ELSE, OP_0, OP_ENDIF), + shouldExecuteNextOperation = true, + isInExecutionBranch = true + ) val newProgramInProgress = newProgram.asInstanceOf[ExecutionInProgressScriptProgram] val elseProgram = - newProgramInProgress.updateStackAndScript(List(ScriptNumber.one), - newProgram.script.tail) - programMustBe(program = elseProgram, - stack = List(ScriptNumber.one), - script = List(OP_ELSE, OP_0, OP_ENDIF), - shouldExecuteNextOperation = true, - isInExecutionBranch = true) + newProgramInProgress.updateStackAndScript( + List(ScriptNumber.one), + newProgram.script.tail + ) + programMustBe( + program = elseProgram, + stack = List(ScriptNumber.one), + script = List(OP_ELSE, OP_0, OP_ENDIF), + shouldExecuteNextOperation = true, + isInExecutionBranch = true + ) val afterElseProgram = COI.opElse(elseProgram) - programMustBe(program = afterElseProgram, - stack = List(ScriptNumber.one), - script = List(OP_0, OP_ENDIF), - shouldExecuteNextOperation = false, - isInExecutionBranch = false) + programMustBe( + program = afterElseProgram, + stack = List(ScriptNumber.one), + script = List(OP_0, OP_ENDIF), + shouldExecuteNextOperation = false, + isInExecutionBranch = false + ) } it must "evaluate a weird case using multiple OP_ELSEs" in { val stack = List(ScriptNumber.one) val script = List(OP_IF, OP_ELSE, OP_0, OP_ELSE, OP_1, OP_ENDIF) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = COI.opIf(program) - programMustBe(program = newProgram, - stack = Nil, - script = List(OP_ELSE, OP_0, OP_ELSE, OP_1, OP_ENDIF), - shouldExecuteNextOperation = true, - isInExecutionBranch = true) + programMustBe( + program = newProgram, + stack = Nil, + script = List(OP_ELSE, OP_0, OP_ELSE, OP_1, OP_ENDIF), + shouldExecuteNextOperation = true, + isInExecutionBranch = true + ) val newProgramInProgress = newProgram.asInstanceOf[ExecutionInProgressScriptProgram] val newNewProgram = COI.opElse(newProgramInProgress) - programMustBe(program = newNewProgram, - stack = Nil, - script = List(OP_0, OP_ELSE, OP_1, OP_ENDIF), - shouldExecuteNextOperation = false, - isInExecutionBranch = false) + programMustBe( + program = newNewProgram, + stack = Nil, + script = List(OP_0, OP_ELSE, OP_1, OP_ENDIF), + shouldExecuteNextOperation = false, + isInExecutionBranch = false + ) val newNewProgramInProgress = newNewProgram.asInstanceOf[ExecutionInProgressScriptProgram] val elseProgram = newNewProgramInProgress.updateScript(newNewProgram.script.tail) - programMustBe(program = elseProgram, - stack = Nil, - script = List(OP_ELSE, OP_1, OP_ENDIF), - shouldExecuteNextOperation = true, - isInExecutionBranch = false) + programMustBe( + program = elseProgram, + stack = Nil, + script = List(OP_ELSE, OP_1, OP_ENDIF), + shouldExecuteNextOperation = true, + isInExecutionBranch = false + ) val afterElseProgram = COI.opElse(elseProgram) - programMustBe(program = afterElseProgram, - stack = Nil, - script = List(OP_1, OP_ENDIF), - shouldExecuteNextOperation = true, - isInExecutionBranch = true) + programMustBe( + program = afterElseProgram, + stack = Nil, + script = List(OP_1, OP_ENDIF), + shouldExecuteNextOperation = true, + isInExecutionBranch = true + ) } it must "evaluate nested OP_IFS correctly" in { val stack = List(OP_0, OP_1) - val script = List(OP_IF, - OP_IF, - OP_0, - OP_ELSE, - OP_1, - OP_ENDIF, - OP_ELSE, - OP_IF, - OP_2, - OP_ELSE, - OP_3, - OP_ENDIF, - OP_ENDIF) + val script = List( + OP_IF, + OP_IF, + OP_0, + OP_ELSE, + OP_1, + OP_ENDIF, + OP_ELSE, + OP_IF, + OP_2, + OP_ELSE, + OP_3, + OP_ENDIF, + OP_ENDIF + ) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val secondIfProgram = COI.opIf(program) - programMustBe(program = secondIfProgram, - stack = List(ScriptNumber.one), - script = script.tail, - shouldExecuteNextOperation = true, - isInExecutionBranch = false) + programMustBe( + program = secondIfProgram, + stack = List(ScriptNumber.one), + script = script.tail, + shouldExecuteNextOperation = true, + isInExecutionBranch = false + ) val secondIfProgramInProgress = secondIfProgram.asInstanceOf[ExecutionInProgressScriptProgram] val ignoreProgram0 = COI.opIf(secondIfProgramInProgress) - programMustBe(program = ignoreProgram0, - stack = List(ScriptNumber.one), - script = secondIfProgram.script.tail, - shouldExecuteNextOperation = false, - isInExecutionBranch = false) + programMustBe( + program = ignoreProgram0, + stack = List(ScriptNumber.one), + script = secondIfProgram.script.tail, + shouldExecuteNextOperation = false, + isInExecutionBranch = false + ) val ignoreProgram0InProgress = ignoreProgram0.asInstanceOf[ExecutionInProgressScriptProgram] val ignoreElseProgram = ignoreProgram0InProgress.updateScript(ignoreProgram0.script.tail) - programMustBe(program = ignoreElseProgram, - stack = List(ScriptNumber.one), - script = ignoreProgram0.script.tail, - shouldExecuteNextOperation = true, - isInExecutionBranch = false) + programMustBe( + program = ignoreElseProgram, + stack = List(ScriptNumber.one), + script = ignoreProgram0.script.tail, + shouldExecuteNextOperation = true, + isInExecutionBranch = false + ) val ignoreProgram1 = COI.opElse(ignoreElseProgram) - programMustBe(program = ignoreProgram1, - stack = List(ScriptNumber.one), - script = ignoreElseProgram.script.tail, - shouldExecuteNextOperation = false, - isInExecutionBranch = false) + programMustBe( + program = ignoreProgram1, + stack = List(ScriptNumber.one), + script = ignoreElseProgram.script.tail, + shouldExecuteNextOperation = false, + isInExecutionBranch = false + ) val ignoreProgram1InProgress = ignoreProgram1.asInstanceOf[ExecutionInProgressScriptProgram] val endIfProgram = ignoreProgram1InProgress.updateScript(ignoreProgram1.script.tail) - programMustBe(program = endIfProgram, - stack = List(ScriptNumber.one), - script = ignoreProgram1.script.tail, - shouldExecuteNextOperation = true, - isInExecutionBranch = false) + programMustBe( + program = endIfProgram, + stack = List(ScriptNumber.one), + script = ignoreProgram1.script.tail, + shouldExecuteNextOperation = true, + isInExecutionBranch = false + ) val elseProgram = COI.opEndIf(endIfProgram) - programMustBe(program = elseProgram, - stack = List(ScriptNumber.one), - script = endIfProgram.script.tail, - shouldExecuteNextOperation = true, - isInExecutionBranch = false) + programMustBe( + program = elseProgram, + stack = List(ScriptNumber.one), + script = endIfProgram.script.tail, + shouldExecuteNextOperation = true, + isInExecutionBranch = false + ) val elseProgramInProgress = elseProgram.asInstanceOf[ExecutionInProgressScriptProgram] val correctIfProgram = COI.opElse(elseProgramInProgress) - programMustBe(program = correctIfProgram, - stack = List(ScriptNumber.one), - script = elseProgram.script.tail, - shouldExecuteNextOperation = true, - isInExecutionBranch = true) + programMustBe( + program = correctIfProgram, + stack = List(ScriptNumber.one), + script = elseProgram.script.tail, + shouldExecuteNextOperation = true, + isInExecutionBranch = true + ) val correctIfProgramInProgress = correctIfProgram.asInstanceOf[ExecutionInProgressScriptProgram] val correctBranchProgram = COI.opIf(correctIfProgramInProgress) - programMustBe(program = correctBranchProgram, - stack = Nil, - script = correctIfProgram.script.tail, - shouldExecuteNextOperation = true, - isInExecutionBranch = true) + programMustBe( + program = correctBranchProgram, + stack = Nil, + script = correctIfProgram.script.tail, + shouldExecuteNextOperation = true, + isInExecutionBranch = true + ) } it must "evaluate an OP_ENDIF correctly" in { @@ -340,8 +408,10 @@ class ControlOperationsInterpreterTest extends BitcoinSJvmTest { val stack = Seq() val script = Seq(OP_RETURN) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(COI.opReturn(program)) diff --git a/core-test/src/test/scala/org/bitcoins/core/script/crypto/CryptoInterpreterTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/crypto/CryptoInterpreterTest.scala index 398d27ce6b..0b56c1e496 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/crypto/CryptoInterpreterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/crypto/CryptoInterpreterTest.scala @@ -18,19 +18,25 @@ import scala.util.Try */ class CryptoInterpreterTest extends BitcoinSJvmTest { - val stack = List(ScriptConstant( - "02218AD6CDC632E7AE7D04472374311CEBBBBF0AB540D2D08C3400BB844C654231".toLowerCase)) + val stack = List( + ScriptConstant( + "02218AD6CDC632E7AE7D04472374311CEBBBBF0AB540D2D08C3400BB844C654231".toLowerCase + ) + ) val CI = CryptoInterpreter "CryptoInterpreter" must "evaluate OP_HASH160 correctly when it is on top of the script stack" in { val script = List(OP_HASH160) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.opHash160(program) newProgram.stack.head must be( - ScriptConstant("5238C71458E464D9FF90299ABCA4A1D7B9CB76AB".toLowerCase)) + ScriptConstant("5238C71458E464D9FF90299ABCA4A1D7B9CB76AB".toLowerCase) + ) newProgram.script.size must be(0) } @@ -38,8 +44,10 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { val stack = List() val script = List(OP_HASH160) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val executedProgram: ExecutedScriptProgram = ScriptProgramTestUtil.toExecutedScriptProgram(CI.opHash160(program)) executedProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -49,8 +57,10 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { it must "fail to evaluate all OP codes when the script stack is empty" in { val script = List() val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) Try(CI.opHash160(program)).isFailure must be(true) Try(CI.opRipeMd160(program)).isFailure must be(true) Try(CI.opSha256(program)).isFailure must be(true) @@ -67,11 +77,14 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { val stack = List(ScriptConstant("")) val script = List(OP_RIPEMD160) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.opRipeMd160(program) newProgram.stack must be( - List(ScriptConstant("9c1185a5c5e9fc54612808977ee8f548b2258d31"))) + List(ScriptConstant("9c1185a5c5e9fc54612808977ee8f548b2258d31")) + ) newProgram.script.isEmpty must be(true) } @@ -79,11 +92,14 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { val stack = List(ScriptConstant("ab")) val script = List(OP_SHA1) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.opSha1(program) newProgram.stack.head must be( - ScriptConstant("fe83f217d464f6fdfa5b2b1f87fe3a1a47371196")) + ScriptConstant("fe83f217d464f6fdfa5b2b1f87fe3a1a47371196") + ) newProgram.script.isEmpty must be(true) } @@ -91,12 +107,18 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { val stack = List(ScriptConstant("")) val script = List(OP_SHA256) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.opSha256(program) newProgram.stack must be( - List(ScriptConstant( - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"))) + List( + ScriptConstant( + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ) + ) + ) newProgram.script.isEmpty must be(true) } @@ -104,12 +126,18 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { val stack = List(ScriptConstant("")) val script = List(OP_HASH256) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = CI.opHash256(program) newProgram.stack must be( - List(ScriptConstant( - "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"))) + List( + ScriptConstant( + "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456" + ) + ) + ) newProgram.script.isEmpty must be(true) } @@ -117,8 +145,10 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { val stack = List(OP_0, OP_0, OP_0) val script = List(OP_CHECKMULTISIG) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val programNoFlags = program.removeFlags() val newProgram = CI.opCheckMultiSig(programNoFlags) newProgram.stack must be(List(OP_TRUE)) @@ -129,8 +159,10 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { val stack = List(OP_0, OP_0, OP_0, OP_16, OP_16, OP_16) val script = List(OP_CHECKMULTISIG, OP_16, OP_16, OP_16, OP_16) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val programNoFlags = program.removeFlags() val newProgram = CI.opCheckMultiSig(programNoFlags) newProgram.stack must be(List(OP_TRUE, OP_16, OP_16, OP_16)) @@ -141,8 +173,10 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { val stack = List(ScriptNumber.zero, ScriptNumber.zero, ScriptNumber.zero) val script = List(OP_CHECKMULTISIGVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val programNoFlags = program.removeFlags() val newProgram = CI.opCheckMultiSigVerify(programNoFlags) newProgram.script.isEmpty must be(true) @@ -154,8 +188,10 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { val stack = List(OP_0, OP_0, OP_0, OP_16, OP_16, OP_16) val script = List(OP_CHECKMULTISIGVERIFY, OP_16, OP_16, OP_16, OP_16) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val programNoFlags = program.removeFlags() val newProgram = CI.opCheckMultiSigVerify(programNoFlags) newProgram.stack must be(List(OP_16, OP_16, OP_16)) @@ -164,12 +200,14 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { } it must "evaluate an OP_CHECKMULTISIG for" in { - //0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL + // 0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL val stack = List(OP_1, OP_0, OP_0, OP_0) val script = List(OP_CHECKMULTISIG) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val programNoFlags = program.removeFlags() val newProgram = CI.opCheckMultiSig(programNoFlags) newProgram.stack must be(List(OP_TRUE)) @@ -180,9 +218,11 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { it must "mark a transaction invalid when the NULLDUMMY flag is set for a OP_CHECKMULTISIG operation & the scriptSig does not begin with OP_0" in { val flags = Seq(ScriptVerifyNullDummy) val scriptSig = ScriptSignature.fromAsm(Seq(OP_1)) - val input = TransactionInput(EmptyTransactionOutPoint, - scriptSig, - TransactionConstants.sequence) + val input = TransactionInput( + EmptyTransactionOutPoint, + scriptSig, + TransactionConstants.sequence + ) val empty = EmptyTransaction val tx = BaseTransaction(empty.version, Seq(input), empty.outputs, empty.lockTime) @@ -190,7 +230,8 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { transaction = tx, inputIndex = UInt32.zero, output = TransactionOutput(CurrencyUnits.zero, TestUtil.scriptPubKey), - flags = flags) + flags = flags + ) val pre = PreExecutionScriptProgram(t) val baseProgram = pre.toExecutionInProgress val stack = Seq(OP_0, OP_0, OP_1) @@ -205,18 +246,23 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { it must "mark a transaction invalid when the DERSIG flag is set for a OP_CHECKSIG operaetion & the signature is not a strict der sig" in { val flags = Seq(ScriptVerifyDerSig) - //signature is from script_valid.json, it has a negative S value which makes it non strict der + // signature is from script_valid.json, it has a negative S value which makes it non strict der val stack = Seq( OP_0, ScriptConstant( - "302402107777777777777777777777777777777702108777777777777777777777777777777701")) + "302402107777777777777777777777777777777702108777777777777777777777777777777701" + ) + ) val script = Seq(OP_CHECKSIG) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val programWithFlags = program.replaceFlags(flags) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram( - CI.opCheckSig(programWithFlags)) + CI.opCheckSig(programWithFlags) + ) newProgram.error must be(Some(ScriptErrorSigDer)) } @@ -228,7 +274,8 @@ class CryptoInterpreterTest extends BitcoinSJvmTest { .updateStackAndScript(stack, script) .updateOriginalScript(script) val newProgram = ScriptProgramTestUtil.toExecutionInProgressScriptProgram( - CI.opCodeSeparator(program)) + CI.opCodeSeparator(program) + ) newProgram.lastCodeSeparator must be(Some(0)) } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/crypto/CryptoSignatureEvaluationFactoryTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/crypto/CryptoSignatureEvaluationFactoryTest.scala index ae316f6bf4..f1c9bf08ce 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/crypto/CryptoSignatureEvaluationFactoryTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/crypto/CryptoSignatureEvaluationFactoryTest.scala @@ -8,10 +8,13 @@ class CryptoSignatureEvaluationFactoryTest extends BitcoinSUnitTest { "CryptoSignatureEvaluationFactory" must "have all of the Script operations that involve checking signatures" in { CryptoSignatureEvaluationFactory.operations must be( - Seq(OP_CHECKMULTISIG, - OP_CHECKMULTISIGVERIFY, - OP_CHECKSIG, - OP_CHECKSIGVERIFY, - OP_CHECKSIGADD)) + Seq( + OP_CHECKMULTISIG, + OP_CHECKMULTISIGVERIFY, + OP_CHECKSIG, + OP_CHECKSIGVERIFY, + OP_CHECKSIGADD + ) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/flag/ScriptFlagFactoryTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/flag/ScriptFlagFactoryTest.scala index e789067fa0..de4d451575 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/flag/ScriptFlagFactoryTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/flag/ScriptFlagFactoryTest.scala @@ -40,7 +40,8 @@ class ScriptFlagFactoryTest extends BitcoinSUnitTest { it must "find a DISCOURAGE_UPGRADABLE_NOPS flag" in { ScriptFlagFactory.fromString("DISCOURAGE_UPGRADABLE_NOPS") must be( - ScriptVerifyDiscourageUpgradableNOPs) + ScriptVerifyDiscourageUpgradableNOPs + ) } it must "find a CLEANSTACK flag" in { @@ -49,13 +50,15 @@ class ScriptFlagFactoryTest extends BitcoinSUnitTest { it must "find a CHECKLOCKTIMEVERIFY flag" in { ScriptFlagFactory.fromString("CHECKLOCKTIMEVERIFY") must be( - ScriptVerifyCheckLocktimeVerify) + ScriptVerifyCheckLocktimeVerify + ) } it must "find a CHECKSEQUENCEVERIFY flag" in { ScriptFlagFactory.fromString("CHECKSEQUENCEVERIFY") must be( - ScriptVerifyCheckSequenceVerify) + ScriptVerifyCheckSequenceVerify + ) } it must "match a string version of a script flag" in { @@ -66,13 +69,15 @@ class ScriptFlagFactoryTest extends BitcoinSUnitTest { it must "match a comma separated list of flags" in { val str = "P2SH,STRICTENC" ScriptFlagFactory.fromList(str) must be( - Seq(ScriptVerifyP2SH, ScriptVerifyStrictEnc)) + Seq(ScriptVerifyP2SH, ScriptVerifyStrictEnc) + ) } it must "match a sequence of strings with their script flags" in { val l = List("P2SH", "STRICTENC") ScriptFlagFactory.fromList(l) must be( - Seq(ScriptVerifyP2SH, ScriptVerifyStrictEnc)) + Seq(ScriptVerifyP2SH, ScriptVerifyStrictEnc) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/flag/ScriptFlagUtilTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/flag/ScriptFlagUtilTest.scala index 59adf8b6ea..3afe2de0a6 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/flag/ScriptFlagUtilTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/flag/ScriptFlagUtilTest.scala @@ -8,9 +8,11 @@ class ScriptFlagUtilTest extends BitcoinSUnitTest { "ScriptFlagUtil" must "check if strict der encoding check is required" in { ScriptFlagUtil.requiresStrictDerEncoding(Seq(ScriptVerifyDerSig)) must be( - true) + true + ) ScriptFlagUtil.requiresStrictDerEncoding( - Seq(ScriptVerifyStrictEnc)) must be(true) + Seq(ScriptVerifyStrictEnc) + ) must be(true) } it must "return false if strict der encoding check is not required" in { @@ -28,6 +30,7 @@ class ScriptFlagUtilTest extends BitcoinSUnitTest { ScriptVerifyNullDummy, ScriptVerifyP2SH, ScriptVerifySigPushOnly - )) must be(false) + ) + ) must be(false) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/interpreter/ScriptInterpreterTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/interpreter/ScriptInterpreterTest.scala index c9130fd64d..4f0987d213 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/interpreter/ScriptInterpreterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/interpreter/ScriptInterpreterTest.scala @@ -37,13 +37,17 @@ class ScriptInterpreterTest extends BitcoinSUnitTest { testCase <- testCases (creditingTx, outputIndex) = TransactionTestUtil - .buildCreditingTransaction(testCase.scriptPubKey, - testCase.witness.map(_._2)) + .buildCreditingTransaction( + testCase.scriptPubKey, + testCase.witness.map(_._2) + ) (tx, inputIndex) = - TransactionTestUtil.buildSpendingTransaction(creditingTx, - testCase.scriptSig, - outputIndex, - testCase.witness) + TransactionTestUtil.buildSpendingTransaction( + creditingTx, + testCase.scriptSig, + outputIndex, + testCase.witness + ) } yield { val scriptPubKey = ScriptPubKey.fromAsm(testCase.scriptPubKey.asm) val flags = ScriptFlagFactory.fromList(testCase.flags) @@ -53,19 +57,22 @@ class ScriptInterpreterTest extends BitcoinSUnitTest { scriptPubKey match { case p2sh: P2SHScriptPubKey => val output = TransactionOutput(amount, p2sh) - WitnessTxSigComponentP2SH(tx.asInstanceOf[WitnessTransaction], - inputIndex, - output, - flags) + WitnessTxSigComponentP2SH( + tx.asInstanceOf[WitnessTransaction], + inputIndex, + output, + flags + ) case wit: WitnessScriptPubKey => val output = TransactionOutput(amount, wit) val t = - WitnessTxSigComponentRaw(transaction = - tx.asInstanceOf[WitnessTransaction], - inputIndex = inputIndex, - output = output, - flags = flags) + WitnessTxSigComponentRaw( + transaction = tx.asInstanceOf[WitnessTransaction], + inputIndex = inputIndex, + output = output, + flags = flags + ) t case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey | _: P2PKWithTimeoutScriptPubKey | _: MultiSignatureScriptPubKey | @@ -73,18 +80,22 @@ class ScriptInterpreterTest extends BitcoinSUnitTest { _: ConditionalScriptPubKey | _: NonStandardScriptPubKey | _: WitnessCommitment | EmptyScriptPubKey) => val output = TransactionOutput(amount, x) - BaseTxSigComponent(transaction = tx, - inputIndex = inputIndex, - output = output, - flags = flags) + BaseTxSigComponent( + transaction = tx, + inputIndex = inputIndex, + output = output, + flags = flags + ) } case None => - //value in the output does not matter here since it isn't covered by the digital signature + // value in the output does not matter here since it isn't covered by the digital signature val output = TransactionOutput(CurrencyUnits.zero, scriptPubKey) - BaseTxSigComponent(transaction = tx, - inputIndex = inputIndex, - output = output, - flags = flags) + BaseTxSigComponent( + transaction = tx, + inputIndex = inputIndex, + output = output, + flags = flags + ) } val program = PreExecutionScriptProgram(txSigComponent) withClue(testCase.raw) { @@ -103,44 +114,56 @@ class ScriptInterpreterTest extends BitcoinSUnitTest { it must "evaluate a p2sh witness transaction as valid" in { val p2shWitTx = Transaction( - "02000000000101c29e1b0bc7d7eef558cab27731e68526c94a8ee30b5a8795674b39b25430dacd0000000017160014471b19074d141d11042cba016cd60d89caee0150feffffff02ee2916000000000017a91401d95721e723fb9d02fa7ae0d5a330925fa6f90187f0e864da0100000017a9149829ca82bf4d71daeffb14a6b96da4e621cccb31870247304402205406cf034993af5fc0dd9fcd96eafe04acedeb9d4d2a012aa539561cd50b6ce30220680079485226ee184c678da475e291e81ca8b83b5b973d0a8513a5b4a7e24c52012103c6350aad80873966c5a778bc3e019eef399d242ef386e21267652ca1f3e3a6ae087a1900") + "02000000000101c29e1b0bc7d7eef558cab27731e68526c94a8ee30b5a8795674b39b25430dacd0000000017160014471b19074d141d11042cba016cd60d89caee0150feffffff02ee2916000000000017a91401d95721e723fb9d02fa7ae0d5a330925fa6f90187f0e864da0100000017a9149829ca82bf4d71daeffb14a6b96da4e621cccb31870247304402205406cf034993af5fc0dd9fcd96eafe04acedeb9d4d2a012aa539561cd50b6ce30220680079485226ee184c678da475e291e81ca8b83b5b973d0a8513a5b4a7e24c52012103c6350aad80873966c5a778bc3e019eef399d242ef386e21267652ca1f3e3a6ae087a1900" + ) val prevOut = TransactionOutput( - "48677bda0100000017a914885437151ad21f21c5c714ddffdf67e56fcd63ea87") + "48677bda0100000017a914885437151ad21f21c5c714ddffdf67e56fcd63ea87" + ) // safe to use EmptyTransactionOutPoint because non-taproot assert( ScriptInterpreter .verifyTransaction( p2shWitTx, - PreviousOutputMap(Map(EmptyTransactionOutPoint -> prevOut)))) + PreviousOutputMap(Map(EmptyTransactionOutPoint -> prevOut)) + ) + ) } it must "evaluate a witness transaction as valid" in { val wtx = Transaction( - "02000000000101b62a936a1389f6f28a71f88be2703800e267bd0501e4fcd7c803a2eb2ca9d96f0000000000feffffff011027000000000000160014bb7e25b0e93a3d378b813e97d5d61efcfa69863e040047304402204e0401cf6bd54c3551a7534f9c04e30701da735693670028a5ccd5c99934df1a02200249b701467f461015bf6643bed692f911b6a43a05f1e18301e61ace743ba788014730440220385f39b54755df27ddc353b24dd83fd236e6ba0c39fefe2a41d2f0145498612b022036d0992f3245d4da79e0cc4562b8b40fb5325d8bc794cfa92d2bd36263fedcef014752210325815e1ecf3cdc683c16be773798b07ce3ca2af6969bb03975c5e0e0c06f7f0521031d8bcc3a6a7e93d904a89c20104f44b0bf6c157b6e761e20f2751381e8ba382452ae1f6d1900") + "02000000000101b62a936a1389f6f28a71f88be2703800e267bd0501e4fcd7c803a2eb2ca9d96f0000000000feffffff011027000000000000160014bb7e25b0e93a3d378b813e97d5d61efcfa69863e040047304402204e0401cf6bd54c3551a7534f9c04e30701da735693670028a5ccd5c99934df1a02200249b701467f461015bf6643bed692f911b6a43a05f1e18301e61ace743ba788014730440220385f39b54755df27ddc353b24dd83fd236e6ba0c39fefe2a41d2f0145498612b022036d0992f3245d4da79e0cc4562b8b40fb5325d8bc794cfa92d2bd36263fedcef014752210325815e1ecf3cdc683c16be773798b07ce3ca2af6969bb03975c5e0e0c06f7f0521031d8bcc3a6a7e93d904a89c20104f44b0bf6c157b6e761e20f2751381e8ba382452ae1f6d1900" + ) val prevOut = TransactionOutput( - "b82a0000000000002200202d501d0b2df21825d3dca7dc2bdaeea2c484c552b4ccbf687ffa887ae47e42c2") + "b82a0000000000002200202d501d0b2df21825d3dca7dc2bdaeea2c484c552b4ccbf687ffa887ae47e42c2" + ) // safe to use EmptyTransactionOutPoint because non-taproot assert( ScriptInterpreter .verifyTransaction( wtx, - PreviousOutputMap(Map(EmptyTransactionOutPoint -> prevOut)))) + PreviousOutputMap(Map(EmptyTransactionOutPoint -> prevOut)) + ) + ) } it must "evaluate a base transaction as valid" in { val tx = Transaction( - "01000000010289c14b991dde643aca30b9010c9b37b8347f3984fa5c31e78adceeea4eefab000000006a47304402206d1ae877e2339ed74a1b203aacdb8e4dc6202f873a228d681d3075f7cd8ef95c022067383abdf0bc1839db0c26a0d77df097d815b4ef086da3872b4a928468b667f30121032fb875942a07a7606933e383c85d688b5fd3482c29035d4289638987582c3f2bffffffff02500e40a10b0000001976a9142301071cf4f2550a705c6348f33e6b33544b768488ac2752fb02000000001976a914741423cca440e7dc81d3468b832433e4db3c924288ac00000000") + "01000000010289c14b991dde643aca30b9010c9b37b8347f3984fa5c31e78adceeea4eefab000000006a47304402206d1ae877e2339ed74a1b203aacdb8e4dc6202f873a228d681d3075f7cd8ef95c022067383abdf0bc1839db0c26a0d77df097d815b4ef086da3872b4a928468b667f30121032fb875942a07a7606933e383c85d688b5fd3482c29035d4289638987582c3f2bffffffff02500e40a10b0000001976a9142301071cf4f2550a705c6348f33e6b33544b768488ac2752fb02000000001976a914741423cca440e7dc81d3468b832433e4db3c924288ac00000000" + ) val prevOut = TransactionOutput( - "37733ba40b0000001976a914741423cca440e7dc81d3468b832433e4db3c924288ac") + "37733ba40b0000001976a914741423cca440e7dc81d3468b832433e4db3c924288ac" + ) // safe to use EmptyTransactionOutPoint because non-taproot assert( ScriptInterpreter .verifyTransaction( tx, - PreviousOutputMap(Map(EmptyTransactionOutPoint -> prevOut)))) + PreviousOutputMap(Map(EmptyTransactionOutPoint -> prevOut)) + ) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/CoreTestCase.scala b/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/CoreTestCase.scala index a9823bcf4e..19fe811cc5 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/CoreTestCase.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/CoreTestCase.scala @@ -10,10 +10,8 @@ import scodec.bits._ import ujson._ import upickle.default._ -/** Created by chris on 1/18/16. - * This represents a core test case for valid and invalid scripts - * the scripts can be seen in the script_tests.json file - * files. +/** Created by chris on 1/18/16. This represents a core test case for valid and + * invalid scripts the scripts can be seen in the script_tests.json file files. */ case class CoreTestCase( scriptSig: ScriptSignature, @@ -22,7 +20,8 @@ case class CoreTestCase( expectedResult: ScriptResult, comments: String, raw: String, - witness: Option[(ScriptWitness, CurrencyUnit)]) + witness: Option[(ScriptWitness, CurrencyUnit)] +) object CoreTestCase { @@ -32,15 +31,16 @@ object CoreTestCase { case array: Arr => array case _ => throw new RuntimeException( - "Core test case must be in the format of js array") + "Core test case must be in the format of js array" + ) } val elements: Vector[Value] = arr.value.toVector if (elements.size < 3) { - //means that the line is probably a separator between different types of test cases i.e. - //["Equivalency of different numeric encodings"] + // means that the line is probably a separator between different types of test cases i.e. + // ["Equivalency of different numeric encodings"] None } else if (elements.size == 4) { - //means we are missing a comment + // means we are missing a comment val scriptPubKeyBytes: ByteVector = parseScriptPubKey(elements(1)) val scriptPubKey = ScriptPubKey(scriptPubKeyBytes) val scriptSignatureBytes: ByteVector = @@ -50,15 +50,18 @@ object CoreTestCase { val flags = elements(2).str val expectedResult = ScriptResult(elements(3).str) Some( - CoreTestCase(scriptSignature, - scriptPubKey, - flags, - expectedResult, - "", - elements.toString, - None)) + CoreTestCase( + scriptSignature, + scriptPubKey, + flags, + expectedResult, + "", + elements.toString, + None + ) + ) } else if (elements.size == 5 && elements.head.isInstanceOf[Arr]) { - //means we have a witness as the first item in our array + // means we have a witness as the first item in our array val witnessArray = elements.head.asInstanceOf[Arr] val amount = Satoshis((witnessArray.value.last.num * 100000000L).toLong) val stack = witnessArray.value.toVector @@ -73,13 +76,16 @@ object CoreTestCase { val flags = elements(3).str val expectedResult = ScriptResult(elements(4).str) Some( - CoreTestCase(scriptSignature, - scriptPubKey, - flags, - expectedResult, - "", - elements.toString, - Some((witness, amount)))) + CoreTestCase( + scriptSignature, + scriptPubKey, + flags, + expectedResult, + "", + elements.toString, + Some((witness, amount)) + ) + ) } else if (elements.size == 5) { val scriptPubKeyBytes: ByteVector = parseScriptPubKey(elements(1)) val scriptPubKey = ScriptPubKey(scriptPubKeyBytes) @@ -91,13 +97,16 @@ object CoreTestCase { val expectedResult = ScriptResult(elements(3).str) val comments = elements(4).str Some( - CoreTestCase(scriptSignature, - scriptPubKey, - flags, - expectedResult, - comments, - elements.toString, - None)) + CoreTestCase( + scriptSignature, + scriptPubKey, + flags, + expectedResult, + comments, + elements.toString, + None + ) + ) } else if (elements.size == 6 && elements.head.arrOpt.isDefined) { val witnessArray = elements.head.arr val amount = Satoshis((witnessArray.value.last.num * 100000000L).toLong) @@ -114,20 +123,22 @@ object CoreTestCase { val expectedResult = ScriptResult(elements(4).str) val comments = elements(5).str Some( - CoreTestCase(scriptSignature, - scriptPubKey, - flags, - expectedResult, - comments, - elements.toString, - Some((witness, amount)))) + CoreTestCase( + scriptSignature, + scriptPubKey, + flags, + expectedResult, + comments, + elements.toString, + Some((witness, amount)) + ) + ) } else None } - /** Parses the script signature asm, it can come in multiple formats - * such as byte strings i.e. 0x02 0x01 0x00 - * and numbers 1 2 - * look at scirpt_valid.json file for example formats + /** Parses the script signature asm, it can come in multiple formats such as + * byte strings i.e. 0x02 0x01 0x00 and numbers 1 2 look at scirpt_valid.json + * file for example formats */ private def parseScriptSignature(element: Value): ByteVector = { val asm = ScriptParser.fromString(element.str) @@ -136,11 +147,9 @@ object CoreTestCase { compactSizeUInt.bytes ++ bytes } - /** Parses a script pubkey asm from the bitcoin core test cases, - * example formats: - * "2 EQUALVERIFY 1 EQUAL" - * "'Az' EQUAL" - * look at scirpt_valid.json file for more example formats + /** Parses a script pubkey asm from the bitcoin core test cases, example + * formats: "2 EQUALVERIFY 1 EQUAL" "'Az' EQUAL" look at scirpt_valid.json + * file for more example formats */ private def parseScriptPubKey(element: Value): ByteVector = { val asm = ScriptParser.fromString(element.str) diff --git a/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/ScriptPubKeyCoreTestCase.scala b/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/ScriptPubKeyCoreTestCase.scala index cc36a14b40..c0f4fe4bee 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/ScriptPubKeyCoreTestCase.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/ScriptPubKeyCoreTestCase.scala @@ -7,9 +7,8 @@ import org.bitcoins.core.script.constant.ScriptToken */ trait ScriptPubKeyCoreTestCase { - /** The parsed asm representation for the core test case - * this will be different than the asm representation - * inside of scriptPubKey + /** The parsed asm representation for the core test case this will be + * different than the asm representation inside of scriptPubKey * * @return */ @@ -17,9 +16,9 @@ trait ScriptPubKeyCoreTestCase { /** This is the underlying scriptPubKey that is parsed from the core test case * this is needed because there is no ubiquitous formats for scriptPubKeys - * inside of script_valid.json. Normal scriptPubKeys have their asm representation - * parsed from the underlying hex/byte representation every time which won't work - * for core test cases. + * inside of script_valid.json. Normal scriptPubKeys have their asm + * representation parsed from the underlying hex/byte representation every + * time which won't work for core test cases. * * @return */ @@ -28,5 +27,5 @@ trait ScriptPubKeyCoreTestCase { case class ScriptPubKeyCoreTestCaseImpl( asm: Seq[ScriptToken], - scriptPubKey: ScriptPubKey) - extends ScriptPubKeyCoreTestCase + scriptPubKey: ScriptPubKey +) extends ScriptPubKeyCoreTestCase diff --git a/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/ScriptSignatureCoreTestCase.scala b/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/ScriptSignatureCoreTestCase.scala index 17d1574b16..8f98622726 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/ScriptSignatureCoreTestCase.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/interpreter/testprotocol/ScriptSignatureCoreTestCase.scala @@ -7,19 +7,18 @@ import org.bitcoins.core.script.constant.ScriptToken */ trait ScriptSignatureCoreTestCase { - /** The parsed asm representation for the core test case - * this will be different than the asm representation - * inside of scriptSignature + /** The parsed asm representation for the core test case this will be + * different than the asm representation inside of scriptSignature * * @return */ def asm: Seq[ScriptToken] - /** This is the underlying scriptSignature that is parsed from the core test case - * this is needed because there is no ubiquitous formats for scriptSignatures - * inside of script_valid.json. Normal scriptSignatures have their asm representation - * parsed from the underlying hex/byte representation every time which won't work - * for core test cases. + /** This is the underlying scriptSignature that is parsed from the core test + * case this is needed because there is no ubiquitous formats for + * scriptSignatures inside of script_valid.json. Normal scriptSignatures have + * their asm representation parsed from the underlying hex/byte + * representation every time which won't work for core test cases. * * @return */ @@ -29,5 +28,5 @@ trait ScriptSignatureCoreTestCase { case class ScriptSignatureCoreTestCaseImpl( asm: Seq[ScriptToken], - scriptSignature: ScriptSignature) - extends ScriptSignatureCoreTestCase + scriptSignature: ScriptSignature +) extends ScriptSignatureCoreTestCase diff --git a/core-test/src/test/scala/org/bitcoins/core/script/locktime/LockTimeInterpreterTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/locktime/LockTimeInterpreterTest.scala index 423720e742..5c03e20441 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/locktime/LockTimeInterpreterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/locktime/LockTimeInterpreterTest.scala @@ -22,10 +22,13 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { val stack = Seq() val script = Seq(OP_CHECKLOCKTIMEVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram( - LTI.opCheckLockTimeVerify(program)) + LTI.opCheckLockTimeVerify(program) + ) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) } @@ -33,10 +36,13 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { val stack = Seq(OP_0) val script = Seq(OP_CHECKLOCKTIMEVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram( - LTI.opCheckLockTimeVerify(program)) + LTI.opCheckLockTimeVerify(program) + ) newProgram.error must be(Some(ScriptErrorUnsatisfiedLocktime)) } @@ -45,31 +51,39 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { val script = Seq(OP_CHECKLOCKTIMEVERIFY) val oldInput = TestUtil.transaction.inputs.head val txInputAdjustedSequenceNumber = - TransactionInput(oldInput.previousOutput, - oldInput.scriptSignature, - UInt32.zero) + TransactionInput( + oldInput.previousOutput, + oldInput.scriptSignature, + UInt32.zero + ) val emptyTx = EmptyTransaction val txAdjustedSequenceNumber = - BaseTransaction(emptyTx.version, - Seq(txInputAdjustedSequenceNumber), - emptyTx.outputs, - emptyTx.lockTime) - val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version, - txAdjustedSequenceNumber.inputs, - txAdjustedSequenceNumber.outputs, - UInt32.zero) + BaseTransaction( + emptyTx.version, + Seq(txInputAdjustedSequenceNumber), + emptyTx.outputs, + emptyTx.lockTime + ) + val adjustedLockTimeTx = BaseTransaction( + txAdjustedSequenceNumber.version, + txAdjustedSequenceNumber.inputs, + txAdjustedSequenceNumber.outputs, + UInt32.zero + ) val t = BaseTxSigComponent( transaction = adjustedLockTimeTx, inputIndex = TestUtil.testProgram.txSignatureComponent.inputIndex, output = TransactionOutput( CurrencyUnits.zero, - TestUtil.testProgram.txSignatureComponent.scriptPubKey), + TestUtil.testProgram.txSignatureComponent.scriptPubKey + ), flags = TestUtil.testProgram.flags ) val baseProgram = PreExecutionScriptProgram(t) val program = baseProgram.updateStackAndScript(stack, script) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram( - LTI.opCheckLockTimeVerify(program.toExecutionInProgress)) + LTI.opCheckLockTimeVerify(program.toExecutionInProgress) + ) newProgram.error must be(Some(ScriptErrorNegativeLockTime)) } @@ -78,24 +92,31 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { val script = Seq(OP_CHECKLOCKTIMEVERIFY) val oldInput = TestUtil.transaction.inputs.head val txInputAdjustedSequenceNumber = - TransactionInput(oldInput.previousOutput, - oldInput.scriptSignature, - UInt32.zero) + TransactionInput( + oldInput.previousOutput, + oldInput.scriptSignature, + UInt32.zero + ) val emptyTx = EmptyTransaction val txAdjustedSequenceNumber = - BaseTransaction(emptyTx.version, - Seq(txInputAdjustedSequenceNumber), - emptyTx.outputs, - emptyTx.lockTime) - val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version, - txAdjustedSequenceNumber.inputs, - txAdjustedSequenceNumber.outputs, - UInt32.zero) + BaseTransaction( + emptyTx.version, + Seq(txInputAdjustedSequenceNumber), + emptyTx.outputs, + emptyTx.lockTime + ) + val adjustedLockTimeTx = BaseTransaction( + txAdjustedSequenceNumber.version, + txAdjustedSequenceNumber.inputs, + txAdjustedSequenceNumber.outputs, + UInt32.zero + ) val t = buildTxSigComponent(adjustedLockTimeTx) val baseProgram = PreExecutionScriptProgram(t) val program = baseProgram.updateStackAndScript(stack, script) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram( - LTI.opCheckLockTimeVerify(program.toExecutionInProgress)) + LTI.opCheckLockTimeVerify(program.toExecutionInProgress) + ) newProgram.error must be(Some(ScriptErrorUnsatisfiedLocktime)) } @@ -104,24 +125,31 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { val script = Seq(OP_CHECKLOCKTIMEVERIFY) val oldInput = TestUtil.transaction.inputs.head val txInputAdjustedSequenceNumber = - TransactionInput(oldInput.previousOutput, - oldInput.scriptSignature, - UInt32.zero) + TransactionInput( + oldInput.previousOutput, + oldInput.scriptSignature, + UInt32.zero + ) val emptyTx = EmptyTransaction val txAdjustedSequenceNumber = - BaseTransaction(emptyTx.version, - Seq(txInputAdjustedSequenceNumber), - emptyTx.outputs, - emptyTx.lockTime) - val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version, - txAdjustedSequenceNumber.inputs, - txAdjustedSequenceNumber.outputs, - UInt32.zero) + BaseTransaction( + emptyTx.version, + Seq(txInputAdjustedSequenceNumber), + emptyTx.outputs, + emptyTx.lockTime + ) + val adjustedLockTimeTx = BaseTransaction( + txAdjustedSequenceNumber.version, + txAdjustedSequenceNumber.inputs, + txAdjustedSequenceNumber.outputs, + UInt32.zero + ) val t = buildTxSigComponent(adjustedLockTimeTx) val baseProgram = PreExecutionScriptProgram(t) val program = baseProgram.updateStackAndScript(stack, script) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram( - LTI.opCheckLockTimeVerify(program.toExecutionInProgress)) + LTI.opCheckLockTimeVerify(program.toExecutionInProgress) + ) newProgram.error must be(Some(ScriptErrorUnsatisfiedLocktime)) } @@ -130,29 +158,36 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { val script = Seq(OP_CHECKLOCKTIMEVERIFY) val oldInput = TestUtil.transaction.inputs.head val txInputAdjustedSequenceNumber = - TransactionInput(oldInput.previousOutput, - oldInput.scriptSignature, - UInt32.zero) + TransactionInput( + oldInput.previousOutput, + oldInput.scriptSignature, + UInt32.zero + ) val emptyTx = EmptyTransaction val txAdjustedSequenceNumber = - BaseTransaction(emptyTx.version, - Seq(txInputAdjustedSequenceNumber), - emptyTx.outputs, - emptyTx.lockTime) - val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version, - txAdjustedSequenceNumber.inputs, - txAdjustedSequenceNumber.outputs, - UInt32.zero) + BaseTransaction( + emptyTx.version, + Seq(txInputAdjustedSequenceNumber), + emptyTx.outputs, + emptyTx.lockTime + ) + val adjustedLockTimeTx = BaseTransaction( + txAdjustedSequenceNumber.version, + txAdjustedSequenceNumber.inputs, + txAdjustedSequenceNumber.outputs, + UInt32.zero + ) val t = buildTxSigComponent(adjustedLockTimeTx) val basePreProgram = PreExecutionScriptProgram(t) val baseProgram = basePreProgram.toExecutionInProgress val program = baseProgram.updateStackAndScript(stack, script) val newProgram = LTI.opCheckLockTimeVerify(program) - //if an error is hit, the newProgram will be an instance of ExecutedScriptProgram - //if an error is not hit it will still be a ExecutionInProgressScriptProgram + // if an error is hit, the newProgram will be an instance of ExecutedScriptProgram + // if an error is not hit it will still be a ExecutionInProgressScriptProgram newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorUnsatisfiedLocktime)) + Some(ScriptErrorUnsatisfiedLocktime) + ) } it must "mark the transaction as valid if the locktime on the tx is < 500000000 && stack top is < 500000000" in { @@ -160,26 +195,32 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { val script = Seq(OP_CHECKLOCKTIMEVERIFY) val oldInput = TestUtil.transaction.inputs.head val txInputAdjustedSequenceNumber = - TransactionInput(oldInput.previousOutput, - oldInput.scriptSignature, - UInt32.zero) + TransactionInput( + oldInput.previousOutput, + oldInput.scriptSignature, + UInt32.zero + ) val emptyTx = EmptyTransaction val txAdjustedSequenceNumber = - BaseTransaction(emptyTx.version, - Seq(txInputAdjustedSequenceNumber), - emptyTx.outputs, - emptyTx.lockTime) - val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version, - txAdjustedSequenceNumber.inputs, - txAdjustedSequenceNumber.outputs, - UInt32.zero) + BaseTransaction( + emptyTx.version, + Seq(txInputAdjustedSequenceNumber), + emptyTx.outputs, + emptyTx.lockTime + ) + val adjustedLockTimeTx = BaseTransaction( + txAdjustedSequenceNumber.version, + txAdjustedSequenceNumber.inputs, + txAdjustedSequenceNumber.outputs, + UInt32.zero + ) val t = buildTxSigComponent(adjustedLockTimeTx) val basePreProgram = PreExecutionScriptProgram(t) val baseProgram = basePreProgram.toExecutionInProgress val program = baseProgram.updateStackAndScript(stack, script) val newProgram = LTI.opCheckLockTimeVerify(program) - //if an error is hit, the newProgram will be an instance of ExecutedScriptProgram - //if an error is not hit it will still be a ExecutionInProgressScriptProgram + // if an error is hit, the newProgram will be an instance of ExecutedScriptProgram + // if an error is not hit it will still be a ExecutionInProgressScriptProgram newProgram.isInstanceOf[ExecutedScriptProgram] must be(false) } @@ -188,26 +229,32 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { val script = Seq(OP_CHECKLOCKTIMEVERIFY) val oldInput = TestUtil.transaction.inputs.head val txInputAdjustedSequenceNumber = - TransactionInput(oldInput.previousOutput, - oldInput.scriptSignature, - UInt32.zero) + TransactionInput( + oldInput.previousOutput, + oldInput.scriptSignature, + UInt32.zero + ) val emptyTx = EmptyTransaction val txAdjustedSequenceNumber = - BaseTransaction(emptyTx.version, - Seq(txInputAdjustedSequenceNumber), - emptyTx.outputs, - emptyTx.lockTime) - val adjustedLockTimeTx = BaseTransaction(txAdjustedSequenceNumber.version, - txAdjustedSequenceNumber.inputs, - txAdjustedSequenceNumber.outputs, - UInt32(500000000)) + BaseTransaction( + emptyTx.version, + Seq(txInputAdjustedSequenceNumber), + emptyTx.outputs, + emptyTx.lockTime + ) + val adjustedLockTimeTx = BaseTransaction( + txAdjustedSequenceNumber.version, + txAdjustedSequenceNumber.inputs, + txAdjustedSequenceNumber.outputs, + UInt32(500000000) + ) val t = buildTxSigComponent(adjustedLockTimeTx) val basePreProgram = PreExecutionScriptProgram(t) val baseProgram = basePreProgram.toExecutionInProgress val program = baseProgram.updateStackAndScript(stack, script) val newProgram = LTI.opCheckLockTimeVerify(program) - //if an error is hit, the newProgram will be an instance of ExecutedScriptProgram - //if an error is not hit it will still be a ExecutionInProgressScriptProgram + // if an error is hit, the newProgram will be an instance of ExecutedScriptProgram + // if an error is not hit it will still be a ExecutionInProgressScriptProgram newProgram.isInstanceOf[ExecutedScriptProgram] must be(false) } @@ -215,36 +262,45 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_CHECKSEQUENCEVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = LTI.opCheckSequenceVerify(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "mark the script as invalid for OP_CHECKSEQUENCEVERIFY if the stack top is negative" in { val stack = List(ScriptNumber.negativeOne) val script = List(OP_CHECKSEQUENCEVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = LTI.opCheckSequenceVerify(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorNegativeLockTime)) + Some(ScriptErrorNegativeLockTime) + ) } it must "mark the script as invalid for OP_CHECKSEQUENCEVERIFY if we are requiring minimal encoding of numbers and the stack top is not minimal" in { val stack = List(ScriptNumber("0100")) val script = List(OP_CHECKSEQUENCEVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = LTI.opCheckSequenceVerify(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorUnknownError)) + Some(ScriptErrorUnknownError) + ) } it must "treat OP_CHECKSEQUENCEVERIFY as a NOP if the locktime disabled flag is set in the sequence number" in { @@ -252,21 +308,25 @@ class LockTimeInterpreterTest extends BitcoinSUnitTest { List(ScriptNumber(TransactionConstants.locktimeDisabledFlag.toLong)) val script = List(OP_CHECKSEQUENCEVERIFY) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = LTI.opCheckSequenceVerify(program) newProgram.stack must be(stack) newProgram.script.isEmpty must be(true) } private def buildTxSigComponent( - adjustedLockTimeTx: BaseTransaction): TxSigComponent = { + adjustedLockTimeTx: BaseTransaction + ): TxSigComponent = { val t = BaseTxSigComponent( transaction = adjustedLockTimeTx, inputIndex = TestUtil.testProgram.txSignatureComponent.inputIndex, output = TransactionOutput( CurrencyUnits.zero, - TestUtil.testProgram.txSignatureComponent.scriptPubKey), + TestUtil.testProgram.txSignatureComponent.scriptPubKey + ), flags = TestUtil.testProgram.flags ) t diff --git a/core-test/src/test/scala/org/bitcoins/core/script/locktime/LocktimeOperationFactoryTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/locktime/LocktimeOperationFactoryTest.scala index a735c0b8ee..6a5c71b498 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/locktime/LocktimeOperationFactoryTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/locktime/LocktimeOperationFactoryTest.scala @@ -8,7 +8,8 @@ class LocktimeOperationFactoryTest extends BitcoinSUnitTest { "LocktimeOperationFactory" must "match lock time operations from strings" in { LocktimeOperation.fromStringOpt("OP_CHECKLOCKTIMEVERIFY") must be( - Some(OP_CHECKLOCKTIMEVERIFY)) + Some(OP_CHECKLOCKTIMEVERIFY) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/splice/SpliceInterpreterTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/splice/SpliceInterpreterTest.scala index 409bb275d5..0c22efa5bd 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/splice/SpliceInterpreterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/splice/SpliceInterpreterTest.scala @@ -15,8 +15,10 @@ class SpliceInterpreterTest extends BitcoinSUnitTest { val stack = List(OP_0) val script = List(OP_SIZE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opSize(program) newProgram.stack must be(List(OP_0, OP_0)) newProgram.script.isEmpty must be(true) @@ -27,8 +29,10 @@ class SpliceInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.zero) val script = List(OP_SIZE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opSize(program) newProgram.stack must be(List(ScriptNumber.zero, ScriptNumber.zero)) newProgram.script.isEmpty must be(true) @@ -38,20 +42,24 @@ class SpliceInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptConstant("7f")) val script = List(OP_SIZE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opSize(program) newProgram.stack must be(List(ScriptNumber(1), ScriptConstant("7f"))) newProgram.script.isEmpty must be(true) } it must "evaluate an OP_SIZE correctly with 0x8000" in { - //0x8000 == 128 in bitcoin + // 0x8000 == 128 in bitcoin val stack = List(ScriptNumber(128)) val script = List(OP_SIZE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opSize(program) newProgram.stack must be(List(ScriptNumber(2), ScriptNumber(128))) newProgram.script.isEmpty must be(true) @@ -61,8 +69,10 @@ class SpliceInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber(-1)) val script = List(OP_SIZE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opSize(program) newProgram.stack must be(List(ScriptNumber.one, ScriptNumber(-1))) newProgram.script.isEmpty must be(true) @@ -72,11 +82,14 @@ class SpliceInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_SIZE) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opSize(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/script/stack/StackInterpreterTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/stack/StackInterpreterTest.scala index 882b53df68..4d79f9173d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/stack/StackInterpreterTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/stack/StackInterpreterTest.scala @@ -18,8 +18,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_DUP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opDup(program) newProgram.stack.head must be(element1) @@ -31,8 +33,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { intercept[IllegalArgumentException] { val script = List() val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) SI.opDup(program) } } @@ -41,8 +45,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_DUP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) ScriptProgramTestUtil .toExecutedScriptProgram(SI.opDup(program)) .error must be(Some(ScriptErrorInvalidStackOperation)) @@ -52,8 +58,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { it must "evaluate the OP_DEPTH operator correctly" in { val script = List(OP_DEPTH) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opDepth(program) newProgram.stack.head.hex must be(BytesUtil.encodeHex(stack.size.toByte)) @@ -63,8 +71,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_DEPTH) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opDepth(program) newProgram.stack.head must be(ScriptNumber.zero) } @@ -73,8 +83,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List(OP_0) val script = List(OP_TOALTSTACK) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opToAltStack(program) newProgram.stack.isEmpty must be(true) @@ -87,8 +99,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List(OP_0) val script = List(OP_DROP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opDrop(program) newProgram.stack.isEmpty must be(true) @@ -99,20 +113,25 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List() val script = List(OP_DROP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opDrop(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "evaluate an OP_IFDUP correctly" in { val stack = List(ScriptNumber.zero) val script = List(OP_IFDUP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opIfDup(program) newProgram.stack must be(stack) @@ -120,8 +139,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack1 = List(OP_1) val program1 = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack1, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack1, + script + ) val newProgram1 = SI.opIfDup(program1) newProgram1.stack must be(List(OP_1, OP_1)) newProgram1.script.isEmpty must be(true) @@ -133,8 +154,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_NIP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opNip(program) @@ -147,8 +170,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_NIP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.opNip(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -160,8 +185,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_NIP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.opNip(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -171,8 +198,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List(OP_0, OP_1) val script = List(OP_OVER) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opOver(program) newProgram.stack must be(List(OP_1, OP_0, OP_1)) newProgram.script.isEmpty must be(true) @@ -183,8 +212,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_OVER) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.opOver(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -196,8 +227,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_OVER) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.opOver(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -205,21 +238,28 @@ class StackInterpreterTest extends BitcoinSUnitTest { } it must "evaluate an OP_PICK correctly" in { - val stack = List(ScriptNumber.zero, - ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16")) + val stack = List( + ScriptNumber.zero, + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16") + ) val script = List(OP_PICK) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opPick(program) newProgram.stack must be( - List(ScriptConstant("14"), - ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"))) + List( + ScriptConstant("14"), + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16") + ) + ) newProgram.script.isEmpty must be(true) } @@ -227,28 +267,36 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.one) val script = List(OP_PICK) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opPick(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "evaluate an OP_ROLL correctly" in { - val stack = List(ScriptNumber.zero, - ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16")) + val stack = List( + ScriptNumber.zero, + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16") + ) val script = List(OP_ROLL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opRoll(program) newProgram.stack must be( - List(ScriptConstant("14"), ScriptConstant("15"), ScriptConstant("16"))) + List(ScriptConstant("14"), ScriptConstant("15"), ScriptConstant("16")) + ) newProgram.script.isEmpty must be(true) } @@ -256,26 +304,32 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptNumber.one) val script = List(OP_ROLL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opRoll(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "mark an OP_ROLL as invalid if the script number is not minimall encoded" in { val stack = List(ScriptNumber("0100")) val script = List(OP_ROLL) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opRoll(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "evaluate an OP_ROT correctly" in { @@ -283,12 +337,15 @@ class StackInterpreterTest extends BitcoinSUnitTest { List(ScriptConstant("14"), ScriptConstant("15"), ScriptConstant("16")) val script = List(OP_ROT) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opRot(program) newProgram.stack must be( - List(ScriptConstant("16"), ScriptConstant("14"), ScriptConstant("15"))) + List(ScriptConstant("16"), ScriptConstant("14"), ScriptConstant("15")) + ) newProgram.script.isEmpty must be(true) } @@ -297,103 +354,133 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_ROT) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.opRot(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) } it must "evaluate an OP_2ROT correctly" in { - val stack = List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19")) + val stack = List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) val script = List(OP_2ROT) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.op2Rot(program) newProgram.stack must be( - List(ScriptConstant("18"), - ScriptConstant("19"), - ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"))) + List( + ScriptConstant("18"), + ScriptConstant("19"), + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17") + ) + ) newProgram.script.isEmpty must be(true) } it must "mark a scirpt as invalid if there is less than 6 elements on the stack for OP_2ROT" in { - val stack = List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18")) + val stack = List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18") + ) val script = List(OP_2ROT) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.op2Rot(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) } it must "evaluate an OP_2DROP correctly" in { - val stack = List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19")) + val stack = List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) val script = List(OP_2DROP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.op2Drop(program) newProgram.stack must be( - List(ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19"))) + List( + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) + ) } it must "mark a script invalid if an OP_2DROP script does not have two stack items" in { val stack = List(ScriptConstant("14")) val script = List(OP_2DROP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.op2Drop(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "evaluate an OP_SWAP correctly" in { - val stack = List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19")) + val stack = List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) val script = List(OP_SWAP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opSwap(program) newProgram.stack must be( - List(ScriptConstant("15"), - ScriptConstant("14"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19"))) + List( + ScriptConstant("15"), + ScriptConstant("14"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) + ) newProgram.script.isEmpty must be(true) } @@ -401,34 +488,44 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptConstant("14")) val script = List(OP_SWAP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opSwap(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "evaluate an OP_TUCK correctly" in { - val stack = List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19")) + val stack = List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) val script = List(OP_TUCK) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.opTuck(program) newProgram.stack must be( - List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("14"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19"))) + List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("14"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) + ) newProgram.script.isEmpty must be(true) } @@ -437,8 +534,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_TUCK) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.opTuck(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -446,16 +545,20 @@ class StackInterpreterTest extends BitcoinSUnitTest { } it must "evaluate an OP_2DUP correctly" in { - val stack = List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19")) + val stack = List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) val script = List(OP_2DUP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.op2Dup(program) newProgram.stack must be( List( @@ -467,7 +570,8 @@ class StackInterpreterTest extends BitcoinSUnitTest { ScriptConstant("17"), ScriptConstant("18"), ScriptConstant("19") - )) + ) + ) newProgram.script.isEmpty must be(true) } @@ -476,8 +580,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_2DUP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.op2Dup(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -485,16 +591,20 @@ class StackInterpreterTest extends BitcoinSUnitTest { } it must "evaluate an OP_3DUP correctly" in { - val stack = List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19")) + val stack = List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) val script = List(OP_3DUP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.op3Dup(program) newProgram.stack must be( @@ -508,7 +618,8 @@ class StackInterpreterTest extends BitcoinSUnitTest { ScriptConstant("17"), ScriptConstant("18"), ScriptConstant("19") - )) + ) + ) newProgram.script.isEmpty must be(true) } @@ -516,25 +627,32 @@ class StackInterpreterTest extends BitcoinSUnitTest { val stack = List(ScriptConstant("14"), ScriptConstant("15")) val script = List(OP_3DUP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.op3Dup(program) newProgram.isInstanceOf[ExecutedScriptProgram] must be(true) newProgram.asInstanceOf[ExecutedScriptProgram].error must be( - Some(ScriptErrorInvalidStackOperation)) + Some(ScriptErrorInvalidStackOperation) + ) } it must "evaluate an OP_2OVER correctly" in { - val stack = List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19")) + val stack = List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) val script = List(OP_2OVER) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.op2Over(program) newProgram.stack must be( @@ -547,7 +665,8 @@ class StackInterpreterTest extends BitcoinSUnitTest { ScriptConstant("17"), ScriptConstant("18"), ScriptConstant("19") - )) + ) + ) newProgram.script.isEmpty must be(true) } @@ -557,33 +676,42 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_2OVER) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.op2Over(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) } it must "evaluate an OP_2SWAP correctly" in { - val stack = List(ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("18"), - ScriptConstant("19")) + val stack = List( + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("18"), + ScriptConstant("19") + ) val script = List(OP_2SWAP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = SI.op2Swap(program) newProgram.stack must be( - List(ScriptConstant("16"), - ScriptConstant("17"), - ScriptConstant("14"), - ScriptConstant("15"), - ScriptConstant("18"), - ScriptConstant("19"))) + List( + ScriptConstant("16"), + ScriptConstant("17"), + ScriptConstant("14"), + ScriptConstant("15"), + ScriptConstant("18"), + ScriptConstant("19") + ) + ) newProgram.script.isEmpty must be(true) } @@ -593,8 +721,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_2SWAP) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val newProgram = ScriptProgramTestUtil.toExecutedScriptProgram(SI.op2Swap(program)) newProgram.error must be(Some(ScriptErrorInvalidStackOperation)) @@ -605,8 +735,10 @@ class StackInterpreterTest extends BitcoinSUnitTest { val script = List(OP_FROMALTSTACK) val altStack = List(OP_0) val program = - TestUtil.testProgramExecutionInProgress.updateStackAndScript(stack, - script) + TestUtil.testProgramExecutionInProgress.updateStackAndScript( + stack, + script + ) val programWithAltStack = program.updateAltStack(altStack) val executedProgram = SI.opFromAltStack(programWithAltStack) executedProgram.stack must be(altStack) diff --git a/core-test/src/test/scala/org/bitcoins/core/script/stack/StackOperationFactoryTest.scala b/core-test/src/test/scala/org/bitcoins/core/script/stack/StackOperationFactoryTest.scala index 769b80f4e7..41de2e7b16 100644 --- a/core-test/src/test/scala/org/bitcoins/core/script/stack/StackOperationFactoryTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/script/stack/StackOperationFactoryTest.scala @@ -9,7 +9,8 @@ class StackOperationFactoryTest extends BitcoinSUnitTest { "StackOperationFactory" must "match correct operations with their strings" in { StackOperation.fromStringOpt("OP_DUP") must be(Some(OP_DUP)) StackOperation.fromStringOpt("OP_FROMALTSTACK") must be( - Some(OP_FROMALTSTACK)) + Some(OP_FROMALTSTACK) + ) StackOperation.fromStringOpt("RANDOM_OP") must be(None) StackOperation.fromStringOpt("OP_IFDUP") must be(Some(OP_IFDUP)) } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/RawSerializerHelperSpec.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/RawSerializerHelperSpec.scala index 98c9444ce1..3a1f6d0f47 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/RawSerializerHelperSpec.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/RawSerializerHelperSpec.scala @@ -11,10 +11,12 @@ class RawSerializerHelperSpec extends Properties("RawSerializerHelperSpec") { Prop.forAll(TransactionGenerators.smallOutputs) { txs: Seq[TransactionOutput] => val serialized = - RawSerializerHelper.writeCmpctSizeUInt(txs, - { tx: TransactionOutput => - tx.bytes - }) + RawSerializerHelper.writeCmpctSizeUInt( + txs, + { tx: TransactionOutput => + tx.bytes + } + ) val (deserialized, remaining) = RawSerializerHelper .parseCmpctSizeUIntSeq(serialized, TransactionOutput(_: ByteVector)) deserialized == txs && remaining == ByteVector.empty diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawBlockHeaderSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawBlockHeaderSerializerTest.scala index ee924478f5..277914f085 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawBlockHeaderSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawBlockHeaderSerializerTest.scala @@ -6,13 +6,12 @@ import org.bitcoins.crypto.DoubleSha256Digest import org.bitcoins.testkitcore.util.BitcoinSUnitTest import scodec.bits.ByteVector -/** Values transmitted in the network are big-endian. - * Created by tom on 6/3/16. +/** Values transmitted in the network are big-endian. Created by tom on 6/3/16. */ class RawBlockHeaderSerializerTest extends BitcoinSUnitTest { - //genesis block - //https://en.bitcoin.it/wiki/Genesis_block - //https://insight.bitpay.com/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f + // genesis block + // https://en.bitcoin.it/wiki/Genesis_block + // https://insight.bitpay.com/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f val version = "01000000" val prevBlockHash = @@ -47,9 +46,9 @@ class RawBlockHeaderSerializerTest extends BitcoinSUnitTest { } it must "parse different block header with known values from dev reference" in { - //from bitcoin developer reference - //https://bitcoin.org/en/developer-reference#block-headers - //https://insight.bitpay.com/block/000000000000000009a11b3972c8e532fe964de937c9e0096b43814e67af3728 + // from bitcoin developer reference + // https://bitcoin.org/en/developer-reference#block-headers + // https://insight.bitpay.com/block/000000000000000009a11b3972c8e532fe964de937c9e0096b43814e67af3728 val version2 = "02000000" val prevBlockHash2 = "b6ff0b1b1680a2862a30ca44d346d9e8910d334beb48ca0c0000000000000000" @@ -72,13 +71,13 @@ class RawBlockHeaderSerializerTest extends BitcoinSUnitTest { } it must "parse/write testnet block header" in { - //https://test-insight.bitpay.com/block/00000000009fdf81e6efa251bc1902aedc07dc499cbe17db6e33db61eb64a7c5 + // https://test-insight.bitpay.com/block/00000000009fdf81e6efa251bc1902aedc07dc499cbe17db6e33db61eb64a7c5 val version = "00000020" val prevBlockHash = "06cd0fd35e1a102b93004d738561b56be94da29692d3b1d0c3dcf20000000000" val merkleRoot = "8dfb7407a20ac5c6bd890e56a37d41ceafae3d13e32ff8a5e63b72bc60214e24" - val timeStamp = "0ae75557" //1465247498 + val timeStamp = "0ae75557" // 1465247498 val nBits = "FFFF001D".toLowerCase val nonce = "43e3fe9e" val hex = version + prevBlockHash + merkleRoot + timeStamp + nBits + nonce diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawBlockSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawBlockSerializerTest.scala index b5125c5ac9..a9c1197f8d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawBlockSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawBlockSerializerTest.scala @@ -11,9 +11,9 @@ import scodec.bits.ByteVector /** Created by tom on 6/3/16. */ class RawBlockSerializerTest extends BitcoinSUnitTest { - //genesis block - //https://en.bitcoin.it/wiki/Genesis_block - //https://webbtc.com/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f + // genesis block + // https://en.bitcoin.it/wiki/Genesis_block + // https://webbtc.com/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f val version = "01000000" val prevBlockHash = @@ -45,7 +45,8 @@ class RawBlockSerializerTest extends BitcoinSUnitTest { block.blockHeader must be(RawBlockHeaderSerializer.read(header)) block.transactions must be(txSeq) block.blockHeader.hash.hex must be( - "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000") + "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" + ) block.hex must be(hex) } @@ -55,13 +56,13 @@ class RawBlockSerializerTest extends BitcoinSUnitTest { } it must "parse/write a block other than genesis" in { - //https://test-insight.bitpay.com/block/00000000009fdf81e6efa251bc1902aedc07dc499cbe17db6e33db61eb64a7c5 + // https://test-insight.bitpay.com/block/00000000009fdf81e6efa251bc1902aedc07dc499cbe17db6e33db61eb64a7c5 val version = "00000020" val merkleRoot = "8dfb7407a20ac5c6bd890e56a37d41ceafae3d13e32ff8a5e63b72bc60214e24" val prevBlockHash = "06cd0fd35e1a102b93004d738561b56be94da29692d3b1d0c3dcf20000000000" - val timeStamp = "0ae75557" //1465247498 + val timeStamp = "0ae75557" // 1465247498 val nBits = "FFFF001D".toLowerCase val nonce = "43e3fe9e" val header = @@ -76,13 +77,14 @@ class RawBlockSerializerTest extends BitcoinSUnitTest { val txSeq = List(tx1) val uInt = CompactSizeUInt(UInt64.one, 1) val hex = header + uInt.hex + rawTx1 - //matches real hex from - //https://test.webbtc.com/block/00000000009fdf81e6efa251bc1902aedc07dc499cbe17db6e33db61eb64a7c5.hex + // matches real hex from + // https://test.webbtc.com/block/00000000009fdf81e6efa251bc1902aedc07dc499cbe17db6e33db61eb64a7c5.hex val block = RawBlockSerializer.read(hex) block.blockHeader.hex must be(header) block.transactions must be(txSeq) block.blockHeader.hash.hex must be( - "c5a764eb61db336edb17be9c49dc07dcae0219bc51a2efe681df9f0000000000") + "c5a764eb61db336edb17be9c49dc07dcae0219bc51a2efe681df9f0000000000" + ) block.hex must be(hex) block.txCount must be(uInt) block.txCount.num must be(UInt64(1)) @@ -91,13 +93,13 @@ class RawBlockSerializerTest extends BitcoinSUnitTest { } it must "parse block with more than 1 transaction" in { - //https://test.webbtc.com/block/000000000000189efaecf3ed9108b9de5320671c66a161a038f87b3e11493d5f.json + // https://test.webbtc.com/block/000000000000189efaecf3ed9108b9de5320671c66a161a038f87b3e11493d5f.json val version = "00000020" val prevBlockHash = "cde33b7c310995d9e84777f3f409aa9f2cefe42ff6723d4a3174d80000000000" val merkleRoot = "cf836ca863a6ee66d49e5769642de08898b622774e4d2617b94dea247c60a685" - val timeStamp = "90895757" //in hex. 1465354640 as long + val timeStamp = "90895757" // in hex. 1465354640 as long val nBits = "6271191a" val nonce = "8f548695" val header = @@ -122,10 +124,12 @@ class RawBlockSerializerTest extends BitcoinSUnitTest { val block = RawBlockSerializer.read(hex) block.blockHeader.hash.hex must be( - "5f3d49113e7bf838a061a1661c672053deb90891edf3ecfa9e18000000000000") + "5f3d49113e7bf838a061a1661c672053deb90891edf3ecfa9e18000000000000" + ) block.blockHeader.version must be(Int32(536870912)) block.blockHeader.previousBlockHash must be( - DoubleSha256Digest(prevBlockHash)) + DoubleSha256Digest(prevBlockHash) + ) block.blockHeader.merkleRootHash must be(DoubleSha256Digest(merkleRoot)) block.blockHeader.time must be(UInt32(1465354640)) block.blockHeader.nBits must be(UInt32(437875042)) diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawMerkleBlockSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawMerkleBlockSerializerTest.scala index 1b97c5f5cb..994eddb022 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawMerkleBlockSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/blockchain/RawMerkleBlockSerializerTest.scala @@ -17,30 +17,40 @@ class RawMerkleBlockSerializerTest extends BitcoinSUnitTest { "RawMerkleBlockSerializer" must "serialize a merkle block generated inside of scalacheck" in { - val (merkleBlock, _) = (MerkleBlock( - BlockHeader( - Int32(49150652), - DoubleSha256Digest( - "6cf34aac6e3de2bf4b429d114ed4572a7ce4b1c44f2091ae6825ee9774dbae2f"), - DoubleSha256Digest( - "4487def8ba376b38c1e4e5910d3c9efd27e740cb9be8d452598cbf2e243fad8a"), - UInt32(2941790316L), - UInt32(1626267458), - UInt32(1688549344) - ), - UInt32(1), - PartialMerkleTree( - Leaf(DoubleSha256Digest( - "442abdc8e74ad35ebd9571f88fda91ff511dcda8d241a5aed52cea1e00d69e03")), - UInt32(1), - BitVector.bits( - Vector(false, false, false, false, false, - false, false, false)), - List(DoubleSha256Digest( - "442abdc8e74ad35ebd9571f88fda91ff511dcda8d241a5aed52cea1e00d69e03")) - ) - ), - List()) + val (merkleBlock, _) = ( + MerkleBlock( + BlockHeader( + Int32(49150652), + DoubleSha256Digest( + "6cf34aac6e3de2bf4b429d114ed4572a7ce4b1c44f2091ae6825ee9774dbae2f" + ), + DoubleSha256Digest( + "4487def8ba376b38c1e4e5910d3c9efd27e740cb9be8d452598cbf2e243fad8a" + ), + UInt32(2941790316L), + UInt32(1626267458), + UInt32(1688549344) + ), + UInt32(1), + PartialMerkleTree( + Leaf( + DoubleSha256Digest( + "442abdc8e74ad35ebd9571f88fda91ff511dcda8d241a5aed52cea1e00d69e03" + ) + ), + UInt32(1), + BitVector.bits( + Vector(false, false, false, false, false, false, false, false) + ), + List( + DoubleSha256Digest( + "442abdc8e74ad35ebd9571f88fda91ff511dcda8d241a5aed52cea1e00d69e03" + ) + ) + ) + ), + List() + ) val hex = "bcfaed026cf34aac6e3de2bf4b429d114ed4572a7ce4b1c44f2091ae6825ee9774dbae2f4487def8ba376b38c1e4e5910d3c9efd27e740cb9be8d452598cbf2e243fad8a6c2858af42dfee60e037a5640100000001442abdc8e74ad35ebd9571f88fda91ff511dcda8d241a5aed52cea1e00d69e030100" @@ -49,82 +59,113 @@ class RawMerkleBlockSerializerTest extends BitcoinSUnitTest { } it must "not have any extra hashes left over when deserializing a previously valid partial merkle tree" in { - val (merkleBlock, _) = (MerkleBlock( - BlockHeader( - Int32(1626792925), - DoubleSha256Digest( - "de2fc5fac498126f27c8adaa17aa86a1ef15d2b0adf5f2d2c056495bec17153f"), - DoubleSha256Digest( - "f27404d701b9047cfcaa8d8454d2ecc12f4aa3e900ba8e5945bbb9289d67dd63"), - UInt32(3098237133L), - UInt32(359220269), - UInt32(590323230) - ), - UInt32(6), - PartialMerkleTree( - Node( - DoubleSha256Digest( - "ed4f3665c72229886e4bdae876233892f8a7b85e5cee93da56be71d9056f6654"), - Node( - DoubleSha256Digest( - "2dc060204deff176f6e366319777d4db76546c17c07f23ebeece4bf0e66fd686"), - Node( - DoubleSha256Digest( - "8023ea73c6c1e643d1604585abbfd997308a5759baa4d2d4a2ee876d71a5780f"), - Leaf(DoubleSha256Digest( - "e4aeaf729035a7fb939e12c4f6a2072a9b2e7da784207ce7852d398593210a45")), - Leaf(DoubleSha256Digest( - "010506d2103d0feb477224926eedaf3d7478fe3d93b54bd24e5eb2c0adc309b3")) - ), - Node( - DoubleSha256Digest( - "79a03d2d9f1c5c97772974c9ef9297e6e2bce0271ca95d40bb598c6156c3d6e0"), - Leaf(DoubleSha256Digest( - "77352045b2995c9e0dfff9089e5563cd13914eb4b0723cdd54675c5c3f1c4f6a")), - Leaf(DoubleSha256Digest( - "7ae10c30932c07e4ed25abab233565f9ab279eabbcd60e1bc028c6cdc400361b")) - ) - ), - Leaf(DoubleSha256Digest( - "8ca2e6b66c55fbb63cb7c9b5ccd19be508034eedcd8511d216b9fe93aafc2ceb")) - ), - UInt32(6), - BitVector.bits( - List(true, true, true, false, true, true, - false, true, false, false, false, false, - false, false, false, false)), - List( - DoubleSha256Digest( - "e4aeaf729035a7fb939e12c4f6a2072a9b2e7da784207ce7852d398593210a45"), - DoubleSha256Digest( - "010506d2103d0feb477224926eedaf3d7478fe3d93b54bd24e5eb2c0adc309b3"), - DoubleSha256Digest( - "77352045b2995c9e0dfff9089e5563cd13914eb4b0723cdd54675c5c3f1c4f6a"), - DoubleSha256Digest( - "7ae10c30932c07e4ed25abab233565f9ab279eabbcd60e1bc028c6cdc400361b"), - DoubleSha256Digest( - "8ca2e6b66c55fbb63cb7c9b5ccd19be508034eedcd8511d216b9fe93aafc2ceb") - ) - ) - ), - List( - DoubleSha256Digest( - "010506d2103d0feb477224926eedaf3d7478fe3d93b54bd24e5eb2c0adc309b3"), - DoubleSha256Digest( - "7ae10c30932c07e4ed25abab233565f9ab279eabbcd60e1bc028c6cdc400361b") - )) + val (merkleBlock, _) = ( + MerkleBlock( + BlockHeader( + Int32(1626792925), + DoubleSha256Digest( + "de2fc5fac498126f27c8adaa17aa86a1ef15d2b0adf5f2d2c056495bec17153f" + ), + DoubleSha256Digest( + "f27404d701b9047cfcaa8d8454d2ecc12f4aa3e900ba8e5945bbb9289d67dd63" + ), + UInt32(3098237133L), + UInt32(359220269), + UInt32(590323230) + ), + UInt32(6), + PartialMerkleTree( + Node( + DoubleSha256Digest( + "ed4f3665c72229886e4bdae876233892f8a7b85e5cee93da56be71d9056f6654" + ), + Node( + DoubleSha256Digest( + "2dc060204deff176f6e366319777d4db76546c17c07f23ebeece4bf0e66fd686" + ), + Node( + DoubleSha256Digest( + "8023ea73c6c1e643d1604585abbfd997308a5759baa4d2d4a2ee876d71a5780f" + ), + Leaf( + DoubleSha256Digest( + "e4aeaf729035a7fb939e12c4f6a2072a9b2e7da784207ce7852d398593210a45" + ) + ), + Leaf( + DoubleSha256Digest( + "010506d2103d0feb477224926eedaf3d7478fe3d93b54bd24e5eb2c0adc309b3" + ) + ) + ), + Node( + DoubleSha256Digest( + "79a03d2d9f1c5c97772974c9ef9297e6e2bce0271ca95d40bb598c6156c3d6e0" + ), + Leaf( + DoubleSha256Digest( + "77352045b2995c9e0dfff9089e5563cd13914eb4b0723cdd54675c5c3f1c4f6a" + ) + ), + Leaf( + DoubleSha256Digest( + "7ae10c30932c07e4ed25abab233565f9ab279eabbcd60e1bc028c6cdc400361b" + ) + ) + ) + ), + Leaf( + DoubleSha256Digest( + "8ca2e6b66c55fbb63cb7c9b5ccd19be508034eedcd8511d216b9fe93aafc2ceb" + ) + ) + ), + UInt32(6), + BitVector.bits( + List(true, true, true, false, true, true, false, true, false, false, + false, false, false, false, false, false) + ), + List( + DoubleSha256Digest( + "e4aeaf729035a7fb939e12c4f6a2072a9b2e7da784207ce7852d398593210a45" + ), + DoubleSha256Digest( + "010506d2103d0feb477224926eedaf3d7478fe3d93b54bd24e5eb2c0adc309b3" + ), + DoubleSha256Digest( + "77352045b2995c9e0dfff9089e5563cd13914eb4b0723cdd54675c5c3f1c4f6a" + ), + DoubleSha256Digest( + "7ae10c30932c07e4ed25abab233565f9ab279eabbcd60e1bc028c6cdc400361b" + ), + DoubleSha256Digest( + "8ca2e6b66c55fbb63cb7c9b5ccd19be508034eedcd8511d216b9fe93aafc2ceb" + ) + ) + ) + ), + List( + DoubleSha256Digest( + "010506d2103d0feb477224926eedaf3d7478fe3d93b54bd24e5eb2c0adc309b3" + ), + DoubleSha256Digest( + "7ae10c30932c07e4ed25abab233565f9ab279eabbcd60e1bc028c6cdc400361b" + ) + ) + ) val hex = merkleBlock.hex val actualMerkleBlock = MerkleBlock(hex) actualMerkleBlock.partialMerkleTree.bits must be( - merkleBlock.partialMerkleTree.bits) + merkleBlock.partialMerkleTree.bits + ) actualMerkleBlock must be(merkleBlock) } it must "serialize and deserialize a merkle block from bitcoinj" in { - //https://github.com/bitcoinj/bitcoinj/blob/840df06b79beac1b984e6e247e90fcdedc4ad6e0/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java#L73 - //from this block - //000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45 + // https://github.com/bitcoinj/bitcoinj/blob/840df06b79beac1b984e6e247e90fcdedc4ad6e0/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java#L73 + // from this block + // 000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45 val hex = "0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101" val merkleBlock = MerkleBlock(hex) @@ -132,17 +173,25 @@ class RawMerkleBlockSerializerTest extends BitcoinSUnitTest { merkleBlock.hex must be(hex) merkleBlock.blockHeader.hash.hex must be( BytesUtil.flipEndianness( - "000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45")) + "000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45" + ) + ) val matches = merkleBlock.partialMerkleTree.extractMatches matches must be( - Seq(DoubleSha256Digest(BytesUtil.flipEndianness( - "63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")))) + Seq( + DoubleSha256Digest( + BytesUtil.flipEndianness( + "63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5" + ) + ) + ) + ) } it must "serialize and deserialize a merkle block with two bytes worth of bit flags" in { - //https://github.com/bitcoinj/bitcoinj/blob/840df06b79beac1b984e6e247e90fcdedc4ad6e0/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java#L129 + // https://github.com/bitcoinj/bitcoinj/blob/840df06b79beac1b984e6e247e90fcdedc4ad6e0/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java#L129 val hex = "0100000006e533fd1ada86391f3f6c343204b0d278d4aaec1c0b20aa27ba0300000000006abbb3eb3d733a9fe18967fd7d4c117" + "e4ccbbac5bec4d910d900b3ae0793e77f54241b4d4c86041b4089cc9b0c000000084c30b63cfcdc2d35e3329421b9805ef0c6565d35381c" + "a857762ea0b3a5a128bbca5065ff9617cbcba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefbbb15ac1d57d0182aaee61c74743" + diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/headers/RawNetworkHeaderSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/headers/RawNetworkHeaderSerializerTest.scala index f35f9dae56..5f9a4419b0 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/headers/RawNetworkHeaderSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/headers/RawNetworkHeaderSerializerTest.scala @@ -9,11 +9,11 @@ import scodec.bits._ class RawNetworkHeaderSerializerTest extends BitcoinSUnitTest { val hex = "f9beb4d976657261636b000000000000000000005df6e0e2" "RawMessageHeaderSerializer" must "read hex string into a message header" in { - //this example is from this section in the bitcoin developer reference - //https://bitcoin.org/en/developer-reference#message-headers + // this example is from this section in the bitcoin developer reference + // https://bitcoin.org/en/developer-reference#message-headers val messageHeader = RawNetworkHeaderSerializer.read(hex) - //this is the mainnet id + // this is the mainnet id messageHeader.network.magicBytes must be(hex"f9beb4d9") messageHeader.commandName must be("verack") diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrMessageSerializerTest.scala index a4a0013740..3bb57ea516 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrMessageSerializerTest.scala @@ -6,8 +6,8 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class RawAddrMessageSerializerTest extends BitcoinSUnitTest { - //from this bitcoin developer guide example - //https://bitcoin.org/en/developer-reference#addr + // from this bitcoin developer guide example + // https://bitcoin.org/en/developer-reference#addr val addressCount = "01" val time = "d91f4854" val services = "0100000000000000" diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrV2MessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrV2MessageSerializerTest.scala index 7822559d2d..2b24cd4797 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrV2MessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrV2MessageSerializerTest.scala @@ -16,10 +16,12 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { services <- NumberGenerator.compactSizeUInts addrBytes <- NumberGenerator.bytevector(AddrV2Message.IPV4_ADDR_LENGTH) port <- NumberGenerator.uInt16 - } yield IPv4AddrV2Message(time, - services, - InetAddress.getByAddress(addrBytes.toArray), - port) + } yield IPv4AddrV2Message( + time, + services, + InetAddress.getByAddress(addrBytes.toArray), + port + ) } def ipv6AddrV2MessageGen: Gen[IPv6AddrV2Message] = { @@ -28,10 +30,12 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { services <- NumberGenerator.compactSizeUInts addrBytes <- NumberGenerator.bytevector(AddrV2Message.IPV6_ADDR_LENGTH) port <- NumberGenerator.uInt16 - } yield IPv6AddrV2Message(time, - services, - InetAddress.getByAddress(addrBytes.toArray), - port) + } yield IPv6AddrV2Message( + time, + services, + InetAddress.getByAddress(addrBytes.toArray), + port + ) } def torV2AddrV2MessageGen: Gen[TorV2AddrV2Message] = { @@ -68,10 +72,12 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { addrBytes <- NumberGenerator.bytevector(AddrV2Message.CJDNS_ADDR_LENGTH - 1) port <- NumberGenerator.uInt16 - } yield CJDNSAddrV2Message(time, - services, - ByteVector.fromByte(0xfc.toByte) ++ addrBytes, - port) + } yield CJDNSAddrV2Message( + time, + services, + ByteVector.fromByte(0xfc.toByte) ++ addrBytes, + port + ) } def unknownAddrV2MessageGen: Gen[UnknownNetworkAddrV2Message] = { @@ -82,11 +88,13 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { !AddrV2Message.knownNetworkBytes.contains(byte)) addrBytes <- NumberGenerator.bytevector port <- NumberGenerator.uInt16 - } yield UnknownNetworkAddrV2Message(time, - services, - networkId, - addrBytes, - port) + } yield UnknownNetworkAddrV2Message( + time, + services, + networkId, + addrBytes, + port + ) } "IPv4AddrV2Message" must "have serialization symmetry" in { @@ -97,10 +105,12 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { it must "parse an IPv4AddrV2Message" in { val msg: IPv4AddrV2Message = - IPv4AddrV2Message(UInt32(4523), - CompactSizeUInt(UInt64(53453453L)), - InetAddress.getByAddress(hex"00000000".toArray), - UInt16(8333)) + IPv4AddrV2Message( + UInt32(4523), + CompactSizeUInt(UInt64(53453453L)), + InetAddress.getByAddress(hex"00000000".toArray), + UInt16(8333) + ) assert("000011abfe8da22f030100000000208d" == msg.hex) } @@ -116,10 +126,12 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { UInt32(4523), CompactSizeUInt(UInt64(53453453L)), InetAddress.getByAddress(hex"00000000000000000000000000000000".toArray), - UInt16(8333)) + UInt16(8333) + ) assert( - "000011abfe8da22f030200000000000000000000000000000000208d" == msg.hex) + "000011abfe8da22f030200000000000000000000000000000000208d" == msg.hex + ) } "TorV2AddrV2Message" must "have serialization symmetry" in { @@ -129,10 +141,12 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { } it must "parse a TorV2AddrV2Message" in { - val msg = TorV2AddrV2Message(UInt32(4523), - CompactSizeUInt(UInt64(53453453L)), - hex"00000000000000000000", - UInt16(8333)) + val msg = TorV2AddrV2Message( + UInt32(4523), + CompactSizeUInt(UInt64(53453453L)), + hex"00000000000000000000", + UInt16(8333) + ) assert("000011abfe8da22f030300000000000000000000208d" == msg.hex) } @@ -148,10 +162,12 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { UInt32(4523), CompactSizeUInt(UInt64(53453453L)), hex"0000000000000000000000000000000000000000000000000000000000000000", - UInt16(8333)) + UInt16(8333) + ) assert( - "000011abfe8da22f03040000000000000000000000000000000000000000000000000000000000000000208d" == msg.hex) + "000011abfe8da22f03040000000000000000000000000000000000000000000000000000000000000000208d" == msg.hex + ) } "I2PAddrV2Message" must "have serialization symmetry" in { @@ -165,10 +181,12 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { UInt32(4523), CompactSizeUInt(UInt64(53453453L)), hex"0000000000000000000000000000000000000000000000000000000000000000", - UInt16(8333)) + UInt16(8333) + ) assert( - "000011abfe8da22f03050000000000000000000000000000000000000000000000000000000000000000208d" == msg.hex) + "000011abfe8da22f03050000000000000000000000000000000000000000000000000000000000000000208d" == msg.hex + ) } "CJDNSAddrV2Message" must "have serialization symmetry" in { @@ -178,13 +196,16 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { } it must "parse a CJDNSAddrV2Message" in { - val msg = CJDNSAddrV2Message(UInt32(4523), - CompactSizeUInt(UInt64(53453453L)), - hex"fc000000000000000000000000000000", - UInt16(8333)) + val msg = CJDNSAddrV2Message( + UInt32(4523), + CompactSizeUInt(UInt64(53453453L)), + hex"fc000000000000000000000000000000", + UInt16(8333) + ) assert( - "000011abfe8da22f0306fc000000000000000000000000000000208d" == msg.hex) + "000011abfe8da22f0306fc000000000000000000000000000000208d" == msg.hex + ) } "UnknownNetworkAddrV2Message" must "have serialization symmetry" in { @@ -194,13 +215,16 @@ class RawAddrV2MessageSerializerTest extends BitcoinSUnitTest { } it must "parse a UnknownNetworkAddrV2Message" in { - val msg = UnknownNetworkAddrV2Message(UInt32(4523), - CompactSizeUInt(UInt64(53453453L)), - 0x07, - hex"00000000000000000000000000000000", - UInt16(8333)) + val msg = UnknownNetworkAddrV2Message( + UInt32(4523), + CompactSizeUInt(UInt64(53453453L)), + 0x07, + hex"00000000000000000000000000000000", + UInt16(8333) + ) assert( - "000011abfe8da22f030700000000000000000000000000000000208d" == msg.hex) + "000011abfe8da22f030700000000000000000000000000000000208d" == msg.hex + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterCheckPointMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterCheckPointMessageSerializerTest.scala index 27a69e0b69..50a1697815 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterCheckPointMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterCheckPointMessageSerializerTest.scala @@ -20,16 +20,22 @@ class RawCompactFilterCheckPointMessageSerializerTest extends BitcoinSUnitTest { assert(message.filterType == FilterType.Basic) assert( message.stopHash == DoubleSha256Digest.fromHex( - "6f0ee334fbba823804e14042c33bc5dfa5126e5076d8dcff02d4a045f266f427")) + "6f0ee334fbba823804e14042c33bc5dfa5126e5076d8dcff02d4a045f266f427" + ) + ) assert( message.filterHeaders == Vector( DoubleSha256Digest.fromHex( - "93daaed620ff44fb7a760860ee8084f7f8c722d6c7ea9d1e1a35059253f876e6"), + "93daaed620ff44fb7a760860ee8084f7f8c722d6c7ea9d1e1a35059253f876e6" + ), DoubleSha256Digest.fromHex( - "2c2faad9d5e25594914772dc815e157debf385cbe5de5a0aea59d15af42b19ad"), + "2c2faad9d5e25594914772dc815e157debf385cbe5de5a0aea59d15af42b19ad" + ), DoubleSha256Digest.fromHex( - "dd9cc1baf1453d682d27958c0f64c97a69249d655151c3b25b1ef1a993ec4f4f") - )) + "dd9cc1baf1453d682d27958c0f64c97a69249d655151c3b25b1ef1a993ec4f4f" + ) + ) + ) } it must "have serialization symmetry" in { @@ -46,7 +52,8 @@ class RawCompactFilterCheckPointMessageSerializerTest extends BitcoinSUnitTest { val biggerMessage = CompactFilterCheckPointMessage( filterType = FilterType.Basic, stopHash = DoubleSha256Digest.fromHex( - "0000000000000000000000000000000000000000000000000000000000000001"), + "0000000000000000000000000000000000000000000000000000000000000001" + ), filterHeaders = 1.to(20000).toVector.map(_ => DoubleSha256Digest.empty) ) diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterHeadersMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterHeadersMessageSerializerTest.scala index 148edc85fb..edc327b761 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterHeadersMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterHeadersMessageSerializerTest.scala @@ -22,17 +22,23 @@ class RawCompactFilterHeadersMessageSerializerTest extends BitcoinSUnitTest { assert(message.filterType == FilterType.Basic) assert( message.stopHash == DoubleSha256Digest.fromHex( - "226f1acd30ec19b541dba2478b673a142283bb39ccddef75015e3caf0ec89f48")) + "226f1acd30ec19b541dba2478b673a142283bb39ccddef75015e3caf0ec89f48" + ) + ) assert(message.previousFilterHeader == DoubleSha256Digest.empty) assert( message.filterHashes == Vector( DoubleSha256Digest.fromHex( - "1f30de30fabb7892d15eb985cc5d6c34c54a11b7e4c51f3da498f16255a27bb1"), + "1f30de30fabb7892d15eb985cc5d6c34c54a11b7e4c51f3da498f16255a27bb1" + ), DoubleSha256Digest.fromHex( - "57965194aaa7ad3890c977d1b3c738d0a43a357ec645df28dc5c21876fb529c4"), + "57965194aaa7ad3890c977d1b3c738d0a43a357ec645df28dc5c21876fb529c4" + ), DoubleSha256Digest.fromHex( - "87eb3f35daf3b6adba13b40c2f0d0e99dee59b624b0e09d870894e1a0d6d3bb0") - )) + "87eb3f35daf3b6adba13b40c2f0d0e99dee59b624b0e09d870894e1a0d6d3bb0" + ) + ) + ) } it must "have serialization symmetry" in { @@ -52,9 +58,11 @@ class RawCompactFilterHeadersMessageSerializerTest extends BitcoinSUnitTest { val biggerMessage = CompactFilterHeadersMessage( filterType = FilterType.Basic, stopHash = DoubleSha256Digest.fromHex( - "0000000000000000000000000000000000000000000000000000000000000001"), + "0000000000000000000000000000000000000000000000000000000000000001" + ), previousFilterHeader = DoubleSha256Digest.fromHex( - "0000000000000000000000000000000000000000000000000000000000000002"), + "0000000000000000000000000000000000000000000000000000000000000002" + ), filterHashes = 1.to(2000).toVector.map(_ => DoubleSha256Digest.empty) ) diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterMessageSerializerTest.scala index 61d2601696..f983d02a8c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterMessageSerializerTest.scala @@ -20,7 +20,9 @@ class RawCompactFilterMessageSerializerTest extends BitcoinSUnitTest { assert(message.filterType == FilterType.Basic) assert( message.blockHash == DoubleSha256Digest.fromHex( - "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000")) + "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" + ) + ) assert(message.filterBytes == hex"017fa880") } @@ -36,17 +38,21 @@ class RawCompactFilterMessageSerializerTest extends BitcoinSUnitTest { assert(message.bytes == bytes) val blockHash = DoubleSha256Digest.fromHex( - "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000") + "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000" + ) val fromFilter = - CompactFilterMessage(blockHash, - BlockFilter.fromBytes(hex"017fa880", blockHash)) + CompactFilterMessage( + blockHash, + BlockFilter.fromBytes(hex"017fa880", blockHash) + ) assert(message.bytes == fromFilter.bytes) val biggerMessage = CompactFilterMessage( filterType = FilterType.Basic, blockHash = DoubleSha256Digest.fromHex( - "0000000000000000000000000000000000000000000000000000000000000001"), + "0000000000000000000000000000000000000000000000000000000000000001" + ), filterBytes = ByteVector.fill(100000)(0xaa) ) diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterAddMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterAddMessageSerializerTest.scala index 1507986582..7f6166edce 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterAddMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterAddMessageSerializerTest.scala @@ -5,14 +5,15 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class RawFilterAddMessageSerializerTest extends BitcoinSUnitTest { - //https://bitcoin.org/en/developer-reference#filteradd + // https://bitcoin.org/en/developer-reference#filteradd val hex = "20" + "fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b" "RawFilterAddMessageSerializer" must "deserialize a message in the bitcoin developer reference" in { val filterAddMsg = RawFilterAddMessageSerializer.read(hex) filterAddMsg.elementSize.hex must be("20") BytesUtil.encodeHex(filterAddMsg.element) must be( - "fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b") + "fdacf9b3eb077412e7a968d2e4f11b9a9dee312d666187ed77ee7d26af16cb0b" + ) } it must "serialize a filter add message" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterLoadMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterLoadMessageSerializerTest.scala index 40e1ee58d7..a00f2892e5 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterLoadMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterLoadMessageSerializerTest.scala @@ -11,8 +11,8 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class RawFilterLoadMessageSerializerTest extends BitcoinSUnitTest { "RawFilterLoadMessageSerializer" must "deserialize and serialize a filter load message" in { - //example from the bitcoin developer reference - //https://bitcoin.org/en/developer-reference#filterload + // example from the bitcoin developer reference + // https://bitcoin.org/en/developer-reference#filterload val hex = "02b50f0b0000000000000000" val filterLoadMsg = RawFilterLoadMessageSerializer.read(hex) diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetBlocksMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetBlocksMessageSerializerTest.scala index cbcdcf8ea4..b05b93d2f5 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetBlocksMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetBlocksMessageSerializerTest.scala @@ -26,16 +26,24 @@ class RawGetBlocksMessageSerializerTest extends BitcoinSUnitTest { getBlocksMessage.blockHeaderHashes.head must be (DoubleSha256Digest( BytesUtil.decodeHex( - "d39f608a7775b537729884d4e6633bb2105e55a16a14d31b0000000000000000"))) + "d39f608a7775b537729884d4e6633bb2105e55a16a14d31b0000000000000000" + ) + )) getBlocksMessage.blockHeaderHashes.tail.head must be (DoubleSha256Digest( BytesUtil.decodeHex( - "5c3e6403d40837110a2e8afb602b1c01714bda7ce23bea0a0000000000000000"))) + "5c3e6403d40837110a2e8afb602b1c01714bda7ce23bea0a0000000000000000" + ) + )) getBlocksMessage.stopHash must be( - DoubleSha256Digest(BytesUtil.decodeHex( - "0000000000000000000000000000000000000000000000000000000000000000"))) + DoubleSha256Digest( + BytesUtil.decodeHex( + "0000000000000000000000000000000000000000000000000000000000000000" + ) + ) + ) } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterCheckpointMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterCheckpointMessageSerializerTest.scala index 0572845e49..3a94221b1c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterCheckpointMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterCheckpointMessageSerializerTest.scala @@ -11,7 +11,7 @@ class RawGetCompactFilterCheckpointMessageSerializerTest it must "parse a message" in { // cribbed from a P2P log dump with Bitcoin-S node - val bytes = hex"00" ++ //type + val bytes = hex"00" ++ // type hex"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" // stop hash val message = GetCompactFilterCheckPointMessage.fromBytes(bytes) @@ -19,12 +19,14 @@ class RawGetCompactFilterCheckpointMessageSerializerTest assert(message.filterType == FilterType.Basic) assert( message.stopHash == DoubleSha256Digest.fromHex( - "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f")) + "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" + ) + ) } it must "have serialization symmetry" in { - val bytes = hex"00" ++ //type + val bytes = hex"00" ++ // type hex"06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f" // stop hash val message = GetCompactFilterCheckPointMessage.fromBytes(bytes) @@ -33,13 +35,17 @@ class RawGetCompactFilterCheckpointMessageSerializerTest val anotherMessage = GetCompactFilterCheckPointMessage( DoubleSha256Digest.fromHex( - "8000000000000000000000000000000000000000000000000000000000000001")) + "8000000000000000000000000000000000000000000000000000000000000001" + ) + ) val anotherBytes = anotherMessage.bytes assert( anotherMessage == GetCompactFilterCheckPointMessage.fromBytes( - anotherBytes)) + anotherBytes + ) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterHeadersMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterHeadersMessageSerializerTest.scala index 1e5f979310..b0d0c40d61 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterHeadersMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterHeadersMessageSerializerTest.scala @@ -20,7 +20,9 @@ class RawGetCompactFilterHeadersMessageSerializerTest extends BitcoinSUnitTest { assert(message.startHeight.toInt == 2000) assert( message.stopHash == DoubleSha256Digest.fromHex( - "6f0ee334fbba823804e14042c33bc5dfa5126e5076d8dcff02d4a045f266f427")) + "6f0ee334fbba823804e14042c33bc5dfa5126e5076d8dcff02d4a045f266f427" + ) + ) } it must "have serialization symmetry" in { @@ -35,12 +37,15 @@ class RawGetCompactFilterHeadersMessageSerializerTest extends BitcoinSUnitTest { val anotherMessage = GetCompactFilterHeadersMessage( 0x0180, DoubleSha256Digest.fromHex( - "8000000000000000000000000000000000000000000000000000000000000001")) + "8000000000000000000000000000000000000000000000000000000000000001" + ) + ) val anotherBytes = anotherMessage.bytes assert( - anotherMessage == GetCompactFilterHeadersMessage.fromBytes(anotherBytes)) + anotherMessage == GetCompactFilterHeadersMessage.fromBytes(anotherBytes) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFiltersMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFiltersMessageSerializerTest.scala index ef3756f6cb..5972d951f6 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFiltersMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFiltersMessageSerializerTest.scala @@ -10,7 +10,7 @@ class RawGetCompactFiltersMessageSerializerTest extends BitcoinSUnitTest { it must "parse a message" in { // cribbed from a P2P log dump with Bitcoin-S node - val bytes = hex"00" ++ //type + val bytes = hex"00" ++ // type hex"1d0c0000" ++ // start height hex"83abc1c5f4d8c065208b3c0b5f8b61a373c79b647b0421c56ee50c6f0ddd2917" // stop hash @@ -20,11 +20,13 @@ class RawGetCompactFiltersMessageSerializerTest extends BitcoinSUnitTest { assert(message.startHeight.toInt == 3101) assert( message.stopHash == DoubleSha256Digest.fromHex( - "83abc1c5f4d8c065208b3c0b5f8b61a373c79b647b0421c56ee50c6f0ddd2917")) + "83abc1c5f4d8c065208b3c0b5f8b61a373c79b647b0421c56ee50c6f0ddd2917" + ) + ) } it must "have serialization symmetry" in { - val bytes = hex"00" ++ //type + val bytes = hex"00" ++ // type hex"1d0c0000" ++ // start height hex"83abc1c5f4d8c065208b3c0b5f8b61a373c79b647b0421c56ee50c6f0ddd2917" // stop hash @@ -35,7 +37,9 @@ class RawGetCompactFiltersMessageSerializerTest extends BitcoinSUnitTest { val anotherMessage = GetCompactFiltersMessage( 0x0180, DoubleSha256Digest.fromHex( - "8000000000000000000000000000000000000000000000000000000000000001")) + "8000000000000000000000000000000000000000000000000000000000000001" + ) + ) val anotherBytes = anotherMessage.bytes diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetDataMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetDataMessageSerializerTest.scala index 9964d66055..1a14a4e577 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetDataMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetDataMessageSerializerTest.scala @@ -11,9 +11,9 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest */ class RawGetDataMessageSerializerTest extends BitcoinSUnitTest { - //from bitcoin developer reference - //a getdata message is essentially an inv message - //https://bitcoin.org/en/developer-reference#inv + // from bitcoin developer reference + // a getdata message is essentially an inv message + // https://bitcoin.org/en/developer-reference#inv val hex = "02" + "01000000" + "de55ffd709ac1f5dc509a0925d0b1fc442ca034f224732e429081da1b621f55a" + "01000000" + "91d36d997037e08018262978766f24b8a055aaf1d872e94ae85e9817b2c68dc7" @@ -25,12 +25,18 @@ class RawGetDataMessageSerializerTest extends BitcoinSUnitTest { Inventory( MsgTx, DoubleSha256Digest( - "de55ffd709ac1f5dc509a0925d0b1fc442ca034f224732e429081da1b621f55a"))) + "de55ffd709ac1f5dc509a0925d0b1fc442ca034f224732e429081da1b621f55a" + ) + ) + ) dataMsg.inventories(1) must be( Inventory( MsgTx, DoubleSha256Digest( - "91d36d997037e08018262978766f24b8a055aaf1d872e94ae85e9817b2c68dc7"))) + "91d36d997037e08018262978766f24b8a055aaf1d872e94ae85e9817b2c68dc7" + ) + ) + ) } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetHeadersMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetHeadersMessageSerializerTest.scala index a36020ca97..cf63782584 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetHeadersMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawGetHeadersMessageSerializerTest.scala @@ -20,7 +20,9 @@ class RawGetHeadersMessageSerializerTest extends BitcoinSUnitTest { getHeadersMessage.hashStop must be( DoubleSha256Digest( - "0000000000000000000000000000000000000000000000000000000000000000")) + "0000000000000000000000000000000000000000000000000000000000000000" + ) + ) } it must "write a GetHeaderMessage" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawHeadersMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawHeadersMessageSerializerTest.scala index aaa1beb6bf..346cda9211 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawHeadersMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawHeadersMessageSerializerTest.scala @@ -10,8 +10,8 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest */ class RawHeadersMessageSerializerTest extends BitcoinSUnitTest { - //from this example - //https://bitcoin.org/en/developer-reference#headers + // from this example + // https://bitcoin.org/en/developer-reference#headers val hex = "01" + "02000000" + "b6ff0b1b1680a2862a30ca44d346d9e8910d334beb48ca0c0000000000000000" + @@ -25,10 +25,14 @@ class RawHeadersMessageSerializerTest extends BitcoinSUnitTest { headersMsg.count must be(CompactSizeUInt(UInt64.one, 1)) header.previousBlockHash must be( DoubleSha256Digest( - "b6ff0b1b1680a2862a30ca44d346d9e8910d334beb48ca0c0000000000000000")) + "b6ff0b1b1680a2862a30ca44d346d9e8910d334beb48ca0c0000000000000000" + ) + ) header.merkleRootHash must be( DoubleSha256Digest( - "9d10aa52ee949386ca9385695f04ede270dda20810decd12bc9b048aaab31471")) + "9d10aa52ee949386ca9385695f04ede270dda20810decd12bc9b048aaab31471" + ) + ) header.time must be(UInt32(1415239972)) header.nBits must be(UInt32(BytesUtil.flipEndianness("30c31b18"))) header.nonce must be(UInt32(BytesUtil.flipEndianness("fe9f0864"))) @@ -46,22 +50,34 @@ class RawHeadersMessageSerializerTest extends BitcoinSUnitTest { val first = headersMsg.headers.head first.previousBlockHash.hex must be( BytesUtil.flipEndianness( - "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")) + "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943" + ) + ) first.hash.hex must be( BytesUtil.flipEndianness( - "00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206")) + "00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206" + ) + ) first.merkleRootHash.hex must be( BytesUtil.flipEndianness( - "f0315ffc38709d70ad5647e22048358dd3745f3ce3874223c80a7c92fab0c8ba")) + "f0315ffc38709d70ad5647e22048358dd3745f3ce3874223c80a7c92fab0c8ba" + ) + ) val second = headersMsg.headers(1) second.previousBlockHash.hex must be( BytesUtil.flipEndianness( - "00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206")) + "00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206" + ) + ) second.hash.hex must be( BytesUtil.flipEndianness( - "000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820")) + "000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820" + ) + ) second.merkleRootHash.hex must be( BytesUtil.flipEndianness( - "20222eb90f5895556926c112bb5aa0df4ab5abc3107e21a6950aec3b2e3541e2")) + "20222eb90f5895556926c112bb5aa0df4ab5abc3107e21a6950aec3b2e3541e2" + ) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawInventoryMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawInventoryMessageSerializerTest.scala index e0b33d69a1..4f55d4fd59 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawInventoryMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawInventoryMessageSerializerTest.scala @@ -8,8 +8,8 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest */ class RawInventoryMessageSerializerTest extends BitcoinSUnitTest { - //from bitcoin developer reference - //https://bitcoin.org/en/developer-reference#inv + // from bitcoin developer reference + // https://bitcoin.org/en/developer-reference#inv val hex = "0201000000de55ffd709ac1f5dc509a0925d0b1fc442ca034f224732e429081da1b621f55a" + "0100000091d36d997037e08018262978766f24b8a055aaf1d872e94ae85e9817b2c68dc7" diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawInventorySerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawInventorySerializerTest.scala index 2d831ef84f..d499cad5e7 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawInventorySerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawInventorySerializerTest.scala @@ -9,8 +9,8 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest */ class RawInventorySerializerTest extends BitcoinSUnitTest { - //from bitcoin developer reference example section - //https://bitcoin.org/en/developer-reference#inv + // from bitcoin developer reference example section + // https://bitcoin.org/en/developer-reference#inv val hex = "01000000de55ffd709ac1f5dc509a0925d0b1fc442ca034f224732e429081da1b621f55a" "RawInventorySerializer" must "read a inventory object from its hex representation" in { @@ -19,7 +19,9 @@ class RawInventorySerializerTest extends BitcoinSUnitTest { inventory.hash must be (DoubleSha256Digest( BytesUtil.decodeHex( - "de55ffd709ac1f5dc509a0925d0b1fc442ca034f224732e429081da1b621f55a"))) + "de55ffd709ac1f5dc509a0925d0b1fc442ca034f224732e429081da1b621f55a" + ) + )) } it must "write a inventory object to its serialized format" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawMerkleBlockMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawMerkleBlockMessageSerializerTest.scala index fc1a99d87c..e8c59c7131 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawMerkleBlockMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawMerkleBlockMessageSerializerTest.scala @@ -9,8 +9,8 @@ import scodec.bits.BitVector class RawMerkleBlockMessageSerializerTest extends BitcoinSUnitTest { - //from bitcoin developer reference - //https://bitcoin.org/en/developer-reference#merkleblock + // from bitcoin developer reference + // https://bitcoin.org/en/developer-reference#merkleblock val hex = "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc88067010000000000" + "7f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d97287" + @@ -29,18 +29,32 @@ class RawMerkleBlockMessageSerializerTest extends BitcoinSUnitTest { merkleBlockMessage.merkleBlock.hashes must be( Seq( - DoubleSha256Digest(BytesUtil.decodeHex( - "3612262624047ee87660be1a707519a443b1c1ce3d248cbfc6c15870f6c5daa2")), - DoubleSha256Digest(BytesUtil.decodeHex( - "019f5b01d4195ecbc9398fbf3c3b1fa9bb3183301d7a1fb3bd174fcfa40a2b65")), - DoubleSha256Digest(BytesUtil.decodeHex( - "41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068")), - DoubleSha256Digest(BytesUtil.decodeHex( - "20d2a7bc994987302e5b1ac80fc425fe25f8b63169ea78e68fbaaefa59379bbf")) - )) + DoubleSha256Digest( + BytesUtil.decodeHex( + "3612262624047ee87660be1a707519a443b1c1ce3d248cbfc6c15870f6c5daa2" + ) + ), + DoubleSha256Digest( + BytesUtil.decodeHex( + "019f5b01d4195ecbc9398fbf3c3b1fa9bb3183301d7a1fb3bd174fcfa40a2b65" + ) + ), + DoubleSha256Digest( + BytesUtil.decodeHex( + "41ed70551dd7e841883ab8f0b16bf04176b7d1480e4f0af9f3d4c3595768d068" + ) + ), + DoubleSha256Digest( + BytesUtil.decodeHex( + "20d2a7bc994987302e5b1ac80fc425fe25f8b63169ea78e68fbaaefa59379bbf" + ) + ) + ) + ) merkleBlockMessage.merkleBlock.partialMerkleTree.bits must be( - BitVector.fromValidBin("10111000")) + BitVector.fromValidBin("10111000") + ) } it must "write a merkle block header message" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawNetworkIpAddressSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawNetworkIpAddressSerializerTest.scala index f1c3e22a3f..82fab5e969 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawNetworkIpAddressSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawNetworkIpAddressSerializerTest.scala @@ -6,8 +6,8 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class RawNetworkIpAddressSerializerTest extends BitcoinSUnitTest { - //from this bitcoin developer guide example - //https://bitcoin.org/en/developer-reference#addr + // from this bitcoin developer guide example + // https://bitcoin.org/en/developer-reference#addr val time = "d91f4854" val services = "0100000000000000" val address = "00000000000000000000ffffc0000233" diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawNotFoundMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawNotFoundMessageSerializerTest.scala index 14b1cfa6d1..ddd9e71596 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawNotFoundMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawNotFoundMessageSerializerTest.scala @@ -6,10 +6,10 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class RawNotFoundMessageSerializerTest extends BitcoinSUnitTest { - //according to the developer reference, the format for inventory messages and - //not found messages are the same - //from bitcoin developer reference - //https://bitcoin.org/en/developer-reference#inv + // according to the developer reference, the format for inventory messages and + // not found messages are the same + // from bitcoin developer reference + // https://bitcoin.org/en/developer-reference#inv val hex = "0201000000de55ffd709ac1f5dc509a0925d0b1fc442ca034f224732e429081da1b621f55a" + "0100000091d36d997037e08018262978766f24b8a055aaf1d872e94ae85e9817b2c68dc7" diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawRejectMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawRejectMessageSerializerTest.scala index 4ffbbb222f..951fe22b7d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawRejectMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawRejectMessageSerializerTest.scala @@ -9,7 +9,7 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest */ class RawRejectMessageSerializerTest extends BitcoinSUnitTest { - //https://bitcoin.org/en/developer-reference#reject + // https://bitcoin.org/en/developer-reference#reject val hex = "02" + "7478" + "12" + "15" + "6261642d74786e732d696e707574732d7370656e74" + "394715fcab51093be7bfca5a31005972947baf86a31017939575fb2354222821" @@ -22,7 +22,8 @@ class RawRejectMessageSerializerTest extends BitcoinSUnitTest { rejectMsg.reasonSize must be(CompactSizeUInt(UInt64(21))) rejectMsg.reason must be("bad-txns-inputs-spent") BytesUtil.encodeHex(rejectMsg.extra) must be( - "394715fcab51093be7bfca5a31005972947baf86a31017939575fb2354222821") + "394715fcab51093be7bfca5a31005972947baf86a31017939575fb2354222821" + ) } it must "read then write a reject message" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawTransactionMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawTransactionMessageSerializerTest.scala index ab8b816a23..b40d89f484 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawTransactionMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawTransactionMessageSerializerTest.scala @@ -11,13 +11,16 @@ class RawTransactionMessageSerializerTest extends BitcoinSUnitTest { RawTransactionMessageSerializer.read(P2PMessageTestUtil.rawTransaction) txMessage.transaction.txId.hex must be( BytesUtil.flipEndianness( - "44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff")) + "44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff" + ) + ) } it must "write a TransactionMessage to its hex format" in { val txMessage = RawTransactionMessageSerializer.read(P2PMessageTestUtil.rawTransaction) RawTransactionMessageSerializer.write(txMessage).toHex must be( - P2PMessageTestUtil.rawTransaction) + P2PMessageTestUtil.rawTransaction + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawVersionMessageSerializerTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawVersionMessageSerializerTest.scala index f7e706011c..c9c9785461 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawVersionMessageSerializerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/p2p/messages/RawVersionMessageSerializerTest.scala @@ -9,8 +9,8 @@ import scodec.bits._ class RawVersionMessageSerializerTest extends BitcoinSUnitTest { - //take from the bitcoin developer reference underneath this section - //https://bitcoin.org/en/developer-reference#version + // take from the bitcoin developer reference underneath this section + // https://bitcoin.org/en/developer-reference#version val protocolVersion = "72110100" val services = "0100000000000000" @@ -53,7 +53,8 @@ class RawVersionMessageSerializerTest extends BitcoinSUnitTest { versionMessage.addressTransPort must be(8333) versionMessage.nonce.toBigInt must be( - BigInt(BytesUtil.decodeHex(nonce).toArray)) + BigInt(BytesUtil.decodeHex(nonce).toArray) + ) versionMessage.userAgentSize must be(CompactSizeUInt(UInt64(15), 1)) versionMessage.userAgent must be("/Satoshi:0.9.3/") @@ -68,8 +69,8 @@ class RawVersionMessageSerializerTest extends BitcoinSUnitTest { } it must "read a VersionMessage that bitcoins created" in { - //random version message bitcoins created when connecting to a testnet seed - //and sending it a version message + // random version message bitcoins created when connecting to a testnet seed + // and sending it a version message val hex = "7c1101000000000000000000d805833655010000000000000000000000000000000000000000ffff0a940106479d010000000000000000000000000000000000ffff739259bb479d0000000000000000182f626974636f696e732d7370762d6e6f64652f302e302e310000000000" val versionMessage = RawVersionMessageSerializer.read(hex) @@ -100,17 +101,20 @@ class RawVersionMessageSerializerTest extends BitcoinSUnitTest { assert(versionMessage.services.nodeNetwork) versionMessage.timestamp must be(Int64(-4420735367386806222L)) versionMessage.addressReceiveIpAddress must be( - InetAddress(hex"00000000000000000000ffff00000000")) + InetAddress(hex"00000000000000000000ffff00000000") + ) assert(versionMessage.addressReceiveServices.nodeNone) versionMessage.addressReceivePort must be(17057) assert(versionMessage.addressTransServices.nodeNone) versionMessage.addressTransIpAddress must be( - InetAddress(hex"00000000000000000000ffff00000000")) + InetAddress(hex"00000000000000000000ffff00000000") + ) versionMessage.addressTransPort must be(41963) versionMessage.nonce must be(UInt64(BigInt("9223372036854775809"))) versionMessage.userAgentSize must be(CompactSizeUInt(UInt64(86), 1)) versionMessage.userAgent must be( - "NcQHwZ87bRe9y4m6PA7lX2iVA5If1jWjUycykFOQeqB0REj92awaKy0zMRdckvEKq1j97i3Mal3Eo7QxgdjcpV") + "NcQHwZ87bRe9y4m6PA7lX2iVA5If1jWjUycykFOQeqB0REj92awaKy0zMRdckvEKq1j97i3Mal3Eo7QxgdjcpV" + ) versionMessage.startHeight must be(Int32(-919905282)) versionMessage.relay must be(false) versionMessage.hex must be(hex) diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/script/RawScriptPubKeyParserTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/script/RawScriptPubKeyParserTest.scala index c24ddab790..935cc61a99 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/script/RawScriptPubKeyParserTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/script/RawScriptPubKeyParserTest.scala @@ -18,7 +18,8 @@ class RawScriptPubKeyParserTest extends BitcoinSUnitTest { val scriptPubKey: ScriptPubKey = RawScriptPubKeyParser.read(TestUtil.rawScriptPubKey) encode(RawScriptPubKeyParser.write(scriptPubKey)) must be( - TestUtil.rawScriptPubKey) + TestUtil.rawScriptPubKey + ) } it must "read an EmptyScriptPubKey" in { @@ -28,18 +29,20 @@ class RawScriptPubKeyParserTest extends BitcoinSUnitTest { it must "read a raw scriptPubKey and give us the expected asm" in { val scriptPubKey = RawScriptPubKeyParser.read(TestUtil.rawP2PKHScriptPubKey) val expectedAsm: Seq[ScriptToken] = - List(OP_DUP, - OP_HASH160, - BytesToPushOntoStack(20), - ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), - OP_EQUALVERIFY, - OP_CHECKSIG) + List( + OP_DUP, + OP_HASH160, + BytesToPushOntoStack(20), + ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"), + OP_EQUALVERIFY, + OP_CHECKSIG + ) scriptPubKey.asm must be(expectedAsm) } it must "read a raw scriptPubKey from an output" in { - //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc - //output is index 1 + // from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + // output is index 1 val rawScriptPubKey = "17a914af575bd77c5ce7eba3bd9ce6f89774713ae62c7987" val scriptPubKey = RawScriptPubKeyParser.read(rawScriptPubKey) encode(RawScriptPubKeyParser.write(scriptPubKey)) must be(rawScriptPubKey) @@ -51,9 +54,10 @@ class RawScriptPubKeyParserTest extends BitcoinSUnitTest { val asm = ScriptParser.fromString(rawScriptPubKey) val scriptPubKey = ScriptPubKey.fromAsm(asm) val actualRawScriptPubKey = RawScriptPubKeyParser.write(scriptPubKey) - //the actual hex representation is from a bitcoin core test case inside of tx_valid.json + // the actual hex representation is from a bitcoin core test case inside of tx_valid.json encode(actualRawScriptPubKey) must be( - "ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288ac") + "ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288ac" + ) } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/script/RawScriptSignatureParserTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/script/RawScriptSignatureParserTest.scala index af7f4e88ae..0107f0ca34 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/script/RawScriptSignatureParserTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/script/RawScriptSignatureParserTest.scala @@ -11,8 +11,8 @@ import scodec.bits.ByteVector */ class RawScriptSignatureParserTest extends BitcoinSUnitTest { - //from bitcoin developer examples - //https://bitcoin.org/en/developer-reference#raw-transaction-format + // from bitcoin developer examples + // https://bitcoin.org/en/developer-reference#raw-transaction-format val rawScriptSig = "4a494830450221008949f0cb400094ad2b5eb399d59d01c14d73d8fe6e96df1a7150deb388ab8935022079656090d7f6bac4c9a94e0aad311a4268e082a725f8aeae0573fb12ff866a5f01" val encode = BytesUtil.encodeHex(_: ByteVector) @@ -23,12 +23,13 @@ class RawScriptSignatureParserTest extends BitcoinSUnitTest { it must "read an EmptyScriptSignature" in { assert( - RawScriptSignatureParser.read(ByteVector.empty) == EmptyScriptSignature) + RawScriptSignatureParser.read(ByteVector.empty) == EmptyScriptSignature + ) } it must "read then write a raw script sig" in { - //from this tx - //https://tbtc.blockr.io/api/v1/tx/raw/bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 + // from this tx + // https://tbtc.blockr.io/api/v1/tx/raw/bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 val rawScriptSig = TestUtil.rawScriptSig val scriptSig = RawScriptSignatureParser.read(rawScriptSig) encode(RawScriptSignatureParser.write(scriptSig)) must be(rawScriptSig) @@ -42,11 +43,14 @@ class RawScriptSignatureParserTest extends BitcoinSUnitTest { Seq( BytesToPushOntoStack(72), ScriptConstant( - "3045022100ad8e961fe3c22b2647d92b078f4c0cf81b3106ea5bf8b900ab8646aa4430216f022071d4edc2b5588be20ac4c2d07edd8ed069e10b2402d3dce2d3b835ccd075f28301"), + "3045022100ad8e961fe3c22b2647d92b078f4c0cf81b3106ea5bf8b900ab8646aa4430216f022071d4edc2b5588be20ac4c2d07edd8ed069e10b2402d3dce2d3b835ccd075f28301" + ), BytesToPushOntoStack(65), ScriptConstant( - "04fa79182bbc26c708b5d9f36b8635947d4a834ea356cf612ede08395c295f962e0b1dc2557aba34188640e51a58ed547f2c89c8265cd0c04ff890d8435648746e") - )) + "04fa79182bbc26c708b5d9f36b8635947d4a834ea356cf612ede08395c295f962e0b1dc2557aba34188640e51a58ed547f2c89c8265cd0c04ff890d8435648746e" + ) + ) + ) } @@ -56,24 +60,31 @@ class RawScriptSignatureParserTest extends BitcoinSUnitTest { OP_0, BytesToPushOntoStack(72), ScriptConstant( - "3045022100a077d4fe9a81411ecb796c254d8b4e0bc73ff86a42288bc3b3ecfa1ef26c00dd02202389bf96cf38c14c3a6ccb8c688339f3fd880b724322862547a8ee3b547a9df901"), + "3045022100a077d4fe9a81411ecb796c254d8b4e0bc73ff86a42288bc3b3ecfa1ef26c00dd02202389bf96cf38c14c3a6ccb8c688339f3fd880b724322862547a8ee3b547a9df901" + ), BytesToPushOntoStack(71), ScriptConstant( - "304402207c0692464998e7f3869f8501cdd25bbcd9d32b6fd34ae8aeae643b422a8dfd42022057eb16f8ca1f34e88babc9f8beb4c2521eb5c4dea41f8902a70d045f1c132a4401"), + "304402207c0692464998e7f3869f8501cdd25bbcd9d32b6fd34ae8aeae643b422a8dfd42022057eb16f8ca1f34e88babc9f8beb4c2521eb5c4dea41f8902a70d045f1c132a4401" + ), BytesToPushOntoStack(71), ScriptConstant( - "3044022024233923253c73569f4b34723a5495698bc124b099c5542a5997d13fba7d18a802203c317bddc070276c6f6c79cb3415413e608af30e4759e31b0d53eab3ca0acd4e01"), + "3044022024233923253c73569f4b34723a5495698bc124b099c5542a5997d13fba7d18a802203c317bddc070276c6f6c79cb3415413e608af30e4759e31b0d53eab3ca0acd4e01" + ), BytesToPushOntoStack(72), ScriptConstant( - "30450221009b9f0d8b945717d2fca3685093d547a3928d122b8894903ed51e2248303213bc022008b376422c9f2cd713b9d10b5b106d1c56c5893dcc01ae300253ed2234bdb63f01"), + "30450221009b9f0d8b945717d2fca3685093d547a3928d122b8894903ed51e2248303213bc022008b376422c9f2cd713b9d10b5b106d1c56c5893dcc01ae300253ed2234bdb63f01" + ), BytesToPushOntoStack(71), ScriptConstant( - "30440220257b57cb09386d82c4328461f8fe200c2f381d6b635e2a2f4ea40c8d945e9ec102201ec67d58d51a309af4d8896e9147a42944e9f9833a456f733ea5fa6954ed2fed01"), + "30440220257b57cb09386d82c4328461f8fe200c2f381d6b635e2a2f4ea40c8d945e9ec102201ec67d58d51a309af4d8896e9147a42944e9f9833a456f733ea5fa6954ed2fed01" + ), OP_PUSHDATA1, ScriptConstant("f1"), ScriptConstant( - "55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae") - )) + "55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae" + ) + ) + ) } @@ -85,7 +96,7 @@ class RawScriptSignatureParserTest extends BitcoinSUnitTest { } it must "parse hex to a p2pkh scriptSig and then write that p2pkh scriptSig to hex" in { - //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + // from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val rawScriptSig = "6a4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff35722305012103dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b" @@ -95,10 +106,12 @@ class RawScriptSignatureParserTest extends BitcoinSUnitTest { BytesToPushOntoStack(71), ScriptConstant( "30440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf" + - "225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff3572230501"), + "225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff3572230501" + ), BytesToPushOntoStack(33), ScriptConstant( - "03dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b") + "03dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b" + ) ) scriptSig.asm.head must be(expectedAsm.head) diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/script/ScriptParserTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/script/ScriptParserTest.scala index e7fc78faff..30f328081f 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/script/ScriptParserTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/script/ScriptParserTest.scala @@ -32,18 +32,21 @@ class ScriptParserTest extends BitcoinSUnitTest { it must "parse a number larger than an integer into a ScriptNumberImpl" in { ScriptParser.fromString("2147483648") must be( - List(BytesToPushOntoStack(5), ScriptNumber(2147483648L))) + List(BytesToPushOntoStack(5), ScriptNumber(2147483648L)) + ) } it must "parse a decimal number and correctly add its corresponding BytesToPushOntoStack" in { ScriptParser.fromString("127") must be( - List(BytesToPushOntoStack(1), ScriptNumber(127))) + List(BytesToPushOntoStack(1), ScriptNumber(127)) + ) } it must "parse a decimal number that is pushed onto the stack" in { val str = "NOP 0x01 1" ScriptParser.fromString(str) must be( - List(OP_NOP, BytesToPushOntoStack(1), ScriptConstant("51"))) + List(OP_NOP, BytesToPushOntoStack(1), ScriptConstant("51")) + ) } it must "parse a pay-to-pubkey-hash output script" in { @@ -82,13 +85,15 @@ class ScriptParserTest extends BitcoinSUnitTest { it must "parse a script constant from 'Az' EQUAL" in { val str = "'Az' EQUAL" ScriptParser.fromString(str) must equal( - List(BytesToPushOntoStack(2), ScriptConstant("417a"), OP_EQUAL)) + List(BytesToPushOntoStack(2), ScriptConstant("417a"), OP_EQUAL) + ) } it must "parse a script number that has a leading zero" in { val str = "0x02 0x0100" ScriptParser.fromString(str) must equal( - List(BytesToPushOntoStack(2), ScriptConstant("0100"))) + List(BytesToPushOntoStack(2), ScriptConstant("0100")) + ) } it must "parse an OP_PICK" in { @@ -104,11 +109,14 @@ class ScriptParserTest extends BitcoinSUnitTest { it must "parse a script that has a decimal and a hexadecimal number in it " in { val str = "32767 0x02 0xff7f EQUAL" ScriptParser.fromString(str) must equal( - List(BytesToPushOntoStack(2), - ScriptConstant("ff7f"), - BytesToPushOntoStack(2), - ScriptConstant("ff7f"), - OP_EQUAL)) + List( + BytesToPushOntoStack(2), + ScriptConstant("ff7f"), + BytesToPushOntoStack(2), + ScriptConstant("ff7f"), + OP_EQUAL + ) + ) } it must "parse an OP_1" in { val str = "0x51" @@ -124,23 +132,29 @@ class ScriptParserTest extends BitcoinSUnitTest { List( BytesToPushOntoStack(75), ScriptConstant( - "417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a"), + "417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a" + ), BytesToPushOntoStack(75), ScriptConstant( - "417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a"), + "417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a" + ), OP_EQUAL - )) + ) + ) } it must "parse an OP_IF OP_ENDIF block" in { val str = "1 0x01 0x80 IF 0 ENDIF" ScriptParser.fromString(str) must be( - List(OP_1, - BytesToPushOntoStack(1), - ScriptConstant("80"), - OP_IF, - OP_0, - OP_ENDIF)) + List( + OP_1, + BytesToPushOntoStack(1), + ScriptConstant("80"), + OP_IF, + OP_0, + OP_ENDIF + ) + ) } it must "parse an OP_PUSHDATA1 correctly" in { @@ -159,7 +173,7 @@ class ScriptParserTest extends BitcoinSUnitTest { } it must "parse a OP_PUSHDATA1 correct from a scriptSig" in { - //https://tbtc.blockr.io/api/v1/tx/raw/5d254a872c9197c683ea9111fb5c0e2e0f49280a89961c45b9fea76834d335fe + // https://tbtc.blockr.io/api/v1/tx/raw/5d254a872c9197c683ea9111fb5c0e2e0f49280a89961c45b9fea76834d335fe val str = "4cf1" + "55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae" ScriptParser.fromString(str) must be( @@ -167,8 +181,10 @@ class ScriptParserTest extends BitcoinSUnitTest { OP_PUSHDATA1, ScriptConstant("f1"), ScriptConstant( - "55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae") - )) + "55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae" + ) + ) + ) } it must "parse bytes from a string" in { @@ -190,7 +206,8 @@ class ScriptParserTest extends BitcoinSUnitTest { "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" + - "1111111"), + "1111111" + ), OP_PUSHDATA1, ScriptConstant("ff"), ScriptConstant( @@ -199,7 +216,8 @@ class ScriptParserTest extends BitcoinSUnitTest { "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" + - "1111111"), + "1111111" + ), OP_EQUAL ) @@ -207,8 +225,8 @@ class ScriptParserTest extends BitcoinSUnitTest { } it must "parse a hex string to a list of script tokens, and then back again" in { - //from this question - //https://bitcoin.stackexchange.com/questions/37125/how-are-sighash-flags-encoded-into-a-signature + // from this question + // https://bitcoin.stackexchange.com/questions/37125/how-are-sighash-flags-encoded-into-a-signature val hex = "304402206e3729f021476102a06ea453cea0a26cb9c096cca641efc4229c1111ed3a96fd022037dce1456a93f53d3e868c789b1b750a48a4c1110cd5b7049779b5f4f3c8b6200103ff1104b46b2141df1948dd0df2223720a3a471ec57404cace47063843a699a0f" @@ -217,7 +235,7 @@ class ScriptParserTest extends BitcoinSUnitTest { } it must "parse a p2pkh scriptSig properly" in { - //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + // from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val rawScriptSig = "4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff35722305012103dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b" @@ -225,10 +243,12 @@ class ScriptParserTest extends BitcoinSUnitTest { BytesToPushOntoStack(71), ScriptConstant( "30440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf" + - "225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff3572230501"), + "225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff3572230501" + ), BytesToPushOntoStack(33), ScriptConstant( - "03dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b") + "03dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b" + ) ) val scriptTokens: Vector[ScriptToken] = ScriptParser.fromHex(rawScriptSig) @@ -246,15 +266,18 @@ class ScriptParserTest extends BitcoinSUnitTest { it must "parse a OP_PUSHDATA operation that pushes zero bytes correctly" in { val str = "0x4c 0x00" ScriptParser.fromString(str) must be( - List(OP_PUSHDATA1, ScriptConstant("00"))) + List(OP_PUSHDATA1, ScriptConstant("00")) + ) val str1 = "0x4d 0x00" ScriptParser.fromString(str1) must be( - List(OP_PUSHDATA2, ScriptConstant("00"))) + List(OP_PUSHDATA2, ScriptConstant("00")) + ) val str2 = "0x4e 0x00" ScriptParser.fromString(str2) must be( - List(OP_PUSHDATA4, ScriptConstant("00"))) + List(OP_PUSHDATA4, ScriptConstant("00")) + ) } it must "parse a large string constant found inside of script_valid.json" in { @@ -266,45 +289,43 @@ class ScriptParserTest extends BitcoinSUnitTest { OP_PUSHDATA2, ScriptConstant("0802"), ScriptConstant( - "62626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262") - )) + "62626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262" + ) + ) + ) } it must "parse a offered htlc" in { - //https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#offered-htlc-outputs + // https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#offered-htlc-outputs val witScriptHex = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c820120876475527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae67a914b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d188ac6868" val asm = ScriptParser.fromHex(witScriptHex) - /** # To remote node with revocation key - * OP_DUP OP_HASH160 OP_EQUAL - * OP_IF - * OP_CHECKSIG - * OP_ELSE - * OP_SWAP OP_SIZE 32 OP_EQUAL - * OP_NOTIF - * # To local node via HTLC-timeout transaction (timelocked). - * OP_DROP 2 OP_SWAP 2 OP_CHECKMULTISIG - * OP_ELSE - * # To remote node with preimage. - * OP_HASH160 OP_EQUALVERIFY - * OP_CHECKSIG - * OP_ENDIF - * OP_ENDIF + /** # To remote node with revocation key OP_DUP OP_HASH160 + * OP_EQUAL OP_IF OP_CHECKSIG OP_ELSE + * OP_SWAP OP_SIZE 32 OP_EQUAL OP_NOTIF # To local node + * via HTLC-timeout transaction (timelocked). OP_DROP 2 OP_SWAP + * 2 OP_CHECKMULTISIG OP_ELSE # To remote node with + * preimage. OP_HASH160 OP_EQUALVERIFY + * OP_CHECKSIG OP_ENDIF OP_ENDIF */ val expectedAsm = List( OP_DUP, OP_HASH160, BytesToPushOntoStack(20), ScriptConstant( - ByteVector.fromValidHex("14011f7254d96b819c76986c277d115efce6f7b5")), + ByteVector.fromValidHex("14011f7254d96b819c76986c277d115efce6f7b5") + ), OP_EQUAL, OP_IF, OP_CHECKSIG, OP_ELSE, BytesToPushOntoStack(33), - ScriptConstant(ByteVector.fromValidHex( - "0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b")), + ScriptConstant( + ByteVector.fromValidHex( + "0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b" + ) + ), OP_SWAP, OP_SIZE, BytesToPushOntoStack(1), @@ -315,15 +336,19 @@ class ScriptParserTest extends BitcoinSUnitTest { OP_2, OP_SWAP, BytesToPushOntoStack(33), - ScriptConstant(ByteVector.fromValidHex( - "030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7")), + ScriptConstant( + ByteVector.fromValidHex( + "030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7" + ) + ), OP_2, OP_CHECKMULTISIG, OP_ELSE, OP_HASH160, BytesToPushOntoStack(20), ScriptConstant( - ByteVector.fromValidHex("b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d1")), + ByteVector.fromValidHex("b43e1b38138a41b37f7cd9a1d274bc63e3a9b5d1") + ), OP_EQUALVERIFY, OP_CHECKSIG, OP_ENDIF, @@ -335,23 +360,14 @@ class ScriptParserTest extends BitcoinSUnitTest { } it must "parse a received htlc" in { - //https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#received-htlc-outputs - /** # To remote node with revocation key - * OP_DUP OP_HASH160 OP_EQUAL - * OP_IF - * OP_CHECKSIG - * OP_ELSE - * OP_SWAP OP_SIZE 32 OP_EQUAL - * OP_IF - * # To local node via HTLC-success transaction. - * OP_HASH160 OP_EQUALVERIFY - * 2 OP_SWAP 2 OP_CHECKMULTISIG - * OP_ELSE - * # To remote node after timeout. - * OP_DROP OP_CHECKLOCKTIMEVERIFY OP_DROP - * OP_CHECKSIG - * OP_ENDIF - * OP_ENDIF + // https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#received-htlc-outputs + /** # To remote node with revocation key OP_DUP OP_HASH160 + * OP_EQUAL OP_IF OP_CHECKSIG OP_ELSE + * OP_SWAP OP_SIZE 32 OP_EQUAL OP_IF # To local node + * via HTLC-success transaction. OP_HASH160 + * OP_EQUALVERIFY 2 OP_SWAP 2 OP_CHECKMULTISIG OP_ELSE # + * To remote node after timeout. OP_DROP + * OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIG OP_ENDIF OP_ENDIF */ val witScriptHex = "76a91414011f7254d96b819c76986c277d115efce6f7b58763ac67210394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b7c8201208763a914b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc688527c21030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e752ae677502f401b175ac6868" @@ -364,14 +380,18 @@ class ScriptParserTest extends BitcoinSUnitTest { OP_HASH160, BytesToPushOntoStack(20), ScriptConstant( - ByteVector.fromValidHex("14011f7254d96b819c76986c277d115efce6f7b5")), + ByteVector.fromValidHex("14011f7254d96b819c76986c277d115efce6f7b5") + ), OP_EQUAL, OP_IF, OP_CHECKSIG, OP_ELSE, BytesToPushOntoStack(33), - ScriptConstant(ByteVector.fromValidHex( - "0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b")), + ScriptConstant( + ByteVector.fromValidHex( + "0394854aa6eab5b2a8122cc726e9dded053a2184d88256816826d6231c068d4a5b" + ) + ), OP_SWAP, OP_SIZE, BytesToPushOntoStack(1), @@ -381,13 +401,17 @@ class ScriptParserTest extends BitcoinSUnitTest { OP_HASH160, BytesToPushOntoStack(20), ScriptConstant( - ByteVector.fromValidHex("b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6")), + ByteVector.fromValidHex("b8bcb07f6344b42ab04250c86a6e8b75d3fdbbc6") + ), OP_EQUALVERIFY, OP_2, OP_SWAP, BytesToPushOntoStack(33), - ScriptConstant(ByteVector.fromValidHex( - "030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7")), + ScriptConstant( + ByteVector.fromValidHex( + "030d417a46946384f88d5f3337267c5e579765875dc4daca813e21734b140639e7" + ) + ), OP_2, OP_CHECKMULTISIG, OP_ELSE, diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawBaseTransactionParserTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawBaseTransactionParserTest.scala index 43cfb87205..5f99d0e493 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawBaseTransactionParserTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawBaseTransactionParserTest.scala @@ -23,22 +23,26 @@ class RawBaseTransactionParserTest extends BitcoinSUnitTest { tx.lockTime must be(UInt32.zero) tx.txId.hex must be( BytesUtil.flipEndianness( - "44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff")) + "44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff" + ) + ) } it must "parse a transaction correctly with a locktime" in { - //txid bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 + // txid bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 val rawTx = "0100000002fc37adbd036fb51b3f4f6f70474270939d6ff8c4ea697639f2b57dd6359e3070010000008b483045022100ad8e961fe3c22b2647d92b078f4c0cf81b3106ea5bf8b900ab8646aa4430216f022071d4edc2b5588be20ac4c2d07edd8ed069e10b2402d3dce2d3b835ccd075f283014104fa79182bbc26c708b5d9f36b8635947d4a834ea356cf612ede08395c295f962e0b1dc2557aba34188640e51a58ed547f2c89c8265cd0c04ff890d8435648746e0000000036219231b3043efdfb9405bbc2610baa73e340dddfe9c2a07b09bd3785ca6330000000008b483045022100cb097f8720d0c4665e8771fff5181b30584fd9e7d437fae21b440c94fe76d56902206f9b539ae26ec9688c54272d6a3309d93f17fb9835f382fff1ebeead84af2763014104fa79182bbc26c708b5d9f36b8635947d4a834ea356cf612ede08395c295f962e0b1dc2557aba34188640e51a58ed547f2c89c8265cd0c04ff890d8435648746effffffff02905f0100000000001976a914a45bc47d00c3d2b0d0ea37cbf74b94cd1986ea7988aca0860100000000001976a914a45bc47d00c3d2b0d0ea37cbf74b94cd1986ea7988ac77d3a655" val tx: Transaction = BaseTransaction(rawTx) tx.txId.hex must be( BytesUtil.flipEndianness( - "bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74")) + "bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74" + ) + ) tx.lockTime must be(UInt32(1436996471)) } it must "write a transaction with a locktime" in { - //txid bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 + // txid bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 val rawTxWithLockTime = "0100000002fc37adbd036fb51b3f4f6f70474270939d6ff8c4ea697639f2b57dd6359e3070010000008b483045022100ad8e961fe3c22b2647d92b078f4c0cf81b3106ea5bf8b900ab8646aa4430216f022071d4edc2b5588be20ac4c2d07edd8ed069e10b2402d3dce2d3b835ccd075f283014104fa79182bbc26c708b5d9f36b8635947d4a834ea356cf612ede08395c295f962e0b1dc2557aba34188640e51a58ed547f2c89c8265cd0c04ff890d8435648746e0000000036219231b3043efdfb9405bbc2610baa73e340dddfe9c2a07b09bd3785ca6330000000008b483045022100cb097f8720d0c4665e8771fff5181b30584fd9e7d437fae21b440c94fe76d56902206f9b539ae26ec9688c54272d6a3309d93f17fb9835f382fff1ebeead84af2763014104fa79182bbc26c708b5d9f36b8635947d4a834ea356cf612ede08395c295f962e0b1dc2557aba34188640e51a58ed547f2c89c8265cd0c04ff890d8435648746effffffff02905f0100000000001976a914a45bc47d00c3d2b0d0ea37cbf74b94cd1986ea7988aca0860100000000001976a914a45bc47d00c3d2b0d0ea37cbf74b94cd1986ea7988ac77d3a655" val tx = BaseTransaction(rawTxWithLockTime) @@ -47,7 +51,7 @@ class RawBaseTransactionParserTest extends BitcoinSUnitTest { } it must "read and write a raw tx" in { - //https://btc.blockr.io/api/v1/tx/raw/cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a + // https://btc.blockr.io/api/v1/tx/raw/cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a val rawTx = "01000000020df1e23002ddf909aec026b1cf0c3b6b7943c042f22e25dbd0441855e6b39ee900000000fdfd00004730440220028c02f14654a0cc12c7e3229adb09d5d35bebb6ba1057e39adb1b2706607b0d0220564fab12c6da3d5acef332406027a7ff1cbba980175ffd880e1ba1bf40598f6b014830450221009362f8d67b60773745e983d07ba10efbe566127e244b724385b2ca2e47292dda022033def393954c320653843555ddbe7679b35cc1cacfe1dad923977de8cd6cc6d7014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53aeffffffffd11533b0f283fca193e361a91ca7ddfc66592e20fd6eaf5dc0f1ef5fed05818000000000fdfe0000483045022100b4062edd75b5b3117f28ba937ed737b10378f762d7d374afabf667180dedcc62022005d44c793a9d787197e12d5049da5e77a09046014219b31e9c6b89948f648f1701483045022100b3b0c0273fc2c531083701f723e03ea3d9111e4bbca33bdf5b175cec82dcab0802206650462db37f9b4fe78da250a3b339ab11e11d84ace8f1b7394a1f6db0960ba4014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53aeffffffff02500f1e00000000001976a9147ecaa33ef3cd6169517e43188ad3c034db091f5e88ac204e0000000000001976a914321908115d8a138942f98b0b53f86c9a1848501a88ac00000000" @@ -67,11 +71,14 @@ class RawBaseTransactionParserTest extends BitcoinSUnitTest { val tx = BaseTransaction(TestUtil.parentSimpleRawTransaction) tx.inputs.size must be(1) tx.inputs.head.scriptSignature.hex must be( - "6a4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff35722305012103dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b") + "6a4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff35722305012103dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b" + ) tx.inputs.head.previousOutput.vout must be(UInt32.one) tx.inputs.head.previousOutput.txId.hex must be( BytesUtil.flipEndianness( - "65bd23d3fb0ac9d3ee0195aae8d033d6689dacf71907902b27a7ad6f6441a7cd")) + "65bd23d3fb0ac9d3ee0195aae8d033d6689dacf71907902b27a7ad6f6441a7cd" + ) + ) tx.inputs.head.sequence must be(TransactionConstants.sequence) tx.outputs.size must be(2) } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParserTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParserTest.scala index 667372c145..b571a387cd 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParserTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParserTest.scala @@ -13,7 +13,7 @@ import scodec.bits.ByteVector */ class RawTransactionInputParserTest extends BitcoinSJvmTest { - //txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 + // txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 val rawTxInput = "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" + "6f0047304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f00125512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" + "ffffffff" val encode = BytesUtil.encodeHex(_: ByteVector) @@ -22,7 +22,9 @@ class RawTransactionInputParserTest extends BitcoinSJvmTest { txInput.previousOutput.vout must be(UInt32.zero) txInput.previousOutput.txId.hex must be( BytesUtil.flipEndianness( - "e17d316006850c1764301befcf82c8c84cd1794f3f0d0382b296df2edab0d685")) + "e17d316006850c1764301befcf82c8c84cd1794f3f0d0382b296df2edab0d685" + ) + ) txInput.scriptSignature.hex must be(TestUtil.rawP2shInputScript) txInput.scriptSignature.asm must be(TestUtil.p2shInputScript.asm) txInput.sequence must be(UInt32(4294967295L)) @@ -43,18 +45,19 @@ class RawTransactionInputParserTest extends BitcoinSJvmTest { it must "write a single input not in a sequence" in { val txInput = RawTransactionInputParser.read(rawTxInput) val serializedInput = RawTransactionInputParser.write(txInput) - //txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 - //note that the expected hex does NOT have the number of inputs + // txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 + // note that the expected hex does NOT have the number of inputs encode(serializedInput) must be( "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" + "6f0047304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e8" + "7d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f00125512102b022902a0fdd71e831c37e4136c2754a59" + - "887be0618fb75336d7ab67e2982ff551aeffffffff") + "887be0618fb75336d7ab67e2982ff551aeffffffff" + ) } it must "parse a single input that uses a VarInt push operation" in { - //from this tx - //https://btc.blockr.io/api/v1/tx/raw/cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a + // from this tx + // https://btc.blockr.io/api/v1/tx/raw/cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a val rawTxInput = "0df1e23002ddf909aec026b1cf0c3b6b7943c042f22e25dbd0441855e6b39ee900000000fdfd00004730440220028c02f14654a0cc12c7e3229adb09d5d35bebb6ba1057e39adb1b2706607b0d0220564fab12c6da3d5acef332406027a7ff1cbba980175ffd880e1ba1bf40598f6b014830450221009362f8d67b60773745e983d07ba10efbe566127e244b724385b2ca2e47292dda022033def393954c320653843555ddbe7679b35cc1cacfe1dad923977de8cd6cc6d7014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53aeffffffff" @@ -62,28 +65,34 @@ class RawTransactionInputParserTest extends BitcoinSJvmTest { txInput.previousOutput.txId.hex must be( BytesUtil.flipEndianness( - "e99eb3e6551844d0db252ef242c043796b3b0ccfb126c0ae09f9dd0230e2f10d")) + "e99eb3e6551844d0db252ef242c043796b3b0ccfb126c0ae09f9dd0230e2f10d" + ) + ) txInput.previousOutput.vout must be(UInt32.zero) txInput.scriptSignature.hex must be( - "fdfd00004730440220028c02f14654a0cc12c7e3229adb09d5d35bebb6ba1057e39adb1b2706607b0d0220564fab12c6da3d5acef332406027a7ff1cbba980175ffd880e1ba1bf40598f6b014830450221009362f8d67b60773745e983d07ba10efbe566127e244b724385b2ca2e47292dda022033def393954c320653843555ddbe7679b35cc1cacfe1dad923977de8cd6cc6d7014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53ae") + "fdfd00004730440220028c02f14654a0cc12c7e3229adb09d5d35bebb6ba1057e39adb1b2706607b0d0220564fab12c6da3d5acef332406027a7ff1cbba980175ffd880e1ba1bf40598f6b014830450221009362f8d67b60773745e983d07ba10efbe566127e244b724385b2ca2e47292dda022033def393954c320653843555ddbe7679b35cc1cacfe1dad923977de8cd6cc6d7014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53ae" + ) txInput.sequence must be(UInt32(4294967295L)) encode(RawTransactionInputParser.write(txInput)) must be(rawTxInput) - //parse the second input on the tx cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a + // parse the second input on the tx cddda897b0e9322937ee1f4fd5d6147d60f04a0f4d3b461e4f87066ac3918f2a val rawTxInput2 = "d11533b0f283fca193e361a91ca7ddfc66592e20fd6eaf5dc0f1ef5fed05818000000000fdfe0000483045022100b4062edd75b5b3117f28ba937ed737b10378f762d7d374afabf667180dedcc62022005d44c793a9d787197e12d5049da5e77a09046014219b31e9c6b89948f648f1701483045022100b3b0c0273fc2c531083701f723e03ea3d9111e4bbca33bdf5b175cec82dcab0802206650462db37f9b4fe78da250a3b339ab11e11d84ace8f1b7394a1f6db0960ba4014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53aeffffffff" val txInput2 = RawTransactionInputParser.read(rawTxInput2) txInput2.previousOutput.txId.hex must be( BytesUtil.flipEndianness( - "808105ed5feff1c05daf6efd202e5966fcdda71ca961e393a1fc83f2b03315d1")) + "808105ed5feff1c05daf6efd202e5966fcdda71ca961e393a1fc83f2b03315d1" + ) + ) txInput2.previousOutput.vout must be(UInt32.zero) txInput2.scriptSignature.hex must be( - "fdfe0000483045022100b4062edd75b5b3117f28ba937ed737b10378f762d7d374afabf667180dedcc62022005d44c793a9d787197e12d5049da5e77a09046014219b31e9c6b89948f648f1701483045022100b3b0c0273fc2c531083701f723e03ea3d9111e4bbca33bdf5b175cec82dcab0802206650462db37f9b4fe78da250a3b339ab11e11d84ace8f1b7394a1f6db0960ba4014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53ae") + "fdfe0000483045022100b4062edd75b5b3117f28ba937ed737b10378f762d7d374afabf667180dedcc62022005d44c793a9d787197e12d5049da5e77a09046014219b31e9c6b89948f648f1701483045022100b3b0c0273fc2c531083701f723e03ea3d9111e4bbca33bdf5b175cec82dcab0802206650462db37f9b4fe78da250a3b339ab11e11d84ace8f1b7394a1f6db0960ba4014c695221025e9adcc3d65c11346c8a6069d6ebf5b51b348d1d6dc4b95e67480c34dc0bc75c21030585b3c80f4964bf0820086feda57c8e49fa1eab925db7c04c985467973df96521037753a5e3e9c4717d3f81706b38a6fb82b5fb89d29e580d7b98a37fea8cdefcad53ae" + ) } it must "parse this transaction input and its script signature" in { - //txid b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + // txid b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val rawTxInput = "cda741646fada7272b900719f7ac9d68d633d0e8aa9501eed3c90afbd323bd65" + "010000006a4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d" + @@ -93,11 +102,14 @@ class RawTransactionInputParserTest extends BitcoinSJvmTest { val input = RawTransactionInputParser.read(rawTxInput) input.scriptSignature.hex must be( - "6a4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff35722305012103dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b") + "6a4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d158c29309939d5a3cd41a889db6f766f3809fff35722305012103dcfc9882c1b3ae4e03fb6cac08bdb39e284e81d70c7aa8b27612457b2774509b" + ) input.previousOutput.vout must be(UInt32.one) input.previousOutput.txId.hex must be( BytesUtil.flipEndianness( - "65bd23d3fb0ac9d3ee0195aae8d033d6689dacf71907902b27a7ad6f6441a7cd")) + "65bd23d3fb0ac9d3ee0195aae8d033d6689dacf71907902b27a7ad6f6441a7cd" + ) + ) input.sequence must be(TransactionConstants.sequence) } diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutPointParserTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutPointParserTest.scala index 2f102a1ead..e72fafd665 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutPointParserTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutPointParserTest.scala @@ -9,7 +9,7 @@ import scodec.bits.ByteVector */ class RawTransactionOutPointParserTest extends BitcoinSUnitTest { - //txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 + // txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 val rawOutPoint = "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" @@ -20,7 +20,9 @@ class RawTransactionOutPointParserTest extends BitcoinSUnitTest { val outPoint = RawTransactionOutPointParser.read(rawOutPoint) outPoint.txId.hex must be( BytesUtil.flipEndianness( - "e17d316006850c1764301befcf82c8c84cd1794f3f0d0382b296df2edab0d685")) + "e17d316006850c1764301befcf82c8c84cd1794f3f0d0382b296df2edab0d685" + ) + ) outPoint.vout must be(UInt32.zero) } @@ -29,7 +31,9 @@ class RawTransactionOutPointParserTest extends BitcoinSUnitTest { outPoint.vout must be(UInt32(52)) outPoint.txId.hex must be( BytesUtil.flipEndianness( - "0140d0ed6c9feeb68ea727723a82bbaf0d143fc1d3810265d4dca7ebe6e380df")) + "0140d0ed6c9feeb68ea727723a82bbaf0d143fc1d3810265d4dca7ebe6e380df" + ) + ) } it must "write a TransactionOutPoint to a serialized format" in { val outPoint = RawTransactionOutPointParser.read(rawOutPoint) @@ -44,20 +48,22 @@ class RawTransactionOutPointParserTest extends BitcoinSUnitTest { } it must "write this outpoint with vout index 1" in { - //from txid bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 + // from txid bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 val rawOutPoint = "fc37adbd036fb51b3f4f6f70474270939d6ff8c4ea697639f2b57dd6359e307001000000" val outPoint = RawTransactionOutPointParser.read(rawOutPoint) outPoint.txId.hex must be( BytesUtil.flipEndianness( - "70309e35d67db5f2397669eac4f86f9d93704247706f4f3f1bb56f03bdad37fc")) + "70309e35d67db5f2397669eac4f86f9d93704247706f4f3f1bb56f03bdad37fc" + ) + ) val serializedOutPoint = RawTransactionOutPointParser.write(outPoint) encode(serializedOutPoint) must be(rawOutPoint) } it must "determine the correct size of a transaction outpoint" in { - //cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 + // cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 val rawOutPoint = "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" val outPoint = RawTransactionOutPointParser.read(rawOutPoint) @@ -65,7 +71,7 @@ class RawTransactionOutPointParserTest extends BitcoinSUnitTest { } it must "parse a outpoint with extremely large vout" in { - //vout should be 20183580 + // vout should be 20183580 val rawOutPoint = "4435c4ea162d51135c9b2bbb867a86f25001c246224b60e8ab2307edce7fc28a0ca13f13" val outPoint = RawTransactionOutPointParser.read(rawOutPoint) diff --git a/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutputParserTest.scala b/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutputParserTest.scala index 6ba688696f..fc1f7ab2ff 100644 --- a/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutputParserTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutputParserTest.scala @@ -17,7 +17,7 @@ import scodec.bits.ByteVector */ class RawTransactionOutputParserTest extends BitcoinSUnitTest { - //txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 + // txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 val rawTxOutput = "204e00000000000017a914eda8ae08b5c9f973f49543e90a7c292367b3337c87" val encode = BytesUtil.encodeHex(_: ByteVector) @@ -27,10 +27,13 @@ class RawTransactionOutputParserTest extends BitcoinSUnitTest { RawTransactionOutputParser.read(rawTxOutput) txOutput.value must be(Satoshis(20000)) txOutput.scriptPubKey.asm must be( - Seq(OP_HASH160, - BytesToPushOntoStack(20), - ScriptConstant("eda8ae08b5c9f973f49543e90a7c292367b3337c"), - OP_EQUAL)) + Seq( + OP_HASH160, + BytesToPushOntoStack(20), + ScriptConstant("eda8ae08b5c9f973f49543e90a7c292367b3337c"), + OP_EQUAL + ) + ) } it must "seralialize a transaction output" in { @@ -44,8 +47,8 @@ class RawTransactionOutputParserTest extends BitcoinSUnitTest { } it must "serialize an older raw transaction output" in { - //from this question - //https://bitcoin.stackexchange.com/questions/2859/how-are-transaction-hashes-calculated + // from this question + // https://bitcoin.stackexchange.com/questions/2859/how-are-transaction-hashes-calculated val txOutput = "00f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" val output = RawTransactionOutputParser.read(txOutput) @@ -54,7 +57,8 @@ class RawTransactionOutputParserTest extends BitcoinSUnitTest { it must "serialize the empty transaction output correctly" in { encode(RawTransactionOutputParser.write(EmptyTransactionOutput)) must be( - "ffffffffffffffff00") + "ffffffffffffffff00" + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/util/Base58Test.scala b/core-test/src/test/scala/org/bitcoins/core/util/Base58Test.scala index c7183fa5ac..7f76bd87a5 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/Base58Test.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/Base58Test.scala @@ -31,9 +31,11 @@ class Base58Test extends BitcoinSUnitTest { Base58.encode("626262") must be("a3gV") Base58.encode("636363") must be("aPEr") Base58.encode("73696d706c792061206c6f6e6720737472696e67") must be( - "2cFupjhnEsSn59qHXstmK2ffpLv2") + "2cFupjhnEsSn59qHXstmK2ffpLv2" + ) Base58.encode("00eb15231dfceb60925886b67d065299925915aeb172c06647") must be( - "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L") + "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L" + ) Base58.encode("516b6fcd0f") must be("ABnLTmg") Base58.encode("bf4f89001e670274dd") must be("3SEo3LWLoPntC") Base58.encode("572e4794") must be("3EFU7m") @@ -49,9 +51,11 @@ class Base58Test extends BitcoinSUnitTest { decodedBase58EncodeToHex("a3gV") must be("626262") decodedBase58EncodeToHex("aPEr") must be("636363") decodedBase58EncodeToHex("2cFupjhnEsSn59qHXstmK2ffpLv2") must be( - "73696d706c792061206c6f6e6720737472696e67") + "73696d706c792061206c6f6e6720737472696e67" + ) decodedBase58EncodeToHex("1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L") must be( - "00eb15231dfceb60925886b67d065299925915aeb172c06647") + "00eb15231dfceb60925886b67d065299925915aeb172c06647" + ) decodedBase58EncodeToHex("ABnLTmg") must be("516b6fcd0f") decodedBase58EncodeToHex("3SEo3LWLoPntC") must be("bf4f89001e670274dd") decodedBase58EncodeToHex("3EFU7m") must be("572e4794") @@ -66,14 +70,15 @@ class Base58Test extends BitcoinSUnitTest { for { testCase <- testCases } yield { - //if testCase is an Address, it must have a valid base58 representation + // if testCase is an Address, it must have a valid base58 representation if (testCase.addressOrWIFPrivKey.isLeft) { Base58.isValid( - testCase.addressOrWIFPrivKey.swap.getOrElse(fail()).toString) must be( - true) + testCase.addressOrWIFPrivKey.swap.getOrElse(fail()).toString + ) must be(true) } else { Base58.isValid(testCase.addressOrWIFPrivKey.getOrElse(fail())) must be( - true) + true + ) } } } @@ -98,7 +103,8 @@ class Base58Test extends BitcoinSUnitTest { } it must "decodeCheck a valid string and succeed" in { Base58.decodeCheck("3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou").isSuccess must be( - true) + true + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/util/BinaryTreeTest.scala b/core-test/src/test/scala/org/bitcoins/core/util/BinaryTreeTest.scala index 55b9f30366..914a2f8fc7 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/BinaryTreeTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/BinaryTreeTest.scala @@ -14,28 +14,32 @@ class BinaryTreeTest extends BitcoinSUnitTest { } it must "convert a binary tree to to a list with node values" in { - //val script = List(OP_IF, OP_IF, OP_1, OP_ELSE, OP_0, OP_ENDIF, OP_ELSE, OP_IF, OP_0, OP_ELSE, OP_1, OP_ENDIF, OP_ENDIF) + // val script = List(OP_IF, OP_IF, OP_1, OP_ELSE, OP_0, OP_ENDIF, OP_ELSE, OP_IF, OP_0, OP_ELSE, OP_1, OP_ENDIF, OP_ENDIF) val bTree: BinaryTree[ScriptToken] = Node[ScriptToken]( OP_IF, Node(OP_IF, Leaf(OP_1), Node(OP_ELSE, Leaf(OP_0), Leaf(OP_ENDIF))), - Node(OP_ELSE, - Node(OP_IF, Leaf(OP_0), Node(OP_ELSE, Leaf(OP_1), Leaf(OP_ENDIF))), - Leaf(OP_ENDIF)) + Node( + OP_ELSE, + Node(OP_IF, Leaf(OP_0), Node(OP_ELSE, Leaf(OP_1), Leaf(OP_ENDIF))), + Leaf(OP_ENDIF) + ) ) - val script = List(OP_IF, - OP_IF, - OP_1, - OP_ELSE, - OP_0, - OP_ENDIF, - OP_ELSE, - OP_IF, - OP_0, - OP_ELSE, - OP_1, - OP_ENDIF, - OP_ENDIF) + val script = List( + OP_IF, + OP_IF, + OP_1, + OP_ELSE, + OP_0, + OP_ENDIF, + OP_ELSE, + OP_IF, + OP_0, + OP_ELSE, + OP_1, + OP_ENDIF, + OP_ENDIF + ) bTree.toSeq.size must be(script.size) bTree.toSeq must be(script) @@ -50,9 +54,11 @@ class BinaryTreeTest extends BitcoinSUnitTest { val seq1 = bTree1.toSeq seq1 must be(List(1, 2, 3)) - val bTree2 = Node(OP_IF, - Node(OP_1, Empty, Empty), - Node(OP_ELSE, Node(OP_2, Empty, Empty), Leaf(OP_ENDIF))) + val bTree2 = Node( + OP_IF, + Node(OP_1, Empty, Empty), + Node(OP_ELSE, Node(OP_2, Empty, Empty), Leaf(OP_ENDIF)) + ) val seq2 = bTree2.toSeq seq2 must be(Seq(OP_IF, OP_1, OP_ELSE, OP_2, OP_ENDIF)) } @@ -81,9 +87,11 @@ class BinaryTreeTest extends BitcoinSUnitTest { } it must "tell if a tree contains a certain element" in { - val tree = Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("3", Empty, Leaf("4"))) + val tree = Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("3", Empty, Leaf("4")) + ) tree.contains("Hello")()() must equal(true) tree.contains("there")()() must equal(true) @@ -94,63 +102,86 @@ class BinaryTreeTest extends BitcoinSUnitTest { } it must "remove a subtree" in { - val tree = Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("3", Empty, Leaf("4"))) + val tree = Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("3", Empty, Leaf("4")) + ) val subTree = Node("there", Leaf("1"), Leaf("2")) tree.remove(subTree)() must be( - Node("Hello", Empty, Node("3", Empty, Leaf("4")))) + Node("Hello", Empty, Node("3", Empty, Leaf("4"))) + ) } it must "remove the entire parent tree if given as a subtree" in { - val tree = Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("3", Empty, Leaf("4"))) + val tree = Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("3", Empty, Leaf("4")) + ) tree.remove(tree)() must be(Empty) } it must "remove no nodes if the given subtree DNE in the parent tree" in { - val tree = Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("3", Empty, Leaf("4"))) - val subTree = Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("4", Empty, Leaf("4"))) + val tree = Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("3", Empty, Leaf("4")) + ) + val subTree = Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("4", Empty, Leaf("4")) + ) tree.remove(subTree)() must be(tree) } it must "replace an entire tree" in { - val tree = Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("3", Empty, Leaf("4"))) + val tree = Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("3", Empty, Leaf("4")) + ) tree.replace(tree, Empty)() must be(Empty) } it must "replace the left branch of a tree" in { - val tree = Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("3", Empty, Leaf("4"))) + val tree = Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("3", Empty, Leaf("4")) + ) tree.replace(tree.left.get, tree.right.get)() must be( - Node[String]("Hello", - Node("3", Empty, Leaf("4")), - Node("3", Empty, Leaf("4")))) + Node[String]( + "Hello", + Node("3", Empty, Leaf("4")), + Node("3", Empty, Leaf("4")) + ) + ) } it must "replace the right branch of a tree" in { - val tree = Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("3", Empty, Leaf("4"))) + val tree = Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("3", Empty, Leaf("4")) + ) tree.replace(tree.right.get, tree.left.get)() must be( - Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("there", Leaf("1"), Leaf("2")))) + Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("there", Leaf("1"), Leaf("2")) + ) + ) } it must "replace nothing in a binary tree if there is no match" in { - val tree = Node[String]("Hello", - Node("there", Leaf("1"), Leaf("2")), - Node("3", Empty, Leaf("4"))) + val tree = Node[String]( + "Hello", + Node("there", Leaf("1"), Leaf("2")), + Node("3", Empty, Leaf("4")) + ) tree.replace(Node("thre", Leaf("1"), Leaf("2")), Empty)() must be(tree) } diff --git a/core-test/src/test/scala/org/bitcoins/core/util/BitcoinSUtilSpec.scala b/core-test/src/test/scala/org/bitcoins/core/util/BitcoinSUtilSpec.scala index 369f9313c3..2b7bd3b713 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/BitcoinSUtilSpec.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/BitcoinSUtilSpec.scala @@ -18,10 +18,10 @@ class BitcoinSUtilSpec extends Properties("BitcoinSUtilSpec") { } property( - "Convert a byte to a bit vector, convert it back to the original byte") = - Prop.forAll { byte: Byte => - BytesUtil - .bitVectorToBytes(BytesUtil.byteToBitVector(byte)) - .toByte() == byte - } + "Convert a byte to a bit vector, convert it back to the original byte" + ) = Prop.forAll { byte: Byte => + BytesUtil + .bitVectorToBytes(BytesUtil.byteToBitVector(byte)) + .toByte() == byte + } } diff --git a/core-test/src/test/scala/org/bitcoins/core/util/BitcoinSUtilTest.scala b/core-test/src/test/scala/org/bitcoins/core/util/BitcoinSUtilTest.scala index a0222f1c56..90a4b9f0b6 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/BitcoinSUtilTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/BitcoinSUtilTest.scala @@ -12,40 +12,46 @@ class BitcoinSUtilTest extends BitcoinSUnitTest { BytesUtil.isHex("") must be(false) - //don't allow upper case hex chars + // don't allow upper case hex chars BytesUtil.isHex("ABCDEF0123456789") must be(false) BytesUtil.isHex("g") must be(false) - //fail to parse a hex string that is uneven + // fail to parse a hex string that is uneven BytesUtil.isHex("123") must be(false) } it must "convert a byte to a bit vector" in { val byte = 0.toByte BytesUtil.byteToBitVector(byte).toIndexedSeq must be( - Seq(false, false, false, false, false, false, false, false)) + Seq(false, false, false, false, false, false, false, false) + ) val byte1 = 1.toByte BytesUtil.byteToBitVector(byte1).toIndexedSeq must be( - Seq(false, false, false, false, false, false, false, true)) + Seq(false, false, false, false, false, false, false, true) + ) val byte2 = 2.toByte BytesUtil.byteToBitVector(byte2).toIndexedSeq must be( - Seq(false, false, false, false, false, false, true, false)) + Seq(false, false, false, false, false, false, true, false) + ) val byte3 = 3.toByte BytesUtil.byteToBitVector(byte3).toIndexedSeq must be( - Seq(false, false, false, false, false, false, true, true)) + Seq(false, false, false, false, false, false, true, true) + ) val maxByte = 0xff.toByte BytesUtil.byteToBitVector(maxByte).toIndexedSeq must be( - Seq(true, true, true, true, true, true, true, true)) + Seq(true, true, true, true, true, true, true, true) + ) } it must "convert a bit vector to a byte" in { val bitVector0 = BitVector.bits( - Seq(false, false, false, false, false, false, false, false)) + Seq(false, false, false, false, false, false, false, false) + ) BytesUtil.bitVectorToBytes(bitVector0).toByte() must be(0.toByte) val bitVector1 = diff --git a/core-test/src/test/scala/org/bitcoins/core/util/BitcoinScriptUtilTest.scala b/core-test/src/test/scala/org/bitcoins/core/util/BitcoinScriptUtilTest.scala index 9c1ec7b2fc..1641f22857 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/BitcoinScriptUtilTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/BitcoinScriptUtilTest.scala @@ -17,7 +17,7 @@ import scodec.bits.ByteVector */ class BitcoinScriptUtilTest extends BitcoinSUnitTest { - //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + // from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val asm = TestUtil.p2pkhScriptPubKey.asm val expectedHex = TestUtil.rawP2PKHScriptPubKey "BitcoinScriptUtil" must "give us the correct hexadecimal value of an asm script" in { @@ -29,21 +29,25 @@ class BitcoinScriptUtilTest extends BitcoinSUnitTest { BitcoinScriptUtil .filterPushOps( Seq(OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4) ++ - BytesToPushOntoStack.operations) + BytesToPushOntoStack.operations + ) .isEmpty must be(true) } // https://en.bitcoin.it/wiki/Genesis_block it must "filter out non-data from the genesis coinbase transaction" in { val genesisPK = ECPublicKeyBytes.fromHex( - "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") + "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f" + ) val output = TransactionOutput.fromHex( - "00f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac") + "00f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" + ) val scriptPubKey = output.scriptPubKey assert( BitcoinScriptUtil .getDataTokens(scriptPubKey.asm) - .map(_.bytes) == Vector(genesisPK.bytes)) + .map(_.bytes) == Vector(genesisPK.bytes) + ) } it must "filter out all but the data tokens" in { @@ -51,35 +55,40 @@ class BitcoinScriptUtilTest extends BitcoinSUnitTest { assert( BitcoinScriptUtil .getDataTokens(p2pkhScript.asm) - .map(_.bytes) == Vector(p2pkhScript.pubKeyHash.bytes)) + .map(_.bytes) == Vector(p2pkhScript.pubKeyHash.bytes) + ) } forAll(ScriptGenerators.p2shScriptPubKey) { case (p2shScript, _, _) => assert( BitcoinScriptUtil .getDataTokens(p2shScript.asm) - .map(_.bytes) == Vector(p2shScript.scriptHash.bytes)) + .map(_.bytes) == Vector(p2shScript.scriptHash.bytes) + ) } forAll(ScriptGenerators.p2wshSPKV0) { case (p2wshScript, _, _) => assert( BitcoinScriptUtil .getDataTokens(p2wshScript.asm) - .map(_.bytes) == Vector(p2wshScript.scriptHash.bytes)) + .map(_.bytes) == Vector(p2wshScript.scriptHash.bytes) + ) } forAll(ScriptGenerators.p2wpkhSPKV0) { case (p2wpkhScript, _) => assert( BitcoinScriptUtil .getDataTokens(p2wpkhScript.asm) - .map(_.bytes) == Vector(p2wpkhScript.pubKeyHash.bytes)) + .map(_.bytes) == Vector(p2wpkhScript.pubKeyHash.bytes) + ) } forAll(ScriptGenerators.multiSigScriptPubKey) { case (multiSigScript, _) => assert( BitcoinScriptUtil .getDataTokens(multiSigScript.asm) - .map(_.bytes) == multiSigScript.publicKeys.map(_.bytes)) + .map(_.bytes) == multiSigScript.publicKeys.map(_.bytes) + ) } } @@ -90,12 +99,14 @@ class BitcoinScriptUtilTest extends BitcoinSUnitTest { BitcoinScriptUtil.countsTowardsScriptOpLimit(OP_NOP) must be(true) BitcoinScriptUtil.countsTowardsScriptOpLimit( - OP_CHECKLOCKTIMEVERIFY) must be(true) + OP_CHECKLOCKTIMEVERIFY + ) must be(true) } it must "not count script constants towards the script count limit" in { BitcoinScriptUtil.countsTowardsScriptOpLimit( - ScriptConstant("1234")) must be(false) + ScriptConstant("1234") + ) must be(false) } it must "not count OP_PUSHDATA operations towards the script count" in { @@ -115,17 +126,17 @@ class BitcoinScriptUtilTest extends BitcoinSUnitTest { BitcoinScriptUtil.countSigOps(Seq(OP_CHECKSIGVERIFY)) must be(1) BitcoinScriptUtil.countSigOps( - Seq(OP_CHECKSIG, - OP_CHECKSIG, - OP_CHECKSIG, - OP_CHECKSIG, - OP_CHECKSIG)) must be(5) + Seq(OP_CHECKSIG, OP_CHECKSIG, OP_CHECKSIG, OP_CHECKSIG, OP_CHECKSIG) + ) must be(5) BitcoinScriptUtil.countSigOps( - Seq(OP_CHECKSIGVERIFY, - OP_CHECKSIGVERIFY, - OP_CHECKSIGVERIFY, - OP_CHECKSIGVERIFY, - OP_CHECKSIGVERIFY)) must be(5) + Seq( + OP_CHECKSIGVERIFY, + OP_CHECKSIGVERIFY, + OP_CHECKSIGVERIFY, + OP_CHECKSIGVERIFY, + OP_CHECKSIGVERIFY + ) + ) must be(5) } it must "count n sigops when have n possible signatures in a OP_CHECKMULTISIG or OP_CHECKMULTISIGVERIFY" in { @@ -137,26 +148,31 @@ class BitcoinScriptUtilTest extends BitcoinSUnitTest { BitcoinScriptUtil.countSigOps(Seq(OP_16, OP_CHECKMULTISIG)) must be(16) BitcoinScriptUtil.countSigOps(Seq(OP_16, OP_CHECKMULTISIGVERIFY)) must be( - 16) + 16 + ) } it must "count n sigops when have n possible signatures with multiple occurrences OP_CHECKMULTISIG or OP_CHECKMULTISIGVERIFY in a script" in { BitcoinScriptUtil.countSigOps( - Seq(OP_0, OP_CHECKMULTISIG, OP_0, OP_CHECKMULTISIG)) must be(0) + Seq(OP_0, OP_CHECKMULTISIG, OP_0, OP_CHECKMULTISIG) + ) must be(0) BitcoinScriptUtil.countSigOps( - Seq(OP_0, OP_CHECKMULTISIGVERIFY, OP_0, OP_CHECKMULTISIGVERIFY)) must be( - 0) + Seq(OP_0, OP_CHECKMULTISIGVERIFY, OP_0, OP_CHECKMULTISIGVERIFY) + ) must be(0) BitcoinScriptUtil.countSigOps( - Seq(OP_1, OP_CHECKMULTISIG, OP_1, OP_CHECKMULTISIG)) must be(2) + Seq(OP_1, OP_CHECKMULTISIG, OP_1, OP_CHECKMULTISIG) + ) must be(2) BitcoinScriptUtil.countSigOps( - Seq(OP_1, OP_CHECKMULTISIGVERIFY, OP_1, OP_CHECKMULTISIGVERIFY)) must be( - 2) + Seq(OP_1, OP_CHECKMULTISIGVERIFY, OP_1, OP_CHECKMULTISIGVERIFY) + ) must be(2) BitcoinScriptUtil.countSigOps( - Seq(OP_16, OP_CHECKMULTISIG, OP_16, OP_CHECKMULTISIG)) must be(32) + Seq(OP_16, OP_CHECKMULTISIG, OP_16, OP_CHECKMULTISIG) + ) must be(32) BitcoinScriptUtil.countSigOps( - Seq(OP_16, OP_CHECKMULTISIGVERIFY, OP_16, OP_CHECKMULTISIG)) must be(32) + Seq(OP_16, OP_CHECKMULTISIGVERIFY, OP_16, OP_CHECKMULTISIG) + ) must be(32) } it must "determine if the empty script is push only" in { @@ -170,22 +186,28 @@ class BitcoinScriptUtilTest extends BitcoinSUnitTest { it must "determine that a script is not push only if it contains a ScriptConstant" in { BitcoinScriptUtil.isPushOnly( - Seq(OP_NOP, BytesToPushOntoStack(1), ScriptConstant("51"))) must be(false) + Seq(OP_NOP, BytesToPushOntoStack(1), ScriptConstant("51")) + ) must be(false) } it must "determine that the script is not push only if it contains an script number operation" in { BitcoinScriptUtil.isMinimalPush(BytesToPushOntoStack(1), OP_1) must be( - false) + false + ) } it must "determine that a script is not minimal push when pushing 4f (-1)" in { - BitcoinScriptUtil.isMinimalPush(BytesToPushOntoStack(1), - ScriptConstant("81")) must be(false) + BitcoinScriptUtil.isMinimalPush( + BytesToPushOntoStack(1), + ScriptConstant("81") + ) must be(false) } it must "determine that a script is minimal push when pushing 4f (79)" in { - BitcoinScriptUtil.isMinimalPush(BytesToPushOntoStack(1), - ScriptConstant("4f")) must be(true) + BitcoinScriptUtil.isMinimalPush( + BytesToPushOntoStack(1), + ScriptConstant("4f") + ) must be(true) } it must "determine that a script is minimal push when pushing OP_1NEGATE (-1)" in { @@ -252,25 +274,31 @@ class BitcoinScriptUtilTest extends BitcoinSUnitTest { BitcoinScriptUtil.isShortestEncoding(ScriptConstant("0500")) must be(false) BitcoinScriptUtil.isShortestEncoding(ScriptConstant("050000")) must be( - false) + false + ) BitcoinScriptUtil.isShortestEncoding(ScriptConstant("0580")) must be(false) BitcoinScriptUtil.isShortestEncoding(ScriptConstant("050080")) must be( - false) + false + ) BitcoinScriptUtil.isShortestEncoding(ScriptConstant("ff7f80")) must be( - false) + false + ) BitcoinScriptUtil.isShortestEncoding(ScriptConstant("ff7f00")) must be( - false) + false + ) BitcoinScriptUtil.isShortestEncoding(ScriptConstant("ffff7f80")) must be( - false) + false + ) BitcoinScriptUtil.isShortestEncoding(ScriptConstant("ffff7f00")) must be( - false) + false + ) } it must "check a public key's encoding" in { - //pubkeys must be compressed or uncompressed or else that are not validly encoded + // pubkeys must be compressed or uncompressed or else that are not validly encoded val key = ECPublicKeyBytes("00") val program = TestUtil.testProgramExecutionInProgress BitcoinScriptUtil.checkPubKeyEncoding(key, program) must be(false) @@ -283,43 +311,55 @@ class BitcoinScriptUtilTest extends BitcoinSUnitTest { val scriptNum16 = ScriptNumber(16) val scriptNum17 = ScriptNumber(17) BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum100) must be( - scriptNum100) + scriptNum100 + ) BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum10) must be( - OP_10) + OP_10 + ) BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNumZero) must be( - OP_0) + OP_0 + ) BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum16) must be( - OP_16) + OP_16 + ) BitcoinScriptUtil.minimalScriptNumberRepresentation(scriptNum17) must be( - scriptNum17) + scriptNum17 + ) BitcoinScriptUtil.minimalScriptNumberRepresentation( - ScriptNumber(-1)) must be(OP_1NEGATE) + ScriptNumber(-1) + ) must be(OP_1NEGATE) BitcoinScriptUtil.minimalScriptNumberRepresentation( - ScriptNumber(-2)) must be(ScriptNumber(-2)) + ScriptNumber(-2) + ) must be(ScriptNumber(-2)) } it must "determine if a segwit pubkey is compressed" in { val key = ECPrivateKeyBytes.freshPrivateKey(false) val pubKey = key.publicKeyBytes val flags = Seq(ScriptVerifyWitnessPubKeyType) - BitcoinScriptUtil.isValidPubKeyEncoding(pubKey, - SigVersionWitnessV0, - flags) must be( - Some(ScriptErrorWitnessPubKeyType)) + BitcoinScriptUtil.isValidPubKeyEncoding( + pubKey, + SigVersionWitnessV0, + flags + ) must be(Some(ScriptErrorWitnessPubKeyType)) val key2 = ECPrivateKeyBytes.freshPrivateKey(false) val pubKey2 = key2.publicKeyBytes - BitcoinScriptUtil.isValidPubKeyEncoding(pubKey2, - SigVersionBase, - flags) must be(None) + BitcoinScriptUtil.isValidPubKeyEncoding( + pubKey2, + SigVersionBase, + flags + ) must be(None) } it must "remove the signatures from a p2sh scriptSig" in { val p2shScriptSig = TestUtil.p2sh2Of3ScriptSig val signatures = p2shScriptSig.signatures val asmWithoutSigs = - BitcoinScriptUtil.removeSignaturesFromScript(signatures, - p2shScriptSig.asm) + BitcoinScriptUtil.removeSignaturesFromScript( + signatures, + p2shScriptSig.asm + ) val sigExists = signatures.map(sig => asmWithoutSigs.contains(ScriptConstant(sig.hex))) sigExists.contains(true) must be(false) @@ -328,7 +368,8 @@ class BitcoinScriptUtilTest extends BitcoinSUnitTest { it must "cast a script token to a boolean value" in { BitcoinScriptUtil.castToBool(ScriptConstant("")) must be(false) BitcoinScriptUtil.castToBool( - ScriptConstant(ByteVector(0x80.toByte))) must be(false) + ScriptConstant(ByteVector(0x80.toByte)) + ) must be(false) BitcoinScriptUtil.castToBool(ScriptConstant("000000")) must be(false) BitcoinScriptUtil.castToBool(ScriptConstant("00000080")) must be(false) diff --git a/core-test/src/test/scala/org/bitcoins/core/util/FutureUtilTest.scala b/core-test/src/test/scala/org/bitcoins/core/util/FutureUtilTest.scala index 6804d27768..53c0cedc0d 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/FutureUtilTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/FutureUtilTest.scala @@ -29,7 +29,8 @@ class FutureUtilTest extends BitcoinSJvmTest { future2.onComplete { _ => if (!future1.isCompleted) { assertionP.failure( - new Error(s"future1 was not complete by future2 completing")) + new Error(s"future1 was not complete by future2 completing") + ) } else { assertionP.success(succeed) } @@ -60,10 +61,10 @@ class FutureUtilTest extends BitcoinSJvmTest { val doneF = FutureUtil.batchAndSyncExecute(elements = vec, f = f, batchSize = 1) - //here is how this test case works: - //the vector above has the same number of elements as available processors in it, and the batchSize is 1 - //each function sleeps for 1000ms (1 second). If things are - //not run in parallel, the total time should be 5 seconds (5 elements * 1 second sleep) + // here is how this test case works: + // the vector above has the same number of elements as available processors in it, and the batchSize is 1 + // each function sleeps for 1000ms (1 second). If things are + // not run in parallel, the total time should be 5 seconds (5 elements * 1 second sleep) for { _ <- doneF stop = TimeUtil.now @@ -73,7 +74,8 @@ class FutureUtilTest extends BitcoinSJvmTest { succeed } else { fail( - s"Batch did not execute in parallel! difference=${difference} seconds") + s"Batch did not execute in parallel! difference=${difference} seconds" + ) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/util/NetworkUtilTest.scala b/core-test/src/test/scala/org/bitcoins/core/util/NetworkUtilTest.scala index b08f598c1c..c3161ec662 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/NetworkUtilTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/NetworkUtilTest.scala @@ -18,7 +18,8 @@ class NetworkUtilTest extends BitcoinSUtilTest { "NetworkUtil" must "convert torV3 pubkey to correct .onion address and vice versa" in { val pubkey = ByteVector.fromValidHex( - "98908ec971ad17171365865a249c420d04a66f103f973a62d8404ce2f4af1ee2") + "98908ec971ad17171365865a249c420d04a66f103f973a62d8404ce2f4af1ee2" + ) val address = "tcii5slrvulroe3fqzncjhccbuckm3yqh6ltuywyibgof5fpd3rpycyd.onion" val addressFromKey = NetworkUtil.parseUnresolvedInetSocketAddress(pubkey) @@ -30,8 +31,11 @@ class NetworkUtilTest extends BitcoinSUtilTest { it must "determine if a block header is stale" in { val staleHeader = ChainTestUtil.genesisHeaderDb assert( - NetworkUtil.isBlockHeaderStale(staleHeader.blockHeader, - MainNetChainParams)) + NetworkUtil.isBlockHeaderStale( + staleHeader.blockHeader, + MainNetChainParams + ) + ) val nonStale = BlockHeader( ChainTestUtil.genesisHeaderDb.version, @@ -57,7 +61,8 @@ class NetworkUtilTest extends BitcoinSUtilTest { } assert( - NetworkUtil.isBlockHeaderStale(barleyStaleHeader, MainNetChainParams)) + NetworkUtil.isBlockHeaderStale(barleyStaleHeader, MainNetChainParams) + ) val barleyNotStaleHeader = { val timestamp = Instant.now.minus(29, ChronoUnit.MINUTES).getEpochSecond @@ -72,7 +77,8 @@ class NetworkUtilTest extends BitcoinSUtilTest { } assert( - !NetworkUtil.isBlockHeaderStale(barleyNotStaleHeader, MainNetChainParams)) + !NetworkUtil.isBlockHeaderStale(barleyNotStaleHeader, MainNetChainParams) + ) } it must "block header message that is not aligned with a tcp frame" in { @@ -83,9 +89,11 @@ class NetworkUtilTest extends BitcoinSUtilTest { BlockHeader( Int32(315017594), DoubleSha256Digest( - "177e777f078d2deeaa3ad4b82e78a00ad2f4738c5217f7a36d9cf3bd11e41817"), + "177e777f078d2deeaa3ad4b82e78a00ad2f4738c5217f7a36d9cf3bd11e41817" + ), DoubleSha256Digest( - "1dcaebebd620823bb344bd18a18276de508910d66b4e3cbb3426a14eced66224"), + "1dcaebebd620823bb344bd18a18276de508910d66b4e3cbb3426a14eced66224" + ), UInt32(2845833462L), UInt32(2626024374L), UInt32(2637850613L) @@ -93,9 +101,11 @@ class NetworkUtilTest extends BitcoinSUtilTest { BlockHeader( Int32(1694049746), DoubleSha256Digest( - "07b6d61809476830bc7ef862a983a7222997df3f639e0d2aa5902a5a48018430"), + "07b6d61809476830bc7ef862a983a7222997df3f639e0d2aa5902a5a48018430" + ), DoubleSha256Digest( - "68c65f803b70b72563e86ac3e8e20ad11fbfa2eac3f9fddf4bc624d03a14f084"), + "68c65f803b70b72563e86ac3e8e20ad11fbfa2eac3f9fddf4bc624d03a14f084" + ), UInt32(202993555), UInt32(4046619225L), UInt32(1231236881) @@ -103,7 +113,7 @@ class NetworkUtilTest extends BitcoinSUtilTest { ) ) val networkMsg = NetworkMessage(np, headersMsg) - //split the network msg at a random index to simulate a tcp frame not being aligned + // split the network msg at a random index to simulate a tcp frame not being aligned val randomIndex = scala.util.Random.nextInt().abs % networkMsg.bytes.size val (firstHalf, secondHalf) = networkMsg.bytes.splitAt(randomIndex) val (firstHalfParseHeaders, remainingBytes) = @@ -122,8 +132,9 @@ class NetworkUtilTest extends BitcoinSUtilTest { it must "return the entire byte array if a message is not aligned to a byte frame" in { val networkMsg = NetworkMessage( - "fabfb5da76657273696f6e00000000006e000000b12d23e97d1101000000000000000000b487c95f00000000000000000000000000000000000000000000ffffc0f1a38e480c010000000000000000000000000000000000ffff7f000101480c0000000000000000182f626974636f696e732d7370762d6e6f64652f302e302e310000000000") - //remove last byte so the message is not aligned + "fabfb5da76657273696f6e00000000006e000000b12d23e97d1101000000000000000000b487c95f00000000000000000000000000000000000000000000ffffc0f1a38e480c010000000000000000000000000000000000ffff7f000101480c0000000000000000182f626974636f696e732d7370762d6e6f64652f302e302e310000000000" + ) + // remove last byte so the message is not aligned val bytes = networkMsg.bytes.slice(0, networkMsg.bytes.size - 1) val (_, unAlignedBytes) = NetworkUtil.parseIndividualMessages(bytes) @@ -147,10 +158,12 @@ class NetworkUtilTest extends BitcoinSUtilTest { it must "parse an unknown command" in { val header: NetworkHeader = - NetworkHeader(TestNet3, - "madeup", - UInt32.zero, - CryptoUtil.doubleSHA256(ByteVector.empty).bytes.take(4)) + NetworkHeader( + TestNet3, + "madeup", + UInt32.zero, + CryptoUtil.doubleSHA256(ByteVector.empty).bytes.take(4) + ) val (messages, leftover) = NetworkUtil.parseIndividualMessages(header.bytes) assert(messages.isEmpty) diff --git a/core-test/src/test/scala/org/bitcoins/core/util/NumberUtilTest.scala b/core-test/src/test/scala/org/bitcoins/core/util/NumberUtilTest.scala index 5cc9dd2769..2b6988e6dd 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/NumberUtilTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/NumberUtilTest.scala @@ -15,15 +15,16 @@ class NumberUtilTest extends BitcoinSUnitTest { private def runTest( nBits: UInt32, - expected: BlockHeader.TargetDifficultyHelper): Assertion = { + expected: BlockHeader.TargetDifficultyHelper + ): Assertion = { val expansion = NumberUtil.targetExpansion(nBits) assert(expansion == expected) } it must "expand nbits to 0 difficulty threshold" in { - //from the examples table on bitcoin developer reference site - //https://bitcoin.org/en/developer-reference#target-nbits + // from the examples table on bitcoin developer reference site + // https://bitcoin.org/en/developer-reference#target-nbits val nBits1 = UInt32.fromHex("01003456") val expected1 = BigInteger.valueOf(0) val diffHelper1 = { @@ -92,11 +93,12 @@ class NumberUtilTest extends BitcoinSUnitTest { } it must "expand the minimum difficulty on bitcoin main network" in { - //https://stackoverflow.com/questions/22059359/trying-to-understand-nbits-value-from-stratum-protocol + // https://stackoverflow.com/questions/22059359/trying-to-understand-nbits-value-from-stratum-protocol val nBits = UInt32.fromHex("1d00ffff") val expected = new BigInteger( "00ffff0000000000000000000000000000000000000000000000000000", - 16) + 16 + ) val diffHelper = { BlockHeader.TargetDifficultyHelper( expected, @@ -128,7 +130,7 @@ class NumberUtilTest extends BitcoinSUnitTest { behavior of "NumberUtil.targetCompression" it must "handle all cases as enumerated in bitcoin core" in { - //https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/test/arith_uint256_tests.cpp#L405 + // https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/test/arith_uint256_tests.cpp#L405 val expanded = NumberUtil.targetExpansion(UInt32.zero) NumberUtil.targetCompression(expanded) must be(UInt32.zero) @@ -167,18 +169,20 @@ class NumberUtilTest extends BitcoinSUnitTest { NumberUtil.targetCompression(expanded10) must be(UInt32.fromHex("01120000")) - NumberUtil.targetCompression(bigInt = BigInt(0x80), - isNegative = false) must be( - UInt32.fromHex("02008000")) + NumberUtil.targetCompression( + bigInt = BigInt(0x80), + isNegative = false + ) must be(UInt32.fromHex("02008000")) val expanded11 = NumberUtil.targetExpansion(UInt32.fromHex("01fedcba")) expanded11.difficulty must be(126) expanded11.isNegative must be(true) NumberUtil.targetCompression(expanded11) must be(UInt32.fromHex("01fe0000")) - NumberUtil.targetCompression(bigInt = BigInt(0x80), - isNegative = false) must be( - UInt32.fromHex("02008000")) + NumberUtil.targetCompression( + bigInt = BigInt(0x80), + isNegative = false + ) must be(UInt32.fromHex("02008000")) val expanded12 = NumberUtil.targetExpansion(UInt32.fromHex("02123456")) NumberUtil.targetCompression(expanded12) must be(UInt32.fromHex("02123400")) diff --git a/core-test/src/test/scala/org/bitcoins/core/util/OrderedNoncesTest.scala b/core-test/src/test/scala/org/bitcoins/core/util/OrderedNoncesTest.scala index 2ed9ca3623..9408b7e210 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/OrderedNoncesTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/OrderedNoncesTest.scala @@ -10,9 +10,11 @@ class OrderedNoncesTest extends BitcoinSUnitTest { val unsorted = Vector( SchnorrNonce( - "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea"), + "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea" + ), SchnorrNonce( - "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc") + "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc" + ) ) it must "throw an exception if you create an unordered nonces" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/util/OrderedSchnorrSignaturesTest.scala b/core-test/src/test/scala/org/bitcoins/core/util/OrderedSchnorrSignaturesTest.scala index a7dbf4a9ad..2c18875ddf 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/OrderedSchnorrSignaturesTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/OrderedSchnorrSignaturesTest.scala @@ -11,12 +11,16 @@ class OrderedSchnorrSignaturesTest extends BitcoinSUnitTest { val unsorted = Vector( SchnorrDigitalSignature( SchnorrNonce( - "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea"), - FieldElement.one), + "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea" + ), + FieldElement.one + ), SchnorrDigitalSignature( SchnorrNonce( - "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc"), - FieldElement.one) + "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc" + ), + FieldElement.one + ) ) it must "throw an exception if the signatures are out of order" in { diff --git a/core-test/src/test/scala/org/bitcoins/core/util/ScriptProgramTestUtil.scala b/core-test/src/test/scala/org/bitcoins/core/util/ScriptProgramTestUtil.scala index 4bb49ccf8b..cf41236a6e 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/ScriptProgramTestUtil.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/ScriptProgramTestUtil.scala @@ -10,8 +10,8 @@ import org.bitcoins.core.script.{ */ trait ScriptProgramTestUtil { - /** Matches a [[StartedScriptProgram]] to an [[ExecutedScriptProgram]] or else throws an exception - * useful for testing purposes. + /** Matches a [[StartedScriptProgram]] to an [[ExecutedScriptProgram]] or else + * throws an exception useful for testing purposes. */ def toExecutedScriptProgram(p: StartedScriptProgram): ExecutedScriptProgram = p match { @@ -20,14 +20,18 @@ trait ScriptProgramTestUtil { throw new RuntimeException("Should be an executed script program") } - /** Matches a [[StartedScriptProgram]] to a [[ExecutionInProgressScriptProgram]] or else throws an exception. */ + /** Matches a [[StartedScriptProgram]] to a + * [[ExecutionInProgressScriptProgram]] or else throws an exception. + */ def toExecutionInProgressScriptProgram( - p: StartedScriptProgram): ExecutionInProgressScriptProgram = + p: StartedScriptProgram + ): ExecutionInProgressScriptProgram = p match { case e: ExecutionInProgressScriptProgram => e case _: ExecutedScriptProgram => throw new RuntimeException( - "Must be an execution in progress script program") + "Must be an execution in progress script program" + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/util/SortedVecTest.scala b/core-test/src/test/scala/org/bitcoins/core/util/SortedVecTest.scala index 9cf1e9db3e..e413f187b9 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/SortedVecTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/SortedVecTest.scala @@ -17,24 +17,38 @@ class SortedVecTest extends BitcoinSUnitTest { assert(SortedVec.sort(Vector(3, 2, 1)) == SortedVec(Vector(1, 2, 3))) assert( SortedVec.sort(Vector(3.0, 2.0, 1.123)) == SortedVec( - Vector(1.123, 2.0, 3.0))) + Vector(1.123, 2.0, 3.0) + ) + ) assert( - SortedVec.sort(Vector('c', 'b', 'a')) == SortedVec(Vector('a', 'b', 'c'))) + SortedVec.sort(Vector('c', 'b', 'a')) == SortedVec(Vector('a', 'b', 'c')) + ) assert( SortedVec.sort(Vector("cab", "ceb", "abc")) == SortedVec( - Vector("abc", "cab", "ceb"))) + Vector("abc", "cab", "ceb") + ) + ) assert( - SortedVec.sort[SchnorrNonce, NetworkElement](Vector( - SchnorrNonce( - "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea"), - SchnorrNonce( - "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc") - )) == SortedVec[SchnorrNonce, NetworkElement](Vector( - SchnorrNonce( - "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc"), - SchnorrNonce( - "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea") - ))) + SortedVec.sort[SchnorrNonce, NetworkElement]( + Vector( + SchnorrNonce( + "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea" + ), + SchnorrNonce( + "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc" + ) + ) + ) == SortedVec[SchnorrNonce, NetworkElement]( + Vector( + SchnorrNonce( + "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc" + ), + SchnorrNonce( + "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea" + ) + ) + ) + ) } it should "fail to construct with unsorted vector under normal orderings" in { @@ -42,14 +56,20 @@ class SortedVecTest extends BitcoinSUnitTest { assertThrows[IllegalArgumentException](SortedVec(Vector(3.0, 2.0, 1.123))) assertThrows[IllegalArgumentException](SortedVec(Vector('c', 'b', 'a'))) assertThrows[IllegalArgumentException]( - SortedVec(Vector("cab", "ceb", "abc"))) + SortedVec(Vector("cab", "ceb", "abc")) + ) assertThrows[IllegalArgumentException]( - SortedVec[SchnorrNonce, NetworkElement](Vector( - SchnorrNonce( - "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea"), - SchnorrNonce( - "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc") - ))) + SortedVec[SchnorrNonce, NetworkElement]( + Vector( + SchnorrNonce( + "c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea" + ), + SchnorrNonce( + "92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc" + ) + ) + ) + ) } it should "sort correctly on construction with custom orderings" in { @@ -68,7 +88,9 @@ class SortedVecTest extends BitcoinSUnitTest { assert( SortedVec.sort(Vector(0.95, 123.123, 5.55)) == SortedVec( - Vector(123.123, 5.55, 0.95))) + Vector(123.123, 5.55, 0.95) + ) + ) } it should "fail to construct with unsorted vector under custom orderings" in { @@ -85,7 +107,8 @@ class SortedVecTest extends BitcoinSUnitTest { } assertThrows[IllegalArgumentException]( - SortedVec(Vector(0.95, 5.55, 123.123))) + SortedVec(Vector(0.95, 5.55, 123.123)) + ) } it should "correctly handle ordered list" in { @@ -97,6 +120,7 @@ class SortedVecTest extends BitcoinSUnitTest { val _ = SortedVec(nonces)(SortedVec.forOrdered(nonces)) assertThrows[IllegalArgumentException]( - SortedVec(wrongOrder)(SortedVec.forOrdered(nonces))) + SortedVec(wrongOrder)(SortedVec.forOrdered(nonces)) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/util/testprotocol/Base58ValidTestCase.scala b/core-test/src/test/scala/org/bitcoins/core/util/testprotocol/Base58ValidTestCase.scala index 16e25e5906..2cbefc003a 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/testprotocol/Base58ValidTestCase.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/testprotocol/Base58ValidTestCase.scala @@ -9,7 +9,8 @@ import upickle.default._ case class Base58ValidTestCase( addressOrWIFPrivKey: Either[Address, String], hashOrPrivKey: Either[Sha256Hash160Digest, ECPrivateKey], - configParams: ConfigParams) + configParams: ConfigParams +) object Base58ValidTestCase { @@ -19,14 +20,16 @@ object Base58ValidTestCase { case array: Arr => array case _: Value => throw new RuntimeException( - "Core test case must be in the format of js array") + "Core test case must be in the format of js array" + ) } val elements: Vector[Value] = jsArray.value.toVector val configParams: ConfigParams = upickle.default.read[ConfigParams](elements(2)) def addressOrPrivateKey( - elements: Vector[Value]): Either[Address, String] = + elements: Vector[Value] + ): Either[Address, String] = if (configParams.isPrivKey) { Right(elements(0).str) } else { @@ -35,7 +38,8 @@ object Base58ValidTestCase { } def isHashOrPrivKey( - elements: Vector[Value]): Either[Sha256Hash160Digest, ECPrivateKey] = + elements: Vector[Value] + ): Either[Sha256Hash160Digest, ECPrivateKey] = configParams.addrTypeOrIsCompressed match { case a if a.isLeft => Left(Sha256Hash160Digest(elements(1).str)) @@ -44,8 +48,10 @@ object Base58ValidTestCase { case _ => sys.error(s"Should be left or right") } - Base58ValidTestCase(addressOrPrivateKey(elements), - isHashOrPrivKey(elements), - configParams) + Base58ValidTestCase( + addressOrPrivateKey(elements), + isHashOrPrivKey(elements), + configParams + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/util/testprotocol/ConfigParams.scala b/core-test/src/test/scala/org/bitcoins/core/util/testprotocol/ConfigParams.scala index c567cb0bed..bb74c530af 100644 --- a/core-test/src/test/scala/org/bitcoins/core/util/testprotocol/ConfigParams.scala +++ b/core-test/src/test/scala/org/bitcoins/core/util/testprotocol/ConfigParams.scala @@ -6,7 +6,8 @@ import upickle.default._ case class ConfigParams( addrTypeOrIsCompressed: Either[String, Boolean], isPrivKey: Boolean, - isTestNet: Boolean) + isTestNet: Boolean +) object ConfigParams { val addrTypeKey = "addrType" diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/CoinSelectorTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/CoinSelectorTest.scala index 6b62dc4245..50747f0ed4 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/CoinSelectorTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/CoinSelectorTest.scala @@ -34,7 +34,8 @@ class CoinSelectorTest extends BitcoinSUnitTest { // difference of fee rate between feeRate and longTermFeeRate val feeRateDiff = SatoshisPerVirtualByte.fromLong( - feeRate.toLong - longTermFeeRate.toLong) + feeRate.toLong - longTermFeeRate.toLong + ) // difference fees it costs to spend our utxos between feeRate and longTermFeeRate val utxoFeeDiffs = @@ -45,55 +46,62 @@ class CoinSelectorTest extends BitcoinSUnitTest { // Waste with change is the change cost and difference between fee and long term fee val waste1 = - CoinSelector.calculateSelectionWaste(utxos = utxos, - changeCostOpt = Some(changeCost), - target = target, - feeRate = feeRate, - longTermFeeRate = - longTermFeeRate) + CoinSelector.calculateSelectionWaste( + utxos = utxos, + changeCostOpt = Some(changeCost), + target = target, + feeRate = feeRate, + longTermFeeRate = longTermFeeRate + ) assert(waste1 == utxoFeeDiffs + changeCost) // Waste without change is the excess and difference between fee and long term fee val waste2 = - CoinSelector.calculateSelectionWaste(utxos = utxos, - changeCostOpt = None, - target = target, - feeRate = feeRate, - longTermFeeRate = - longTermFeeRate) + CoinSelector.calculateSelectionWaste( + utxos = utxos, + changeCostOpt = None, + target = target, + feeRate = feeRate, + longTermFeeRate = longTermFeeRate + ) assert(waste2 == utxoFeeDiffs + excess) // Waste with change and fee == long term fee is just cost of change val waste3 = - CoinSelector.calculateSelectionWaste(utxos = utxos, - changeCostOpt = Some(changeCost), - target = target, - feeRate = feeRate, - longTermFeeRate = feeRate) + CoinSelector.calculateSelectionWaste( + utxos = utxos, + changeCostOpt = Some(changeCost), + target = target, + feeRate = feeRate, + longTermFeeRate = feeRate + ) assert(waste3 == changeCost) // Waste without change and fee == long term fee is just the excess val waste4 = - CoinSelector.calculateSelectionWaste(utxos = utxos, - changeCostOpt = None, - target = target, - feeRate = feeRate, - longTermFeeRate = feeRate) + CoinSelector.calculateSelectionWaste( + utxos = utxos, + changeCostOpt = None, + target = target, + feeRate = feeRate, + longTermFeeRate = feeRate + ) assert(waste4 == excess) // Waste will be greater when fee is greater, but long term fee is the same val biggerFeeRate = SatoshisPerVirtualByte(feeRate.currencyUnit * 2) val waste5 = - CoinSelector.calculateSelectionWaste(utxos = utxos, - changeCostOpt = Some(changeCost), - target = target, - feeRate = biggerFeeRate, - longTermFeeRate = - longTermFeeRate) + CoinSelector.calculateSelectionWaste( + utxos = utxos, + changeCostOpt = Some(changeCost), + target = target, + feeRate = biggerFeeRate, + longTermFeeRate = longTermFeeRate + ) // waste 1 is the same params but feeRate assert(waste5 > waste1) @@ -101,11 +109,13 @@ class CoinSelectorTest extends BitcoinSUnitTest { // Waste with change is the change cost and difference between fee and long term fee // With long term fee greater than fee, waste should be less than when long term fee is less than fee val waste6 = - CoinSelector.calculateSelectionWaste(utxos = utxos, - changeCostOpt = Some(changeCost), - target = target, - feeRate = longTermFeeRate, - longTermFeeRate = feeRate) + CoinSelector.calculateSelectionWaste( + utxos = utxos, + changeCostOpt = Some(changeCost), + target = target, + feeRate = longTermFeeRate, + longTermFeeRate = feeRate + ) assert(waste6 == -utxoFeeDiffs + changeCost) // waste 1 is the same params but feeRate and longTermFeeRate swapped @@ -113,27 +123,32 @@ class CoinSelectorTest extends BitcoinSUnitTest { // 0 Waste only when fee == long term fee, no change, and no excess val waste7 = - CoinSelector.calculateSelectionWaste(utxos = utxos, - changeCostOpt = None, - target = inAmt - utxosFee, - feeRate = feeRate, - longTermFeeRate = feeRate) + CoinSelector.calculateSelectionWaste( + utxos = utxos, + changeCostOpt = None, + target = inAmt - utxosFee, + feeRate = feeRate, + longTermFeeRate = feeRate + ) assert(waste7 == CurrencyUnits.zero) } } def createSpendingInfoDbs( - amounts: Vector[CurrencyUnit]): Vector[SpendingInfoDb] = { + amounts: Vector[CurrencyUnit] + ): Vector[SpendingInfoDb] = { val result = amounts.map { amt => val key = ECPublicKey.freshPublicKey val spk = P2WPKHWitnessSPKV0(key) val output = TransactionOutput(amt, spk) val scriptWitness = P2WPKHWitnessV0(key) - val path = SegWitHDPath(HDCoinType.Testnet, - accountIndex = 0, - HDChainType.External, - addressIndex = 0) + val path = SegWitHDPath( + HDCoinType.Testnet, + accountIndex = 0, + HDChainType.External, + addressIndex = 0 + ) SegwitV0SpendingInfo( outPoint = EmptyTransactionOutPoint, @@ -147,19 +162,20 @@ class CoinSelectorTest extends BitcoinSUnitTest { result } - /** The test assumes feeRate is greater than longTermFeeRate - * After generating fee rates this will order them correctly - * so the tests will pass + /** The test assumes feeRate is greater than longTermFeeRate After generating + * fee rates this will order them correctly so the tests will pass * - * @param feeRateA first fee rate generated - * @param feeRateB second fee rate generated - * @return (feeRate, longTermFeeRate) + * @param feeRateA + * first fee rate generated + * @param feeRateB + * second fee rate generated + * @return + * (feeRate, longTermFeeRate) */ def correctFeeRates( feeRateA: SatoshisPerVirtualByte, - feeRateB: SatoshisPerVirtualByte): ( - SatoshisPerVirtualByte, - SatoshisPerVirtualByte) = { + feeRateB: SatoshisPerVirtualByte + ): (SatoshisPerVirtualByte, SatoshisPerVirtualByte) = { if (feeRateA.toLong > feeRateB.toLong) { (feeRateA, feeRateB) } else if (feeRateA.toLong < feeRateB.toLong) { diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxFinalizerTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxFinalizerTest.scala index c0dfe682eb..e5cee53085 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxFinalizerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxFinalizerTest.scala @@ -23,82 +23,118 @@ class RawTxFinalizerTest extends BitcoinSUnitTest { val outpoints = Vector( TransactionOutPoint( DoubleSha256DigestBE( - "0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57"), - UInt32.zero), + "0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "26aa6e6d8b9e49bb0630aac301db6757c02e3619feb4ee0eea81eb1672947024"), - UInt32.one), + "26aa6e6d8b9e49bb0630aac301db6757c02e3619feb4ee0eea81eb1672947024" + ), + UInt32.one + ), TransactionOutPoint( DoubleSha256DigestBE( - "28e0fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2"), - UInt32.zero), + "28e0fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "381de9b9ae1a94d9c17f6a08ef9d341a5ce29e2e60c36a52d333ff6203e58d5d"), - UInt32.one), + "381de9b9ae1a94d9c17f6a08ef9d341a5ce29e2e60c36a52d333ff6203e58d5d" + ), + UInt32.one + ), TransactionOutPoint( DoubleSha256DigestBE( - "3b8b2f8efceb60ba78ca8bba206a137f14cb5ea4035e761ee204302d46b98de2"), - UInt32.zero), + "3b8b2f8efceb60ba78ca8bba206a137f14cb5ea4035e761ee204302d46b98de2" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "402b2c02411720bf409eff60d05adad684f135838962823f3614cc657dd7bc0a"), - UInt32.one), + "402b2c02411720bf409eff60d05adad684f135838962823f3614cc657dd7bc0a" + ), + UInt32.one + ), TransactionOutPoint( DoubleSha256DigestBE( - "54ffff182965ed0957dba1239c27164ace5a73c9b62a660c74b7b7f15ff61e7a"), - UInt32.one), + "54ffff182965ed0957dba1239c27164ace5a73c9b62a660c74b7b7f15ff61e7a" + ), + UInt32.one + ), TransactionOutPoint( DoubleSha256DigestBE( - "643e5f4e66373a57251fb173151e838ccd27d279aca882997e005016bb53d5aa"), - UInt32.zero), + "643e5f4e66373a57251fb173151e838ccd27d279aca882997e005016bb53d5aa" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "6c1d56f31b2de4bfc6aaea28396b333102b1f600da9c6d6149e96ca43f1102b1"), - UInt32.one), + "6c1d56f31b2de4bfc6aaea28396b333102b1f600da9c6d6149e96ca43f1102b1" + ), + UInt32.one + ), TransactionOutPoint( DoubleSha256DigestBE( - "7a1de137cbafb5c70405455c49c5104ca3057a1f1243e6563bb9245c9c88c191"), - UInt32.zero), + "7a1de137cbafb5c70405455c49c5104ca3057a1f1243e6563bb9245c9c88c191" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "7d037ceb2ee0dc03e82f17be7935d238b35d1deabf953a892a4507bfbeeb3ba4"), - UInt32.one), + "7d037ceb2ee0dc03e82f17be7935d238b35d1deabf953a892a4507bfbeeb3ba4" + ), + UInt32.one + ), TransactionOutPoint( DoubleSha256DigestBE( - "a5e899dddb28776ea9ddac0a502316d53a4a3fca607c72f66c470e0412e34086"), - UInt32.zero), + "a5e899dddb28776ea9ddac0a502316d53a4a3fca607c72f66c470e0412e34086" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "b4112b8f900a7ca0c8b0e7c4dfad35c6be5f6be46b3458974988e1cdb2fa61b8"), - UInt32.zero), + "b4112b8f900a7ca0c8b0e7c4dfad35c6be5f6be46b3458974988e1cdb2fa61b8" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "bafd65e3c7f3f9fdfdc1ddb026131b278c3be1af90a4a6ffa78c4658f9ec0c85"), - UInt32.zero), + "bafd65e3c7f3f9fdfdc1ddb026131b278c3be1af90a4a6ffa78c4658f9ec0c85" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "de0411a1e97484a2804ff1dbde260ac19de841bebad1880c782941aca883b4e9"), - UInt32.one), + "de0411a1e97484a2804ff1dbde260ac19de841bebad1880c782941aca883b4e9" + ), + UInt32.one + ), TransactionOutPoint( DoubleSha256DigestBE( - "f0a130a84912d03c1d284974f563c5949ac13f8342b8112edff52971599e6a45"), - UInt32.zero), + "f0a130a84912d03c1d284974f563c5949ac13f8342b8112edff52971599e6a45" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "f320832a9d2e2452af63154bc687493484a0e7745ebd3aaf9ca19eb80834ad60"), - UInt32.zero) + "f320832a9d2e2452af63154bc687493484a0e7745ebd3aaf9ca19eb80834ad60" + ), + UInt32.zero + ) ) val sortedInputs = outpoints.map(TransactionInput(_, EmptyScriptSignature, UInt32.zero)) val sortedOutputs: Vector[TransactionOutput] = Vector( TransactionOutput( Satoshis(400057456), - ScriptPubKey("76a9144a5fba237213a062f6f57978f796390bdcf8d01588ac")), + ScriptPubKey("76a9144a5fba237213a062f6f57978f796390bdcf8d01588ac") + ), TransactionOutput( Satoshis(40000000000L), - ScriptPubKey("76a9145be32612930b8323add2212a4ec03c1562084f8488ac")) + ScriptPubKey("76a9145be32612930b8323add2212a4ec03c1562084f8488ac") + ) ) testBIP69Finalizer(sortedInputs, sortedOutputs) @@ -109,12 +145,16 @@ class RawTxFinalizerTest extends BitcoinSUnitTest { val outpoints = Vector( TransactionOutPoint( DoubleSha256DigestBE( - "35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055"), - UInt32.zero), + "35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055" + ), + UInt32.zero + ), TransactionOutPoint( DoubleSha256DigestBE( - "35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055"), - UInt32.one) + "35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055" + ), + UInt32.one + ) ) val sortedInputs = outpoints.map(TransactionInput(_, EmptyScriptSignature, UInt32.zero)) @@ -122,12 +162,14 @@ class RawTxFinalizerTest extends BitcoinSUnitTest { TransactionOutput( Satoshis(100000000), ScriptPubKey( - "41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac") + "41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac" + ) ), TransactionOutput( Satoshis(2400000000L), ScriptPubKey( - "41044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac") + "41044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac" + ) ) ) @@ -145,7 +187,9 @@ class RawTxFinalizerTest extends BitcoinSUnitTest { assert( inputs.size <= 1 || txs.exists( - _.inputs.map(_.previousOutput) != inputs.map(_.outPoint))) + _.inputs.map(_.previousOutput) != inputs.map(_.outPoint) + ) + ) } } @@ -173,14 +217,17 @@ class RawTxFinalizerTest extends BitcoinSUnitTest { assert( inputs.size <= 1 || txs.exists( - _.inputs.map(_.previousOutput) != inputs.map(_.outPoint))) + _.inputs.map(_.previousOutput) != inputs.map(_.outPoint) + ) + ) assert(outputs.size <= 1 || txs.exists(_.outputs != outputs)) } } def testBIP69Finalizer( sortedInputs: Vector[TransactionInput], - sortedOutputs: Vector[TransactionOutput]): Assertion = { + sortedOutputs: Vector[TransactionOutput] + ): Assertion = { val inputs = Random.shuffle(sortedInputs) val outputs = Random.shuffle(sortedOutputs) diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxSignerTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxSignerTest.scala index 5ae15b55dc..816fd07db1 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxSignerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/RawTxSignerTest.scala @@ -37,10 +37,12 @@ class RawTxSignerTest extends BitcoinSUnitTest { val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk) val destinations = Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) - val creditingTx = BaseTransaction(TransactionConstants.validLockVersion, - Nil, - Vector(creditingOutput), - TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + TransactionConstants.validLockVersion, + Nil, + Vector(creditingOutput), + TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) val utxo = ScriptSignatureParams( @@ -58,11 +60,13 @@ class RawTxSignerTest extends BitcoinSUnitTest { ) val utxos = Vector(utxo) val feeUnit = SatoshisPerVirtualByte(currencyUnit = Satoshis(1)) - val utx = RawFinalizerFactory.txFrom(outputs = destinations, - utxos = utxos, - feeRate = feeUnit, - changeSPK = EmptyScriptPubKey) - //trivially false + val utx = RawFinalizerFactory.txFrom( + outputs = destinations, + utxos = utxos, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey + ) + // trivially false val f = (_: Seq[ScriptSignatureParams[InputInfo]], _: Transaction) => false assertThrows[IllegalArgumentException] { @@ -75,10 +79,12 @@ class RawTxSignerTest extends BitcoinSUnitTest { val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2pkh) val destinations = Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) - val creditingTx = BaseTransaction(TransactionConstants.validLockVersion, - Nil, - Vector(creditingOutput), - TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + TransactionConstants.validLockVersion, + Nil, + Vector(creditingOutput), + TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) val utxo = ScriptSignatureParams( InputInfo( @@ -96,10 +102,12 @@ class RawTxSignerTest extends BitcoinSUnitTest { val utxos = Vector(utxo) val feeUnit = SatoshisPerVirtualByte(Satoshis.one) - val utx = RawFinalizerFactory.txFrom(outputs = destinations, - utxos = utxos, - feeRate = feeUnit, - changeSPK = EmptyScriptPubKey) + val utx = RawFinalizerFactory.txFrom( + outputs = destinations, + utxos = utxos, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey + ) assertThrows[IllegalArgumentException] { RawTxSigner.sign(utx, utxos, feeUnit) @@ -111,11 +119,12 @@ class RawTxSignerTest extends BitcoinSUnitTest { val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2pkh) val destinations = Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) - val creditingTx = BaseTransaction(version = - TransactionConstants.validLockVersion, - inputs = Nil, - outputs = Vector(creditingOutput), - lockTime = TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + version = TransactionConstants.validLockVersion, + inputs = Nil, + outputs = Vector(creditingOutput), + lockTime = TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(txId = creditingTx.txId, vout = UInt32.zero) val utxo = ScriptSignatureParams( @@ -134,10 +143,12 @@ class RawTxSignerTest extends BitcoinSUnitTest { val utxos = Vector(utxo) val feeUnit = SatoshisPerVirtualByte(Satoshis.one) - val utx = RawFinalizerFactory.txFrom(outputs = destinations, - utxos = utxos, - feeRate = feeUnit, - changeSPK = EmptyScriptPubKey) + val utx = RawFinalizerFactory.txFrom( + outputs = destinations, + utxos = utxos, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey + ) assertThrows[IllegalArgumentException] { RawTxSigner.sign(utx, utxos, feeUnit) @@ -150,8 +161,10 @@ class RawTxSignerTest extends BitcoinSUnitTest { val lockTime = System.currentTimeMillis / 1000 val cltvSPK = - CLTVScriptPubKey(ScriptNumber(lockTime), - P2PKScriptPubKey(fundingPrivKey.publicKey)) + CLTVScriptPubKey( + ScriptNumber(lockTime), + P2PKScriptPubKey(fundingPrivKey.publicKey) + ) val creditingTx = BaseTransaction( version = TransactionConstants.validLockVersion, @@ -161,10 +174,12 @@ class RawTxSignerTest extends BitcoinSUnitTest { ) val cltvSpendingInfo = ScriptSignatureParams( - LockTimeInputInfo(TransactionOutPoint(creditingTx.txId, UInt32.zero), - Bitcoins.one, - cltvSPK, - ConditionalPath.NoCondition), + LockTimeInputInfo( + TransactionOutPoint(creditingTx.txId, UInt32.zero), + Bitcoins.one, + cltvSPK, + ConditionalPath.NoCondition + ), prevTransaction = creditingTx, signers = Vector(fundingPrivKey), hashType = HashType.sigHashAll @@ -176,8 +191,11 @@ class RawTxSignerTest extends BitcoinSUnitTest { val utx = StandardNonInteractiveFinalizer.txFrom( outputs = Vector( - TransactionOutput(Bitcoins.one - CurrencyUnits.oneMBTC, - EmptyScriptPubKey)), + TransactionOutput( + Bitcoins.one - CurrencyUnits.oneMBTC, + EmptyScriptPubKey + ) + ), utxos = utxos, feeRate = feeUnit, changeSPK = EmptyScriptPubKey @@ -194,8 +212,10 @@ class RawTxSignerTest extends BitcoinSUnitTest { val lockTime = 1000 val cltvSPK = - CLTVScriptPubKey(ScriptNumber(lockTime), - P2PKScriptPubKey(fundingPrivKey.publicKey)) + CLTVScriptPubKey( + ScriptNumber(lockTime), + P2PKScriptPubKey(fundingPrivKey.publicKey) + ) val creditingTx = BaseTransaction( version = TransactionConstants.validLockVersion, @@ -205,10 +225,12 @@ class RawTxSignerTest extends BitcoinSUnitTest { ) val cltvSpendingInfo = ScriptSignatureParams( - LockTimeInputInfo(TransactionOutPoint(creditingTx.txId, UInt32.zero), - Bitcoins.one, - cltvSPK, - ConditionalPath.NoCondition), + LockTimeInputInfo( + TransactionOutPoint(creditingTx.txId, UInt32.zero), + Bitcoins.one, + cltvSPK, + ConditionalPath.NoCondition + ), prevTransaction = creditingTx, signers = Vector(fundingPrivKey), hashType = HashType.sigHashAll @@ -220,8 +242,11 @@ class RawTxSignerTest extends BitcoinSUnitTest { val utx = StandardNonInteractiveFinalizer.txFrom( outputs = Vector( - TransactionOutput(Bitcoins.one - CurrencyUnits.oneMBTC, - EmptyScriptPubKey)), + TransactionOutput( + Bitcoins.one - CurrencyUnits.oneMBTC, + EmptyScriptPubKey + ) + ), utxos = utxos, feeRate = feeUnit, changeSPK = EmptyScriptPubKey @@ -240,29 +265,35 @@ class RawTxSignerTest extends BitcoinSUnitTest { val lockTime2 = 1000 val cltvSPK1 = - CLTVScriptPubKey(ScriptNumber(lockTime1), - P2PKScriptPubKey(fundingPrivKey1.publicKey)) + CLTVScriptPubKey( + ScriptNumber(lockTime1), + P2PKScriptPubKey(fundingPrivKey1.publicKey) + ) val cltvSPK2 = - CLTVScriptPubKey(ScriptNumber(lockTime2), - P2PKScriptPubKey(fundingPrivKey2.publicKey)) + CLTVScriptPubKey( + ScriptNumber(lockTime2), + P2PKScriptPubKey(fundingPrivKey2.publicKey) + ) val cltvSpendingInfo1 = ScriptSignatureParams( - LockTimeInputInfo(TransactionOutPoint(DoubleSha256DigestBE.empty, - UInt32.zero), - Bitcoins.one, - cltvSPK1, - ConditionalPath.NoCondition), + LockTimeInputInfo( + TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.zero), + Bitcoins.one, + cltvSPK1, + ConditionalPath.NoCondition + ), prevTransaction = EmptyTransaction, signers = Vector(fundingPrivKey1), hashType = HashType.sigHashAll ) val cltvSpendingInfo2 = ScriptSignatureParams( - LockTimeInputInfo(TransactionOutPoint(DoubleSha256DigestBE.empty, - UInt32.one), - Bitcoins.one, - cltvSPK2, - ConditionalPath.NoCondition), + LockTimeInputInfo( + TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.one), + Bitcoins.one, + cltvSPK2, + ConditionalPath.NoCondition + ), prevTransaction = EmptyTransaction, signers = Vector(fundingPrivKey2), hashType = HashType.sigHashAll @@ -273,8 +304,11 @@ class RawTxSignerTest extends BitcoinSUnitTest { val utx = RawFinalizerFactory.txFrom( Vector( - TransactionOutput(Bitcoins.one + Bitcoins.one - CurrencyUnits.oneMBTC, - EmptyScriptPubKey)), + TransactionOutput( + Bitcoins.one + Bitcoins.one - CurrencyUnits.oneMBTC, + EmptyScriptPubKey + ) + ), utxos, UInt32.zero, feeRate, @@ -291,10 +325,12 @@ class RawTxSignerTest extends BitcoinSUnitTest { case ((creditingTxsInfo, destinations), (changeSPK, _)) => val fee = SatoshisPerVirtualByte(Satoshis(1000)) val utx = - StandardNonInteractiveFinalizer.txFrom(outputs = destinations, - utxos = creditingTxsInfo, - feeRate = fee, - changeSPK = changeSPK) + StandardNonInteractiveFinalizer.txFrom( + outputs = destinations, + utxos = creditingTxsInfo, + feeRate = fee, + changeSPK = changeSPK + ) val tx = RawTxSigner.sign(utx, creditingTxsInfo.toVector, fee) assert(BitcoinScriptUtil.verifyScript(tx, creditingTxsInfo.toVector)) @@ -311,20 +347,26 @@ class RawTxSignerTest extends BitcoinSUnitTest { val mockSigners = inputInfo.pubKeys.take(inputInfo.requiredSigs).map(Sign.dummySign) - inputInfo.toSpendingInfo(EmptyTransaction, - mockSigners, - HashType.sigHashAll) + inputInfo.toSpendingInfo( + EmptyTransaction, + mockSigners, + HashType.sigHashAll + ) } val utx = - StandardNonInteractiveFinalizer.txFrom(outputs = destinations, - utxos = dummySpendingInfos, - feeRate = fee, - changeSPK = changeSPK) - val tx = RawTxSigner.sign(utx, - dummySpendingInfos.toVector, - RawTxSigner.emptyInvariant, - dummySign = true) + StandardNonInteractiveFinalizer.txFrom( + outputs = destinations, + utxos = dummySpendingInfos, + feeRate = fee, + changeSPK = changeSPK + ) + val tx = RawTxSigner.sign( + utx, + dummySpendingInfos.toVector, + RawTxSigner.emptyInvariant, + dummySign = true + ) // Can't use BitcoinScriptUtil.verifyScript because it will pass for things // with EmptyScriptPubKeys or Multisig with 0 required sigs @@ -333,8 +375,12 @@ class RawTxSignerTest extends BitcoinSUnitTest { succeed case btx: BaseTransaction => assert( - btx.inputs.forall(_.scriptSignature.signatures.forall( - _ == LowRDummyECDigitalSignature))) + btx.inputs.forall( + _.scriptSignature.signatures.forall( + _ == LowRDummyECDigitalSignature + ) + ) + ) case wtx: WitnessTransaction => assert( wtx.witness.witnesses.forall { @@ -347,7 +393,8 @@ class RawTxSignerTest extends BitcoinSUnitTest { case taprootWitness: TaprootWitness => throw new UnsupportedOperationException( - s"Taproot not supported, got=$taprootWitness") + s"Taproot not supported, got=$taprootWitness" + ) } ) } @@ -355,18 +402,21 @@ class RawTxSignerTest extends BitcoinSUnitTest { } it should "sign a mix of p2sh/p2wsh in a tx and then have it verified" in { - forAll(CreditingTxGen.inputsAndOutputs(CreditingTxGen.nestedOutputs), - ScriptGenerators.scriptPubKey) { - case ((creditingTxsInfo, destinations), (changeSPK, _)) => - val fee = SatoshisPerByte(Satoshis(1000)) - val utx = - StandardNonInteractiveFinalizer.txFrom(outputs = destinations, - utxos = creditingTxsInfo, - feeRate = fee, - changeSPK = changeSPK) - val tx = RawTxSigner.sign(utx, creditingTxsInfo.toVector, fee) + forAll( + CreditingTxGen.inputsAndOutputs(CreditingTxGen.nestedOutputs), + ScriptGenerators.scriptPubKey + ) { case ((creditingTxsInfo, destinations), (changeSPK, _)) => + val fee = SatoshisPerByte(Satoshis(1000)) + val utx = + StandardNonInteractiveFinalizer.txFrom( + outputs = destinations, + utxos = creditingTxsInfo, + feeRate = fee, + changeSPK = changeSPK + ) + val tx = RawTxSigner.sign(utx, creditingTxsInfo.toVector, fee) - assert(BitcoinScriptUtil.verifyScript(tx, creditingTxsInfo.toVector)) + assert(BitcoinScriptUtil.verifyScript(tx, creditingTxsInfo.toVector)) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/ShufflingNonInteractiveFinalizerTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/ShufflingNonInteractiveFinalizerTest.scala index 69341d822d..5c182b612c 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/ShufflingNonInteractiveFinalizerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/ShufflingNonInteractiveFinalizerTest.scala @@ -37,44 +37,58 @@ class ShufflingNonInteractiveFinalizerTest extends BitcoinSUnitTest { TransactionInput(outPoint, EmptyScriptSignature, UInt32.zero) private val output = TransactionOutput(Bitcoins.one, EmptyScriptPubKey) - private val tx = BaseTransaction(TransactionConstants.validLockVersion, - Vector(input), - Vector(output), - UInt32.zero) + private val tx = BaseTransaction( + TransactionConstants.validLockVersion, + Vector(input), + Vector(output), + UInt32.zero + ) private val changeSPK = P2PKHScriptPubKey(ECPublicKey.freshPublicKey) it should "detect a missing destination" in { - val missingOutputTx = BaseTransaction(tx.version, - tx.inputs, - Vector.empty[TransactionOutput], - tx.lockTime) + val missingOutputTx = BaseTransaction( + tx.version, + tx.inputs, + Vector.empty[TransactionOutput], + tx.lockTime + ) assert( SanityCheckFinalizer - .sanityDestinationChecks(Vector(outPoint), - Vector(EmptyScriptPubKey), - Vector(changeSPK), - missingOutputTx) - .isFailure) + .sanityDestinationChecks( + Vector(outPoint), + Vector(EmptyScriptPubKey), + Vector(changeSPK), + missingOutputTx + ) + .isFailure + ) } it should "detect extra outputs added" in { val newOutput = - TransactionOutput(Bitcoins.one, - P2PKHScriptPubKey(ECPublicKey.freshPublicKey)) - val extraOutputTx = BaseTransaction(tx.version, - tx.inputs, - Vector(output, newOutput), - tx.lockTime) + TransactionOutput( + Bitcoins.one, + P2PKHScriptPubKey(ECPublicKey.freshPublicKey) + ) + val extraOutputTx = BaseTransaction( + tx.version, + tx.inputs, + Vector(output, newOutput), + tx.lockTime + ) assert( SanityCheckFinalizer - .sanityDestinationChecks(Vector(outPoint), - Vector(EmptyScriptPubKey), - Vector(changeSPK), - extraOutputTx) - .isFailure) + .sanityDestinationChecks( + Vector(outPoint), + Vector(EmptyScriptPubKey), + Vector(changeSPK), + extraOutputTx + ) + .isFailure + ) } it should "detect extra outpoints added" in { @@ -82,18 +96,23 @@ class ShufflingNonInteractiveFinalizerTest extends BitcoinSUnitTest { TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.one) val newInput = TransactionInput(newOutPoint, EmptyScriptSignature, UInt32.zero) - val extraOutPointTx = BaseTransaction(tx.version, - Vector(input, newInput), - tx.outputs, - tx.lockTime) + val extraOutPointTx = BaseTransaction( + tx.version, + Vector(input, newInput), + tx.outputs, + tx.lockTime + ) assert( SanityCheckFinalizer - .sanityDestinationChecks(Vector(outPoint), - Vector(EmptyScriptPubKey), - Vector(changeSPK), - extraOutPointTx) - .isFailure) + .sanityDestinationChecks( + Vector(outPoint), + Vector(EmptyScriptPubKey), + Vector(changeSPK), + extraOutPointTx + ) + .isFailure + ) } it should "failed to build a transaction that mints money out of thin air" in { @@ -101,11 +120,12 @@ class ShufflingNonInteractiveFinalizerTest extends BitcoinSUnitTest { val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk) val destinations = Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) - val creditingTx = BaseTransaction(version = - TransactionConstants.validLockVersion, - inputs = Nil, - outputs = Vector(creditingOutput), - lockTime = TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + version = TransactionConstants.validLockVersion, + inputs = Nil, + outputs = Vector(creditingOutput), + lockTime = TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) val utxo = ScriptSignatureParams( InputInfo( @@ -124,10 +144,12 @@ class ShufflingNonInteractiveFinalizerTest extends BitcoinSUnitTest { val feeUnit = SatoshisPerVirtualByte(Satoshis.one) assertThrows[IllegalArgumentException] { - ShufflingNonInteractiveFinalizer.txFrom(outputs = destinations, - utxos = utxos, - feeRate = feeUnit, - changeSPK = EmptyScriptPubKey) + ShufflingNonInteractiveFinalizer.txFrom( + outputs = destinations, + utxos = utxos, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey + ) } } @@ -135,11 +157,12 @@ class ShufflingNonInteractiveFinalizerTest extends BitcoinSUnitTest { val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk) val destinations = Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) - val creditingTx = BaseTransaction(version = - TransactionConstants.validLockVersion, - inputs = Nil, - outputs = Vector(creditingOutput), - lockTime = TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + version = TransactionConstants.validLockVersion, + inputs = Nil, + outputs = Vector(creditingOutput), + lockTime = TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) val utxo = ScriptSignatureParams( InputInfo( @@ -158,10 +181,12 @@ class ShufflingNonInteractiveFinalizerTest extends BitcoinSUnitTest { val feeUnit = SatoshisPerVirtualByte(Satoshis(-1)) assertThrows[IllegalArgumentException] { - ShufflingNonInteractiveFinalizer.txFrom(outputs = destinations, - utxos = utxos, - feeRate = feeUnit, - changeSPK = EmptyScriptPubKey) + ShufflingNonInteractiveFinalizer.txFrom( + outputs = destinations, + utxos = utxos, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey + ) } } @@ -196,20 +221,23 @@ class ShufflingNonInteractiveFinalizerTest extends BitcoinSUnitTest { } it must "create a shuffled transaction with a ShufflingNonInteractiveFinalizer" in { - forAll(CreditingTxGen.inputsAndOutputs(), - FeeUnitGen.feeUnit(100), - ScriptGenerators.scriptPubKey) { - case ((inputs, outputs), feeRate, (changeSpk, _)) => - val txs = - 0.to(20).foldLeft(Vector.empty[Transaction]) { (accum, _) => - ShufflingNonInteractiveFinalizer - .txFrom(outputs, inputs, feeRate, changeSpk) +: accum - } + forAll( + CreditingTxGen.inputsAndOutputs(), + FeeUnitGen.feeUnit(100), + ScriptGenerators.scriptPubKey + ) { case ((inputs, outputs), feeRate, (changeSpk, _)) => + val txs = + 0.to(20).foldLeft(Vector.empty[Transaction]) { (accum, _) => + ShufflingNonInteractiveFinalizer + .txFrom(outputs, inputs, feeRate, changeSpk) +: accum + } - assert( - inputs.size <= 1 || txs.exists( - _.inputs.map(_.previousOutput) != inputs.map(_.outPoint))) - assert(outputs.size <= 1 || txs.exists(_.outputs != outputs)) + assert( + inputs.size <= 1 || txs.exists( + _.inputs.map(_.previousOutput) != inputs.map(_.outPoint) + ) + ) + assert(outputs.size <= 1 || txs.exists(_.outputs != outputs)) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/StandardNonInteractiveFinalizerTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/StandardNonInteractiveFinalizerTest.scala index 7dbe8bac9d..b629348962 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/builder/StandardNonInteractiveFinalizerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/builder/StandardNonInteractiveFinalizerTest.scala @@ -33,44 +33,58 @@ class StandardNonInteractiveFinalizerTest extends BitcoinSUnitTest { TransactionInput(outPoint, EmptyScriptSignature, UInt32.zero) private val output = TransactionOutput(Bitcoins.one, EmptyScriptPubKey) - private val tx = BaseTransaction(TransactionConstants.validLockVersion, - Vector(input), - Vector(output), - UInt32.zero) + private val tx = BaseTransaction( + TransactionConstants.validLockVersion, + Vector(input), + Vector(output), + UInt32.zero + ) private val changeSPK = P2PKHScriptPubKey(ECPublicKey.freshPublicKey) it should "detect a missing destination" in { - val missingOutputTx = BaseTransaction(tx.version, - tx.inputs, - Vector.empty[TransactionOutput], - tx.lockTime) + val missingOutputTx = BaseTransaction( + tx.version, + tx.inputs, + Vector.empty[TransactionOutput], + tx.lockTime + ) assert( SanityCheckFinalizer - .sanityDestinationChecks(Vector(outPoint), - Vector(EmptyScriptPubKey), - Vector(changeSPK), - missingOutputTx) - .isFailure) + .sanityDestinationChecks( + Vector(outPoint), + Vector(EmptyScriptPubKey), + Vector(changeSPK), + missingOutputTx + ) + .isFailure + ) } it should "detect extra outputs added" in { val newOutput = - TransactionOutput(Bitcoins.one, - P2PKHScriptPubKey(ECPublicKey.freshPublicKey)) - val extraOutputTx = BaseTransaction(tx.version, - tx.inputs, - Vector(output, newOutput), - tx.lockTime) + TransactionOutput( + Bitcoins.one, + P2PKHScriptPubKey(ECPublicKey.freshPublicKey) + ) + val extraOutputTx = BaseTransaction( + tx.version, + tx.inputs, + Vector(output, newOutput), + tx.lockTime + ) assert( SanityCheckFinalizer - .sanityDestinationChecks(Vector(outPoint), - Vector(EmptyScriptPubKey), - Vector(changeSPK), - extraOutputTx) - .isFailure) + .sanityDestinationChecks( + Vector(outPoint), + Vector(EmptyScriptPubKey), + Vector(changeSPK), + extraOutputTx + ) + .isFailure + ) } it should "detect extra outpoints added" in { @@ -78,18 +92,23 @@ class StandardNonInteractiveFinalizerTest extends BitcoinSUnitTest { TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.one) val newInput = TransactionInput(newOutPoint, EmptyScriptSignature, UInt32.zero) - val extraOutPointTx = BaseTransaction(tx.version, - Vector(input, newInput), - tx.outputs, - tx.lockTime) + val extraOutPointTx = BaseTransaction( + tx.version, + Vector(input, newInput), + tx.outputs, + tx.lockTime + ) assert( SanityCheckFinalizer - .sanityDestinationChecks(Vector(outPoint), - Vector(EmptyScriptPubKey), - Vector(changeSPK), - extraOutPointTx) - .isFailure) + .sanityDestinationChecks( + Vector(outPoint), + Vector(EmptyScriptPubKey), + Vector(changeSPK), + extraOutPointTx + ) + .isFailure + ) } it should "failed to build a transaction that mints money out of thin air" in { @@ -97,11 +116,12 @@ class StandardNonInteractiveFinalizerTest extends BitcoinSUnitTest { val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk) val destinations = Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) - val creditingTx = BaseTransaction(version = - TransactionConstants.validLockVersion, - inputs = Nil, - outputs = Vector(creditingOutput), - lockTime = TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + version = TransactionConstants.validLockVersion, + inputs = Nil, + outputs = Vector(creditingOutput), + lockTime = TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) val utxo = ScriptSignatureParams( InputInfo( @@ -120,10 +140,12 @@ class StandardNonInteractiveFinalizerTest extends BitcoinSUnitTest { val feeUnit = SatoshisPerVirtualByte(Satoshis.one) assertThrows[IllegalArgumentException] { - StandardNonInteractiveFinalizer.txFrom(outputs = destinations, - utxos = utxos, - feeRate = feeUnit, - changeSPK = EmptyScriptPubKey) + StandardNonInteractiveFinalizer.txFrom( + outputs = destinations, + utxos = utxos, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey + ) } } @@ -131,11 +153,12 @@ class StandardNonInteractiveFinalizerTest extends BitcoinSUnitTest { val creditingOutput = TransactionOutput(CurrencyUnits.zero, spk) val destinations = Vector(TransactionOutput(Satoshis.one, EmptyScriptPubKey)) - val creditingTx = BaseTransaction(version = - TransactionConstants.validLockVersion, - inputs = Nil, - outputs = Vector(creditingOutput), - lockTime = TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + version = TransactionConstants.validLockVersion, + inputs = Nil, + outputs = Vector(creditingOutput), + lockTime = TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) val utxo = ScriptSignatureParams( InputInfo( @@ -154,10 +177,12 @@ class StandardNonInteractiveFinalizerTest extends BitcoinSUnitTest { val feeUnit = SatoshisPerVirtualByte(Satoshis(-1)) assertThrows[IllegalArgumentException] { - StandardNonInteractiveFinalizer.txFrom(outputs = destinations, - utxos = utxos, - feeRate = feeUnit, - changeSPK = EmptyScriptPubKey) + StandardNonInteractiveFinalizer.txFrom( + outputs = destinations, + utxos = utxos, + feeRate = feeUnit, + changeSPK = EmptyScriptPubKey + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/fee/FeeUnitTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/fee/FeeUnitTest.scala index 0a42b7546f..b0388bf9f1 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/fee/FeeUnitTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/fee/FeeUnitTest.scala @@ -7,11 +7,13 @@ import org.bitcoins.testkitcore.util.BitcoinSUnitTest class FeeUnitTest extends BitcoinSUnitTest { val tx: Transaction = Transaction( - "02000000000101a2619b5d58b209439c937e563018efcf174063ca011e4f177a5b14e5ba76211c0100000017160014614e9b96cbc7477eda98f0936385ded6b636f74efeffffff024e3f57c4000000001600147cf00288c2c1b3c5cdf275db532a1c15c514bb2fae1112000000000016001440efb02597b9e9d9bc968f12cec3347e2e264c570247304402205768c2ac8178539fd44721e2a7541bedd6b55654f095143514624203c133f7e8022060d51f33fc2b5c1f51f26c7f703de21be6246dbb5fb7e1c6919aae6d442610c6012102b99a63f166ef53ca67a5c55ae969e80c33456e07189f8457e3438f000be42c19307d1900") + "02000000000101a2619b5d58b209439c937e563018efcf174063ca011e4f177a5b14e5ba76211c0100000017160014614e9b96cbc7477eda98f0936385ded6b636f74efeffffff024e3f57c4000000001600147cf00288c2c1b3c5cdf275db532a1c15c514bb2fae1112000000000016001440efb02597b9e9d9bc968f12cec3347e2e264c570247304402205768c2ac8178539fd44721e2a7541bedd6b55654f095143514624203c133f7e8022060d51f33fc2b5c1f51f26c7f703de21be6246dbb5fb7e1c6919aae6d442610c6012102b99a63f166ef53ca67a5c55ae969e80c33456e07189f8457e3438f000be42c19307d1900" + ) // testnet tx d34888da65ece048d41e0c74a59f225bbe7326e5f8c7437a4bf4df487822b3d3 val wtx: WitnessTransaction = WitnessTransaction( - "02000000000101a2619b5d58b209439c937e563018efcf174063ca011e4f177a5b14e5ba76211c0100000017160014614e9b96cbc7477eda98f0936385ded6b636f74efeffffff024e3f57c4000000001600147cf00288c2c1b3c5cdf275db532a1c15c514bb2fae1112000000000016001440efb02597b9e9d9bc968f12cec3347e2e264c570247304402205768c2ac8178539fd44721e2a7541bedd6b55654f095143514624203c133f7e8022060d51f33fc2b5c1f51f26c7f703de21be6246dbb5fb7e1c6919aae6d442610c6012102b99a63f166ef53ca67a5c55ae969e80c33456e07189f8457e3438f000be42c19307d1900") + "02000000000101a2619b5d58b209439c937e563018efcf174063ca011e4f177a5b14e5ba76211c0100000017160014614e9b96cbc7477eda98f0936385ded6b636f74efeffffff024e3f57c4000000001600147cf00288c2c1b3c5cdf275db532a1c15c514bb2fae1112000000000016001440efb02597b9e9d9bc968f12cec3347e2e264c570247304402205768c2ac8178539fd44721e2a7541bedd6b55654f095143514624203c133f7e8022060d51f33fc2b5c1f51f26c7f703de21be6246dbb5fb7e1c6919aae6d442610c6012102b99a63f166ef53ca67a5c55ae969e80c33456e07189f8457e3438f000be42c19307d1900" + ) it must "calculate the correct fee with a SatoshisPerByte fee rate" in { val feeRate = SatoshisPerByte(Satoshis(3)) @@ -38,7 +40,8 @@ class FeeUnitTest extends BitcoinSUnitTest { it must "have symmetry for SatoshisPerByte and SatoshisPerVirtualByte with BaseTransactions" in { val baseTx = BaseTransaction( - "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000") + "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000" + ) val satoshisPerByte = SatoshisPerByte(Satoshis(3)) val satoshisPerVByte = SatoshisPerVirtualByte(Satoshis(3)) @@ -88,7 +91,8 @@ class FeeUnitTest extends BitcoinSUnitTest { it must "calculate the same fee when using SatoshisPerVirtualByte.toSatoshisPerKW" in { val transaction = Transaction( - "0100000001d8bdc17a9baced096231edd3a2a5ee4ebdb236c4319314034ec012cd18acb004000000006a47304402205b9a9e3483a14143ce12be73ecb4f96011da8d3a15525c59fbbd519fa65e3e18022019d4453683075625c6310b6bd7aa1fdb0f8f49d20db808292e067c1a9de8986b012102fff6ec89268401a69f8f04541cd29d545a761d4a6ba258f52edbf0d0cccac030ffffffff0209f31600000000001976a914a61a24357d1c28f8a13e9167bfed7c4d9f3ac97d88ac6eb70500000000001976a91402b4d9a52a5dfc9b477522adf4952c972e10f79588ac00000000") + "0100000001d8bdc17a9baced096231edd3a2a5ee4ebdb236c4319314034ec012cd18acb004000000006a47304402205b9a9e3483a14143ce12be73ecb4f96011da8d3a15525c59fbbd519fa65e3e18022019d4453683075625c6310b6bd7aa1fdb0f8f49d20db808292e067c1a9de8986b012102fff6ec89268401a69f8f04541cd29d545a761d4a6ba258f52edbf0d0cccac030ffffffff0209f31600000000001976a914a61a24357d1c28f8a13e9167bfed7c4d9f3ac97d88ac6eb70500000000001976a91402b4d9a52a5dfc9b477522adf4952c972e10f79588ac00000000" + ) val satsPerVByte = SatoshisPerVirtualByte.fromLong(5) val satsPerKW = satsPerVByte.toSatoshisPerKW @@ -98,28 +102,35 @@ class FeeUnitTest extends BitcoinSUnitTest { it must "have matching scaleFactor between class and factory" in { assert( - SatoshisPerKiloByte.zero.scaleFactor == SatoshisPerKiloByte.scaleFactor) + SatoshisPerKiloByte.zero.scaleFactor == SatoshisPerKiloByte.scaleFactor + ) assert(SatoshisPerKW.zero.scaleFactor == SatoshisPerKW.scaleFactor) assert(SatoshisPerByte.zero.scaleFactor == SatoshisPerByte.scaleFactor) assert( - SatoshisPerVirtualByte.zero.scaleFactor == SatoshisPerVirtualByte.scaleFactor) + SatoshisPerVirtualByte.zero.scaleFactor == SatoshisPerVirtualByte.scaleFactor + ) } it must "have matching txSizeForCalc between class and factory" in { assert( SatoshisPerKiloByte.zero.txSizeForCalc(wtx) == SatoshisPerKiloByte - .txSizeForCalc(wtx)) + .txSizeForCalc(wtx) + ) assert( - SatoshisPerKW.zero.txSizeForCalc(wtx) == SatoshisPerKW.txSizeForCalc(wtx)) + SatoshisPerKW.zero.txSizeForCalc(wtx) == SatoshisPerKW.txSizeForCalc(wtx) + ) assert( SatoshisPerByte.zero.txSizeForCalc(wtx) == SatoshisPerByte.txSizeForCalc( - wtx)) + wtx + ) + ) assert( SatoshisPerVirtualByte.zero.txSizeForCalc(wtx) == SatoshisPerVirtualByte - .txSizeForCalc(wtx)) + .txSizeForCalc(wtx) + ) } it must "correctly calculate the fee rate for the tx in SatoshisPerVirtualByte" in { @@ -127,7 +138,8 @@ class FeeUnitTest extends BitcoinSUnitTest { assert( SatoshisPerVirtualByte.calc(inputAmount, wtx) == SatoshisPerVirtualByte - .fromLong(147)) + .fromLong(147) + ) } it must "correctly calculate the fee rate for the tx in SatoshisPerByte" in { @@ -135,7 +147,8 @@ class FeeUnitTest extends BitcoinSUnitTest { assert( SatoshisPerByte.calc(inputAmount, wtx) == SatoshisPerByte - .fromLong(98)) + .fromLong(98) + ) } it must "correctly calculate the fee rate for the tx in SatoshisPerKW" in { @@ -143,7 +156,8 @@ class FeeUnitTest extends BitcoinSUnitTest { assert( SatoshisPerKW.calc(inputAmount, wtx) == SatoshisPerKW - .fromLong(36954)) + .fromLong(36954) + ) } it must "correctly calculate the fee rate for the tx in SatoshisPerKiloByte" in { @@ -151,6 +165,7 @@ class FeeUnitTest extends BitcoinSUnitTest { assert( SatoshisPerKiloByte.calc(inputAmount, wtx) == SatoshisPerKiloByte - .fromLong(98494)) + .fromLong(98494) + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/signer/SignerTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/signer/SignerTest.scala index fe5f1b23c4..eb3a2494f3 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/signer/SignerTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/signer/SignerTest.scala @@ -57,14 +57,16 @@ class SignerTest extends BitcoinSUnitTest { p2wpkh.hashType ) assertThrows[UnsupportedOperationException]( - BitcoinSigner.sign(spendingInfo, tx, isDummySignature = false)) + BitcoinSigner.sign(spendingInfo, tx, isDummySignature = false) + ) } it should "fail to sign a P2SH UTXO" in { val p2sh = GenUtil.sample(CreditingTxGen.p2shOutput) val tx = GenUtil.sample(TransactionGenerators.baseTransaction) assertThrows[IllegalArgumentException]( - BitcoinSigner.sign(p2sh, tx, isDummySignature = false)) + BitcoinSigner.sign(p2sh, tx, isDummySignature = false) + ) } it should "fail if there are inconsistent P2WPKH spending infos" in { @@ -95,10 +97,12 @@ class SignerTest extends BitcoinSUnitTest { val fee = SatoshisPerVirtualByte(Satoshis(1000)) val unsignedTx = - StandardNonInteractiveFinalizer.txFrom(destinations, - creditingTxsInfos, - fee, - changeSPK) + StandardNonInteractiveFinalizer.txFrom( + destinations, + creditingTxsInfos, + fee, + changeSPK + ) val signedTx = RawTxSigner.sign(unsignedTx, creditingTxsInfos.toVector, fee) @@ -109,9 +113,11 @@ class SignerTest extends BitcoinSUnitTest { singleInfosVec.map { singleInfos => singleInfos.map { singleInfo => val keyAndSig = - BitcoinSigner.signSingle(singleInfo, - unsignedTx, - isDummySignature = false) + BitcoinSigner.signSingle( + singleInfo, + unsignedTx, + isDummySignature = false + ) keyAndSig.signature } @@ -138,7 +144,8 @@ class SignerTest extends BitcoinSUnitTest { case EmptyScriptWitness => Vector.empty case taprootWitness: TaprootWitness => throw new UnsupportedOperationException( - s"Taproot not supported, got=$taprootWitness") + s"Taproot not supported, got=$taprootWitness" + ) } } @@ -156,10 +163,12 @@ class SignerTest extends BitcoinSUnitTest { val fee = SatoshisPerVirtualByte(Satoshis(100)) val spendingTx = StandardNonInteractiveFinalizer - .txFrom(outputs = destinations, - utxos = creditingTxsInfo, - feeRate = fee, - changeSPK = changeSPK) + .txFrom( + outputs = destinations, + utxos = creditingTxsInfo, + feeRate = fee, + changeSPK = changeSPK + ) val prevOutMap = PreviousOutputMap.fromScriptSignatureParams(creditingTxsInfo) @@ -169,17 +178,20 @@ class SignerTest extends BitcoinSUnitTest { signInfo.signers.map { signer => val txSignatureComponent = TxSigComponent(signInfo.inputInfo, spendingTx, prevOutMap) - @nowarn val oldSig = BitcoinSigner.doSign(txSignatureComponent, - signer.sign, - signInfo.hashType, - isDummySignature = - false) + @nowarn val oldSig = BitcoinSigner.doSign( + txSignatureComponent, + signer.sign, + signInfo.hashType, + isDummySignature = false + ) - val newSig = BitcoinSigner.doSign(spendingTx, - signInfo, - signer.sign, - signInfo.hashType, - isDummySignature = false) + val newSig = BitcoinSigner.doSign( + spendingTx, + signInfo, + signer.sign, + signInfo.hashType, + isDummySignature = false + ) (oldSig.r == newSig.r) && (oldSig.s == newSig.s) && @@ -193,20 +205,23 @@ class SignerTest extends BitcoinSUnitTest { def inputIndex( spendingInfo: InputSigningInfo[InputInfo], - tx: Transaction): Int = { + tx: Transaction + ): Int = { tx.inputs.zipWithIndex .find(_._1.previousOutput == spendingInfo.outPoint) match { case Some((_, index)) => index case None => throw new IllegalArgumentException( - "Transaction did not contain expected input.") + "Transaction did not contain expected input." + ) } } def createProgram( tx: Transaction, idx: Int, - utxo: InputSigningInfo[InputInfo]): PreExecutionScriptProgram = { + utxo: InputSigningInfo[InputInfo] + ): PreExecutionScriptProgram = { val output = utxo.output val spk = output.scriptPubKey @@ -216,10 +231,12 @@ class SignerTest extends BitcoinSUnitTest { val txSigComponent = spk match { case witSPK: WitnessScriptPubKeyV0 => val o = TransactionOutput(amount, witSPK) - WitnessTxSigComponentRaw(tx.asInstanceOf[WitnessTransaction], - UInt32(idx), - o, - Policy.standardFlags) + WitnessTxSigComponentRaw( + tx.asInstanceOf[WitnessTransaction], + UInt32(idx), + o, + Policy.standardFlags + ) case _: UnassignedWitnessScriptPubKey | _: TaprootScriptPubKey => ??? case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey | _: P2PKWithTimeoutScriptPubKey | _: MultiSignatureScriptPubKey | @@ -235,11 +252,12 @@ class SignerTest extends BitcoinSUnitTest { p2shScriptSig.redeemScript match { case _: WitnessScriptPubKey => - WitnessTxSigComponentP2SH(transaction = - tx.asInstanceOf[WitnessTransaction], - inputIndex = UInt32(idx), - output = output, - flags = Policy.standardFlags) + WitnessTxSigComponentP2SH( + transaction = tx.asInstanceOf[WitnessTransaction], + inputIndex = UInt32(idx), + output = output, + flags = Policy.standardFlags + ) case _ => BaseTxSigComponent(tx, UInt32(idx), output, Policy.standardFlags) @@ -251,7 +269,8 @@ class SignerTest extends BitcoinSUnitTest { def verifyScripts( tx: Transaction, - utxos: Vector[InputSigningInfo[InputInfo]]): Boolean = { + utxos: Vector[InputSigningInfo[InputInfo]] + ): Boolean = { val programs: Vector[PreExecutionScriptProgram] = tx.inputs.zipWithIndex.toVector.map { case (input: TransactionInput, idx: Int) => @@ -262,51 +281,55 @@ class SignerTest extends BitcoinSUnitTest { } it must "sign p2wsh inputs correctly when provided no witness data" in { - forAll(CreditingTxGen.inputsAndOutputs(CreditingTxGen.p2wshOutputs), - ScriptGenerators.scriptPubKey) { - case ((creditingTxsInfos, destinations), (changeSPK, _)) => - val fee = SatoshisPerVirtualByte(Satoshis(100)) + forAll( + CreditingTxGen.inputsAndOutputs(CreditingTxGen.p2wshOutputs), + ScriptGenerators.scriptPubKey + ) { case ((creditingTxsInfos, destinations), (changeSPK, _)) => + val fee = SatoshisPerVirtualByte(Satoshis(100)) - val unsignedTx = - StandardNonInteractiveFinalizer.txFrom(destinations, - creditingTxsInfos, - fee, - changeSPK) + val unsignedTx = + StandardNonInteractiveFinalizer.txFrom( + destinations, + creditingTxsInfos, + fee, + changeSPK + ) - val singleSigs: Vector[Vector[PartialSignature]] = { - val singleInfosVec: Vector[Vector[ECSignatureParams[InputInfo]]] = - creditingTxsInfos.toVector.map(_.toSingles) - singleInfosVec.map { singleInfos => - singleInfos.map { singleInfo => - val wtx = - WitnessTransaction(unsignedTx.version, - unsignedTx.inputs, - unsignedTx.outputs, - unsignedTx.lockTime, - EmptyWitness.fromInputs(unsignedTx.inputs)) - BitcoinSigner.signSingle(singleInfo, - wtx, - isDummySignature = false) + val singleSigs: Vector[Vector[PartialSignature]] = { + val singleInfosVec: Vector[Vector[ECSignatureParams[InputInfo]]] = + creditingTxsInfos.toVector.map(_.toSingles) + singleInfosVec.map { singleInfos => + singleInfos.map { singleInfo => + val wtx = + WitnessTransaction( + unsignedTx.version, + unsignedTx.inputs, + unsignedTx.outputs, + unsignedTx.lockTime, + EmptyWitness.fromInputs(unsignedTx.inputs) + ) + BitcoinSigner.signSingle(singleInfo, wtx, isDummySignature = false) - } } } + } - val psbt = - creditingTxsInfos.foldLeft(PSBT.fromUnsignedTx(unsignedTx)) { - (psbt, spendInfo) => - val idx = inputIndex(spendInfo, unsignedTx) - psbt - .addUTXOToInput(spendInfo.prevTransaction, idx) - .addScriptWitnessToInput( - InputInfo.getScriptWitness(spendInfo.inputInfo).get, - idx) - .addSignatures(singleSigs(idx), idx) - } + val psbt = + creditingTxsInfos.foldLeft(PSBT.fromUnsignedTx(unsignedTx)) { + (psbt, spendInfo) => + val idx = inputIndex(spendInfo, unsignedTx) + psbt + .addUTXOToInput(spendInfo.prevTransaction, idx) + .addScriptWitnessToInput( + InputInfo.getScriptWitness(spendInfo.inputInfo).get, + idx + ) + .addSignatures(singleSigs(idx), idx) + } - val signedTx = psbt.finalizePSBT.get.extractTransactionAndValidate + val signedTx = psbt.finalizePSBT.get.extractTransactionAndValidate - assert(verifyScripts(signedTx.get, creditingTxsInfos.toVector)) + assert(verifyScripts(signedTx.get, creditingTxsInfos.toVector)) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/AddressTagTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/AddressTagTest.scala index 76d681dbda..001ee6fe50 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/AddressTagTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/AddressTagTest.scala @@ -8,23 +8,29 @@ class AddressTagTest extends BitcoinSUnitTest { it must "read StorageLocationTag from string" in { StorageLocationTag.fromString("HotStorage") must be( - StorageLocationTag.HotStorage) + StorageLocationTag.HotStorage + ) StorageLocationTag.fromString("ColdStorage") must be( - StorageLocationTag.ColdStorage) + StorageLocationTag.ColdStorage + ) StorageLocationTag.fromString("DeepColdStorage") must be( - StorageLocationTag.DeepColdStorage) + StorageLocationTag.DeepColdStorage + ) } it must "read StorageLocationTagName from string" in { InternalAddressTagName.fromString("HotStorage") must be( - StorageLocationTag.HotStorageName) + StorageLocationTag.HotStorageName + ) InternalAddressTagName.fromString("ColdStorage") must be( - StorageLocationTag.ColdStorageName) + StorageLocationTag.ColdStorageName + ) InternalAddressTagName.fromString("DeepColdStorage") must be( - StorageLocationTag.DeepColdStorageName) + StorageLocationTag.DeepColdStorageName + ) } } diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/InputInfoTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/InputInfoTest.scala index a3a59dbd99..c0f7c17146 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/InputInfoTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/InputInfoTest.scala @@ -57,11 +57,12 @@ class InputInfoTest extends BitcoinSUnitTest { val p2sh = P2SHScriptPubKey(P2WPKHWitnessSPKV0(pubKey)) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2sh) - val creditingTx = BaseTransaction(version = - TransactionConstants.validLockVersion, - inputs = Nil, - outputs = Vector(creditingOutput), - lockTime = TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + version = TransactionConstants.validLockVersion, + inputs = Nil, + outputs = Vector(creditingOutput), + lockTime = TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) assertThrows[IllegalArgumentException] { @@ -81,11 +82,12 @@ class InputInfoTest extends BitcoinSUnitTest { val p2sh = P2SHScriptPubKey(P2WPKHWitnessSPKV0(pubKey)) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2sh) - val creditingTx = BaseTransaction(version = - TransactionConstants.validLockVersion, - inputs = Nil, - outputs = Vector(creditingOutput), - lockTime = TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + version = TransactionConstants.validLockVersion, + inputs = Nil, + outputs = Vector(creditingOutput), + lockTime = TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) assertThrows[UnsupportedOperationException] { @@ -101,7 +103,8 @@ class InputInfoTest extends BitcoinSUnitTest { it should "fail given UnassignedWitnessScriptPubKey redeemScript" in { val unassingedWitnessSPK = UnassignedWitnessScriptPubKey.fromAsm( - P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey).asm) + P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey).asm + ) val privKey = ECPrivateKey.freshPrivateKey val pubKey = privKey.publicKey @@ -162,7 +165,8 @@ class InputInfoTest extends BitcoinSUnitTest { it should "successfully return UnassignedSegwitNativeUTXOSpendingInfoFull" in { val unassingedWitnessSPK = UnassignedWitnessScriptPubKey.fromAsm( - P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey).asm) + P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey).asm + ) val privKey = ECPrivateKey.freshPrivateKey val pubKey = privKey.publicKey @@ -218,9 +222,12 @@ class InputInfoTest extends BitcoinSUnitTest { val dummyTx = BaseTransaction( TransactionConstants.validLockVersion, Vector( - TransactionInput(scriptSigParams.inputInfo.outPoint, - EmptyScriptSignature, - UInt32.zero)), + TransactionInput( + scriptSigParams.inputInfo.outPoint, + EmptyScriptSignature, + UInt32.zero + ) + ), Vector(TransactionOutput(Satoshis.zero, EmptyScriptPubKey)), UInt32.zero ) @@ -241,9 +248,12 @@ class InputInfoTest extends BitcoinSUnitTest { val dummyTx = BaseTransaction( TransactionConstants.validLockVersion, Vector( - TransactionInput(scriptSigParams.inputInfo.outPoint, - EmptyScriptSignature, - UInt32.zero)), + TransactionInput( + scriptSigParams.inputInfo.outPoint, + EmptyScriptSignature, + UInt32.zero + ) + ), Vector(TransactionOutput(Satoshis.zero, EmptyScriptPubKey)), UInt32.zero ) @@ -255,9 +265,12 @@ class InputInfoTest extends BitcoinSUnitTest { .head .scriptSignature - assert(InputInfo.maxScriptSigLen( - scriptSigParams.inputInfo) == maxScriptSig.byteSize, - maxScriptSig.hex) + assert( + InputInfo.maxScriptSigLen( + scriptSigParams.inputInfo + ) == maxScriptSig.byteSize, + maxScriptSig.hex + ) } } } diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/InputSigningInfoTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/InputSigningInfoTest.scala index 74e249309c..dae55dd650 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/InputSigningInfoTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/InputSigningInfoTest.scala @@ -17,11 +17,12 @@ class InputSigningInfoTest extends BitcoinSUnitTest { it should "fail to build a tx if you have the wrong redeem script" in { val p2sh = P2SHScriptPubKey(spk) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2sh) - val creditingTx = BaseTransaction(version = - TransactionConstants.validLockVersion, - inputs = Nil, - outputs = Vector(creditingOutput), - lockTime = TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + version = TransactionConstants.validLockVersion, + inputs = Nil, + outputs = Vector(creditingOutput), + lockTime = TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) val inputInfo = InputInfo( outPoint = outPoint, @@ -53,10 +54,12 @@ class InputSigningInfoTest extends BitcoinSUnitTest { it should "fail to build a tx if you have the wrong script witness" in { val p2wsh = P2WSHWitnessSPKV0(spk) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2wsh) - val creditingTx = BaseTransaction(TransactionConstants.validLockVersion, - Nil, - Vector(creditingOutput), - TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + TransactionConstants.validLockVersion, + Nil, + Vector(creditingOutput), + TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) assertThrows[IllegalArgumentException] { ScriptSignatureParams( @@ -95,11 +98,12 @@ class InputSigningInfoTest extends BitcoinSUnitTest { val p2wpkh = P2WPKHWitnessSPKV0(pubKey = privKey.publicKey) val creditingOutput = TransactionOutput(value = CurrencyUnits.zero, scriptPubKey = p2wpkh) - val creditingTx = BaseTransaction(version = - TransactionConstants.validLockVersion, - inputs = Nil, - outputs = Vector(creditingOutput), - lockTime = TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + version = TransactionConstants.validLockVersion, + inputs = Nil, + outputs = Vector(creditingOutput), + lockTime = TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(txId = creditingTx.txId, vout = UInt32.zero) val inputInfo = InputInfo( @@ -132,10 +136,12 @@ class InputSigningInfoTest extends BitcoinSUnitTest { it should "fail to sign a p2wpkh if we pass in the wrong public key" in { val p2wpkh = P2WPKHWitnessSPKV0(privKey.publicKey) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2wpkh) - val creditingTx = BaseTransaction(TransactionConstants.validLockVersion, - Nil, - Vector(creditingOutput), - TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + TransactionConstants.validLockVersion, + Nil, + Vector(creditingOutput), + TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) assertThrows[IllegalArgumentException] { ScriptSignatureParams( @@ -173,10 +179,12 @@ class InputSigningInfoTest extends BitcoinSUnitTest { it should "fail to sign if the prevTransaction does not match the outPoint" in { val p2wpkh = P2WPKHWitnessSPKV0(privKey.publicKey) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2wpkh) - val creditingTx = BaseTransaction(TransactionConstants.validLockVersion, - Nil, - Vector(creditingOutput), - TransactionConstants.lockTime) + val creditingTx = BaseTransaction( + TransactionConstants.validLockVersion, + Nil, + Vector(creditingOutput), + TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.zero) assertThrows[IllegalArgumentException] { @@ -216,10 +224,12 @@ class InputSigningInfoTest extends BitcoinSUnitTest { val p2wpkh = P2WPKHWitnessSPKV0(privKey.publicKey) val creditingOutput = TransactionOutput(CurrencyUnits.zero, p2wpkh) val creditingTx = - BaseTransaction(TransactionConstants.validLockVersion, - Nil, - Vector(TransactionOutput(CurrencyUnits.oneBTC, p2wpkh)), - TransactionConstants.lockTime) + BaseTransaction( + TransactionConstants.validLockVersion, + Nil, + Vector(TransactionOutput(CurrencyUnits.oneBTC, p2wpkh)), + TransactionConstants.lockTime + ) val outPoint = TransactionOutPoint(creditingTx.txId, UInt32.zero) assertThrows[IllegalArgumentException] { diff --git a/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/TxoStateTest.scala b/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/TxoStateTest.scala index 1befbec177..99e2e6b408 100644 --- a/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/TxoStateTest.scala +++ b/core-test/src/test/scala/org/bitcoins/core/wallet/utxo/TxoStateTest.scala @@ -9,14 +9,16 @@ class TxoStateTest extends BitcoinSUnitTest { it must "read from string" in { TxoState.fromString("PendingConfirmationsReceived") must be( - TxoState.PendingConfirmationsReceived) + TxoState.PendingConfirmationsReceived + ) TxoState.fromString("ConfirmedReceived") must be(TxoState.ConfirmedReceived) TxoState.fromString("Reserved") must be(TxoState.Reserved) TxoState.fromString("PendingConfirmationsSpent") must be( - TxoState.PendingConfirmationsSpent) + TxoState.PendingConfirmationsSpent + ) TxoState.fromString("ConfirmedSpent") must be(TxoState.ConfirmedSpent) } diff --git a/core/src/main/scala-2.13/org/bitcoins/core/compat/CompactPackage.scala b/core/src/main/scala-2.13/org/bitcoins/core/compat/CompactPackage.scala index f465beb1aa..f0ced9a137 100644 --- a/core/src/main/scala-2.13/org/bitcoins/core/compat/CompactPackage.scala +++ b/core/src/main/scala-2.13/org/bitcoins/core/compat/CompactPackage.scala @@ -1,16 +1,13 @@ package org.bitcoins.core -/** This package provides - * compatability functionality - * for compiling Scala 2.11, 2.12 - * and 2.13, ideally without leading - * to any compiler warnings in any of +/** This package provides compatability functionality for compiling Scala 2.11, + * 2.12 and 2.13, ideally without leading to any compiler warnings in any of * the versions. */ package object compat { - /** Provides imports that allow converting - * Java collections to Scala collections + /** Provides imports that allow converting Java collections to Scala + * collections */ val JavaConverters = scala.jdk.CollectionConverters diff --git a/core/src/main/scala/org/bitcoins/core/api/Callback.scala b/core/src/main/scala/org/bitcoins/core/api/Callback.scala index df1d9de770..c7ed2875b7 100644 --- a/core/src/main/scala/org/bitcoins/core/api/Callback.scala +++ b/core/src/main/scala/org/bitcoins/core/api/Callback.scala @@ -31,11 +31,13 @@ object Callback { def noop[T]: T => Future[Unit] = _ => Future.unit } -/** Manages a set of callbacks, should be used to manage execution and logging if needed */ +/** Manages a set of callbacks, should be used to manage execution and logging + * if needed + */ case class CallbackHandler[C, T <: Callback[C]]( name: String, - override val wrapped: IndexedSeq[T]) - extends SeqWrapper[T] { + override val wrapped: IndexedSeq[T] +) extends SeqWrapper[T] { def ++(other: CallbackHandler[C, T]): CallbackHandler[C, T] = { if (name == CallbackHandler.emptyName) { @@ -45,14 +47,18 @@ case class CallbackHandler[C, T <: Callback[C]]( } else { require( name == other.name, - s"Cannot combine callback handlers with different names name=$name other.name=${other.name}") + s"Cannot combine callback handlers with different names name=$name other.name=${other.name}" + ) CallbackHandler(name, wrapped ++ other.wrapped) } } - /** Executes the callbacks synchronously, if any fail, they are recovered by recoverFunc */ + /** Executes the callbacks synchronously, if any fail, they are recovered by + * recoverFunc + */ def execute(param: C, recoverFunc: Throwable => Unit = _ => ())(implicit - ec: ExecutionContext): Future[Unit] = { + ec: ExecutionContext + ): Future[Unit] = { val executeFs = wrapped.map { callback => // Need to wrap in another future so they are all started at once // and do not block each other diff --git a/core/src/main/scala/org/bitcoins/core/api/CallbackConfig.scala b/core/src/main/scala/org/bitcoins/core/api/CallbackConfig.scala index c575c684c6..8b62c8086e 100644 --- a/core/src/main/scala/org/bitcoins/core/api/CallbackConfig.scala +++ b/core/src/main/scala/org/bitcoins/core/api/CallbackConfig.scala @@ -6,7 +6,8 @@ import org.bitcoins.core.util.Mutable trait CallbackConfig[T <: ModuleCallbacks[T]] { private[this] val atomicCallbacks: Mutable[T] = new Mutable( - callbackFactory.empty) + callbackFactory.empty + ) def isCallbackEmpty: Boolean = atomicCallbacks.atomicGet == callbackFactory.empty diff --git a/core/src/main/scala/org/bitcoins/core/api/asyncutil/AsyncUtilApi.scala b/core/src/main/scala/org/bitcoins/core/api/asyncutil/AsyncUtilApi.scala index 347a9eaf6e..027f2e608e 100644 --- a/core/src/main/scala/org/bitcoins/core/api/asyncutil/AsyncUtilApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/asyncutil/AsyncUtilApi.scala @@ -5,8 +5,8 @@ import scala.concurrent.duration.FiniteDuration trait AsyncUtilApi { - /** Returns a future that completes after the given duration - * This is useful for simulating a non blocking Thread.sleep() + /** Returns a future that completes after the given duration This is useful + * for simulating a non blocking Thread.sleep() */ def nonBlockingSleep(duration: FiniteDuration): Future[Unit] } diff --git a/core/src/main/scala/org/bitcoins/core/api/chain/ChainApi.scala b/core/src/main/scala/org/bitcoins/core/api/chain/ChainApi.scala index 4000bb077e..ed3c0d290a 100644 --- a/core/src/main/scala/org/bitcoins/core/api/chain/ChainApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/chain/ChainApi.scala @@ -17,9 +17,8 @@ import scala.concurrent.Future */ trait ChainApi extends ChainQueryApi { - /** Adds a block header to our chain project. - * This will return a failed future when the - * given header is invalid. + /** Adds a block header to our chain project. This will return a failed future + * when the given header is invalid. * * @param header * @return @@ -30,22 +29,29 @@ trait ChainApi extends ChainQueryApi { /** Process all of the given headers and returns a new [[ChainApi chain api]] * that contains these headers. This method processes headers in the order - * that they are given. If the headers are out of order, this method will fail. + * that they are given. If the headers are out of order, this method will + * fail. * - * This method will also fail when there are zero headers given that are valid. + * This method will also fail when there are zero headers given that are + * valid. * * @param headers * @return */ def processHeaders(headers: Vector[BlockHeader]): Future[ChainApi] - /** Gets a [[org.bitcoins.core.api.chain.db.BlockHeaderDb]] from the chain's database */ + /** Gets a [[org.bitcoins.core.api.chain.db.BlockHeaderDb]] from the chain's + * database + */ def getHeader(hash: DoubleSha256DigestBE): Future[Option[BlockHeaderDb]] - def getHeaders(hashes: Vector[DoubleSha256DigestBE]): Future[ - Vector[Option[BlockHeaderDb]]] + def getHeaders( + hashes: Vector[DoubleSha256DigestBE] + ): Future[Vector[Option[BlockHeaderDb]]] - /** Gets all [[org.bitcoins.core.api.chain.db.BlockHeaderDb]]s at a given height */ + /** Gets all [[org.bitcoins.core.api.chain.db.BlockHeaderDb]]s at a given + * height + */ def getHeadersAtHeight(height: Int): Future[Vector[BlockHeaderDb]] /** Gets the number of blocks in the database */ @@ -60,63 +66,77 @@ trait ChainApi extends ChainQueryApi { /** Gets all chain tips with the heaviest work */ def getBestChainTips(): Future[Vector[BlockHeaderDb]] - /** Adds a compact filter header into the filter header chain and returns a new [[ChainApi chain api]] - * that contains this header + /** Adds a compact filter header into the filter header chain and returns a + * new [[ChainApi chain api]] that contains this header */ def processFilterHeader( filterHeader: FilterHeader, - blockHash: DoubleSha256DigestBE): Future[ChainApi] = { + blockHash: DoubleSha256DigestBE + ): Future[ChainApi] = { processFilterHeaders(Vector(filterHeader), blockHash) } - /** Process all of the given compact filter headers and returns a new [[ChainApi chain api]] - * that contains these headers. + /** Process all of the given compact filter headers and returns a new + * [[ChainApi chain api]] that contains these headers. */ def processFilterHeaders( filterHeaders: Vector[FilterHeader], - stopHash: DoubleSha256DigestBE): Future[ChainApi] + stopHash: DoubleSha256DigestBE + ): Future[ChainApi] - /** Generates a block range in form of (startHeight, stopHash) by the given stop hash. - * Returns None if we are synced + /** Generates a block range in form of (startHeight, stopHash) by the given + * stop hash. Returns None if we are synced * - * @param prevStopHash our previous block hash where filter header sync stopped - * @param stopHash the block hash we want to sync the new batch of filters to - * @param batchSize the batch size of filter headers + * @param prevStopHash + * our previous block hash where filter header sync stopped + * @param stopHash + * the block hash we want to sync the new batch of filters to + * @param batchSize + * the batch size of filter headers * @return */ def nextBlockHeaderBatchRange( prevStopHash: DoubleSha256DigestBE, stopHash: DoubleSha256DigestBE, - batchSize: Int): Future[Option[FilterSyncMarker]] + batchSize: Int + ): Future[Option[FilterSyncMarker]] - /** Generates a filter header range in form of (startHeight, stopHash) by the given stop hash. + /** Generates a filter header range in form of (startHeight, stopHash) by the + * given stop hash. */ final def nextFilterHeaderBatchRange( stopBlockHash: DoubleSha256DigestBE, - batchSize: Int): Future[Option[FilterSyncMarker]] = { - nextFilterHeaderBatchRange(stopBlockHash = stopBlockHash, - batchSize = batchSize, - startHeightOpt = None) + batchSize: Int + ): Future[Option[FilterSyncMarker]] = { + nextFilterHeaderBatchRange( + stopBlockHash = stopBlockHash, + batchSize = batchSize, + startHeightOpt = None + ) } /** Generates a query for a range of compact filters - * @param stopBlockHash the block hash to stop receiving filters at + * @param stopBlockHash + * the block hash to stop receiving filters at * @param batchSize - * @param startHeightOpt the block height to start syncing filters from. If None, we query our chainstate for the last filter we've seen + * @param startHeightOpt + * the block height to start syncing filters from. If None, we query our + * chainstate for the last filter we've seen * @return */ def nextFilterHeaderBatchRange( stopBlockHash: DoubleSha256DigestBE, batchSize: Int, - startHeightOpt: Option[Int]): Future[Option[FilterSyncMarker]] + startHeightOpt: Option[Int] + ): Future[Option[FilterSyncMarker]] /** Adds a compact filter into the filter database. */ def processFilter(message: CompactFilterMessage): Future[ChainApi] = processFilters(Vector(message)) - /** Process all of the given compact filters and returns a new [[ChainApi chain api]] - * that contains these headers. + /** Process all of the given compact filters and returns a new + * [[ChainApi chain api]] that contains these headers. */ def processFilters(message: Vector[CompactFilterMessage]): Future[ChainApi] @@ -124,7 +144,8 @@ trait ChainApi extends ChainQueryApi { */ def processCheckpoint( filterHeaderHash: DoubleSha256DigestBE, - blockHash: DoubleSha256DigestBE): Future[ChainApi] = { + blockHash: DoubleSha256DigestBE + ): Future[ChainApi] = { processCheckpoints(Vector(filterHeaderHash), blockHash) } @@ -132,7 +153,8 @@ trait ChainApi extends ChainQueryApi { */ def processCheckpoints( checkpoints: Vector[DoubleSha256DigestBE], - blockHash: DoubleSha256DigestBE): Future[ChainApi] + blockHash: DoubleSha256DigestBE + ): Future[ChainApi] /** Gets the number of compact filter headers in the database */ def getFilterHeaderCount(): Future[Int] @@ -140,12 +162,12 @@ trait ChainApi extends ChainQueryApi { /** Looks up a compact filter header by its height. */ def getFilterHeadersAtHeight( - height: Int): Future[Vector[CompactFilterHeaderDb]] + height: Int + ): Future[Vector[CompactFilterHeaderDb]] - /** Finds the "best" filter header we have stored in our database - * What this means in practice is the latest filter header we - * have received from our peer. - * Returns none if we have no filters in the database + /** Finds the "best" filter header we have stored in our database What this + * means in practice is the latest filter header we have received from our + * peer. Returns none if we have no filters in the database */ def getBestFilterHeader(): Future[Option[CompactFilterHeaderDb]] @@ -154,7 +176,8 @@ trait ChainApi extends ChainQueryApi { /** Looks up a compact filter header by its hash. */ def getFilterHeader( - blockHash: DoubleSha256DigestBE): Future[Option[CompactFilterHeaderDb]] + blockHash: DoubleSha256DigestBE + ): Future[Option[CompactFilterHeaderDb]] /** Looks up a compact filter by its hash. */ @@ -173,14 +196,16 @@ trait ChainApi extends ChainQueryApi { /** Fetchs the block headers between from and to (inclusive). */ def getHeadersBetween( from: BlockHeaderDb, - to: BlockHeaderDb): Future[Vector[BlockHeaderDb]] + to: BlockHeaderDb + ): Future[Vector[BlockHeaderDb]] def isSyncing(): Future[Boolean] def isIBD(): Future[Boolean] /** Checks if our chain tip is stale - * @see [[https://github.com/bitcoin/bitcoin/blob/664500fc71a32d5066db8cb4a19ddc7005a1c9e9/src/net_processing.cpp#L1235]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/664500fc71a32d5066db8cb4a19ddc7005a1c9e9/src/net_processing.cpp#L1235]] */ def isTipStale(): Future[Boolean] diff --git a/core/src/main/scala/org/bitcoins/core/api/chain/ChainQueryApi.scala b/core/src/main/scala/org/bitcoins/core/api/chain/ChainQueryApi.scala index 1c49ac7d80..eba6d9c35f 100644 --- a/core/src/main/scala/org/bitcoins/core/api/chain/ChainQueryApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/chain/ChainQueryApi.scala @@ -20,13 +20,16 @@ trait ChainQueryApi { for { hash <- getBestBlockHash() heightOpt <- getBlockHeight(hash) - _ = require(heightOpt.isDefined, - s"Best block hash must have a height! blockhash=$hash") + _ = require( + heightOpt.isDefined, + s"Best block hash must have a height! blockhash=$hash" + ) } yield heightOpt.get /** Gets number of confirmations for the given block hash */ def getNumberOfConfirmations( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] /** Gets the number of compact filters in the database */ def getFilterCount(): Future[Int] @@ -36,7 +39,8 @@ trait ChainQueryApi { def getFiltersBetweenHeights( startHeight: Int, - endHeight: Int): Future[Vector[ChainQueryApi.FilterResponse]] + endHeight: Int + ): Future[Vector[ChainQueryApi.FilterResponse]] /** Gets the block height of the closest block to the given time */ def epochSecondToBlockHeight(time: Long): Future[Int] @@ -50,27 +54,27 @@ object ChainQueryApi { case class FilterResponse( compactFilter: GolombFilter, blockHash: DoubleSha256DigestBE, - blockHeight: Int) + blockHeight: Int + ) sealed abstract class ChainException(message: String) extends RuntimeException(message) - /** [[ChainQueryApi]] cannot find a compact - * filter or header by its filter hash + /** [[ChainQueryApi]] cannot find a compact filter or header by its filter + * hash */ case class UnknownFilterHash(message: String) extends ChainException(message) - /** [[ChainQueryApi]] cannot find a blockchain - * item by its block hash + /** [[ChainQueryApi]] cannot find a blockchain item by its block hash */ case class UnknownBlockHash(message: String) extends ChainException(message) - /** [[ChainQueryApi]] cannot find a blockchain - * item by its height + /** [[ChainQueryApi]] cannot find a blockchain item by its height */ case class UnknownBlockHeight(message: String) extends ChainException(message) - /** [[ChainQueryApi]] tried to process multiple filters for the same block hash + /** [[ChainQueryApi]] tried to process multiple filters for the same block + * hash */ case class DuplicateFilters(message: String) extends ChainException(message) diff --git a/core/src/main/scala/org/bitcoins/core/api/chain/FilterSyncMarker.scala b/core/src/main/scala/org/bitcoins/core/api/chain/FilterSyncMarker.scala index c88babfe5c..9d25d96a11 100644 --- a/core/src/main/scala/org/bitcoins/core/api/chain/FilterSyncMarker.scala +++ b/core/src/main/scala/org/bitcoins/core/api/chain/FilterSyncMarker.scala @@ -2,15 +2,17 @@ package org.bitcoins.core.api.chain import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE} -/** This is a helper class for syncing block filters following the - * BIP157 protocol. This indicates the starting block height we are - * syncing filters at, and the last block hash we expect in the batch - * of filters sent back to us by our peer - * @see https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfheaders +/** This is a helper class for syncing block filters following the BIP157 + * protocol. This indicates the starting block height we are syncing filters + * at, and the last block hash we expect in the batch of filters sent back to + * us by our peer + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfheaders */ case class FilterSyncMarker( startHeight: Int, - stopBlockHash: DoubleSha256Digest) { + stopBlockHash: DoubleSha256Digest +) { val stopBlockHashBE: DoubleSha256DigestBE = stopBlockHash.flip diff --git a/core/src/main/scala/org/bitcoins/core/api/chain/db/BlockHeaderDb.scala b/core/src/main/scala/org/bitcoins/core/api/chain/db/BlockHeaderDb.scala index ee4df11900..96b473d0f2 100644 --- a/core/src/main/scala/org/bitcoins/core/api/chain/db/BlockHeaderDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/chain/db/BlockHeaderDb.scala @@ -14,7 +14,8 @@ case class BlockHeaderDb( nBits: UInt32, nonce: UInt32, hex: String, - chainWork: BigInt) { + chainWork: BigInt +) { lazy val blockHeader: BlockHeader = { val blockHeader = BlockHeader.fromHex(hex) @@ -26,7 +27,8 @@ case class BlockHeaderDb( require(blockHeader.nonce == nonce) require( blockHeader.time == time, - s"Inconsistent in memory time=$time vs serialized time=${blockHeader.time}") + s"Inconsistent in memory time=$time vs serialized time=${blockHeader.time}" + ) blockHeader } @@ -48,7 +50,8 @@ object BlockHeaderDbHelper { def fromBlockHeader( height: Int, chainWork: BigInt, - bh: BlockHeader): BlockHeaderDb = { + bh: BlockHeader + ): BlockHeaderDb = { BlockHeaderDb( height = height, hashBE = bh.hashBE, diff --git a/core/src/main/scala/org/bitcoins/core/api/chain/db/CompactFilterDb.scala b/core/src/main/scala/org/bitcoins/core/api/chain/db/CompactFilterDb.scala index 2dd8a3bc14..47a397d9c2 100644 --- a/core/src/main/scala/org/bitcoins/core/api/chain/db/CompactFilterDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/chain/db/CompactFilterDb.scala @@ -9,10 +9,12 @@ case class CompactFilterDb( filterType: FilterType, bytes: ByteVector, height: Int, - blockHashBE: DoubleSha256DigestBE) { + blockHashBE: DoubleSha256DigestBE +) { require( CryptoUtil.doubleSHA256(bytes).flip == hashBE, - s"Bytes must hash to hashBE! It looks like you didn't construct CompactFilterDb correctly") + s"Bytes must hash to hashBE! It looks like you didn't construct CompactFilterDb correctly" + ) def golombFilter: GolombFilter = filterType match { @@ -29,16 +31,20 @@ object CompactFilterDbHelper { def fromGolombFilter( golombFilter: GolombFilter, blockHash: DoubleSha256DigestBE, - height: Int): CompactFilterDb = + height: Int + ): CompactFilterDb = fromFilterBytes(golombFilter.bytes, blockHash, height) def fromFilterBytes( filterBytes: ByteVector, blockHash: DoubleSha256DigestBE, - height: Int): CompactFilterDb = - CompactFilterDb(CryptoUtil.doubleSHA256(filterBytes).flip, - FilterType.Basic, - filterBytes, - height, - blockHash) + height: Int + ): CompactFilterDb = + CompactFilterDb( + CryptoUtil.doubleSHA256(filterBytes).flip, + FilterType.Basic, + filterBytes, + height, + blockHash + ) } diff --git a/core/src/main/scala/org/bitcoins/core/api/chain/db/CompactFilterHeaderDb.scala b/core/src/main/scala/org/bitcoins/core/api/chain/db/CompactFilterHeaderDb.scala index 5e1623d422..c63b7ca1e1 100644 --- a/core/src/main/scala/org/bitcoins/core/api/chain/db/CompactFilterHeaderDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/chain/db/CompactFilterHeaderDb.scala @@ -8,7 +8,8 @@ case class CompactFilterHeaderDb( filterHashBE: DoubleSha256DigestBE, previousFilterHeaderBE: DoubleSha256DigestBE, blockHashBE: DoubleSha256DigestBE, - height: Int) { + height: Int +) { def filterHeader: FilterHeader = FilterHeader(filterHashBE.flip, previousFilterHeaderBE.flip) @@ -23,7 +24,8 @@ object CompactFilterHeaderDbHelper { def fromFilterHeader( filterHeader: FilterHeader, blockHash: DoubleSha256DigestBE, - height: Int): CompactFilterHeaderDb = + height: Int + ): CompactFilterHeaderDb = CompactFilterHeaderDb( hashBE = filterHeader.hash.flip, filterHashBE = filterHeader.filterHash.flip, diff --git a/core/src/main/scala/org/bitcoins/core/api/commons/InstanceFactory.scala b/core/src/main/scala/org/bitcoins/core/api/commons/InstanceFactory.scala index 8f0b6d733c..7eda3c2193 100644 --- a/core/src/main/scala/org/bitcoins/core/api/commons/InstanceFactory.scala +++ b/core/src/main/scala/org/bitcoins/core/api/commons/InstanceFactory.scala @@ -4,8 +4,11 @@ import java.io.File import java.nio.file.Path /** A factory to create things like bitcoind instances or eclair instances - * @tparam the type of the instance (i.e. BitcoindInstance) - * @tparam the type of hte implicit parameter, this can be an execution context or ActorSystem + * @tparam the + * type of the instance (i.e. BitcoindInstance) + * @tparam the + * type of hte implicit parameter, this can be an execution context or + * ActorSystem */ trait InstanceFactory[+T, I] { def fromConfigFile(file: File)(implicit i: I): T diff --git a/core/src/main/scala/org/bitcoins/core/api/db/DbRowAutoInc.scala b/core/src/main/scala/org/bitcoins/core/api/db/DbRowAutoInc.scala index c97c425a08..6bbcbbf5d8 100644 --- a/core/src/main/scala/org/bitcoins/core/api/db/DbRowAutoInc.scala +++ b/core/src/main/scala/org/bitcoins/core/api/db/DbRowAutoInc.scala @@ -1,10 +1,9 @@ package org.bitcoins.core.api.db -/** This is meant to be coupled with [[CRUDAutoInc]] - * and [[TableAutoInc]] to allow for automatically incrementing an id - * when inserting something into a database. This removes the boiler - * boiler plate from this having to happen every where a [[CRUD]] - * is created +/** This is meant to be coupled with [[CRUDAutoInc]] and [[TableAutoInc]] to + * allow for automatically incrementing an id when inserting something into a + * database. This removes the boiler boiler plate from this having to happen + * every where a [[CRUD]] is created */ abstract class DbRowAutoInc[T] { diff --git a/core/src/main/scala/org/bitcoins/core/api/dlc/node/DLCNodeApi.scala b/core/src/main/scala/org/bitcoins/core/api/dlc/node/DLCNodeApi.scala index ad75ea9b36..759d26d836 100644 --- a/core/src/main/scala/org/bitcoins/core/api/dlc/node/DLCNodeApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/dlc/node/DLCNodeApi.scala @@ -18,18 +18,20 @@ trait DLCNodeApi extends StartStopAsync[Unit] { peerAddress: InetSocketAddress, dlcOffer: LnMessage[DLCOfferTLV], externalPayoutAddress: Option[BitcoinAddress], - externalChangeAddress: Option[BitcoinAddress]): Future[ - DLCMessage.DLCAccept] + externalChangeAddress: Option[BitcoinAddress] + ): Future[DLCMessage.DLCAccept] def sendDLCOffer( peerAddress: InetSocketAddress, message: String, - offerTLV: DLCOfferTLV): Future[Sha256Digest] + offerTLV: DLCOfferTLV + ): Future[Sha256Digest] def sendDLCOffer( peerAddress: InetSocketAddress, message: String, - tempContractId: Sha256Digest): Future[Sha256Digest] + tempContractId: Sha256Digest + ): Future[Sha256Digest] def checkPeerConnection(peerAddress: InetSocketAddress): Future[Unit] diff --git a/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/DLCWalletApi.scala b/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/DLCWalletApi.scala index de13adb3ca..b9aca2afca 100644 --- a/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/DLCWalletApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/DLCWalletApi.scala @@ -30,15 +30,18 @@ trait DLCWalletApi { self: WalletApi => refundLT: UInt32, peerAddressOpt: Option[java.net.InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] = { + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCOffer] = { val contractInfo = ContractInfo.fromTLV(contractInfoTLV) - createDLCOffer(contractInfo, - collateral, - feeRateOpt, - refundLT, - peerAddressOpt, - externalPayoutAddressOpt, - externalChangeAddressOpt) + createDLCOffer( + contractInfo, + collateral, + feeRateOpt, + refundLT, + peerAddressOpt, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) } def createDLCOffer( @@ -49,16 +52,19 @@ trait DLCWalletApi { self: WalletApi => refundLT: UInt32, peerAddressOpt: Option[java.net.InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] = { + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCOffer] = { val contractInfo = ContractInfo.fromTLV(contractInfoTLV) - createDLCOffer(contractInfo, - collateral, - feeRateOpt, - locktime, - refundLT, - peerAddressOpt, - externalPayoutAddressOpt, - externalChangeAddressOpt) + createDLCOffer( + contractInfo, + collateral, + feeRateOpt, + locktime, + refundLT, + peerAddressOpt, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) } def createDLCOffer( @@ -68,7 +74,8 @@ trait DLCWalletApi { self: WalletApi => refundLT: UInt32, peerAddressOpt: Option[java.net.InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCOffer] def createDLCOffer( contractInfo: ContractInfo, @@ -78,24 +85,29 @@ trait DLCWalletApi { self: WalletApi => refundLT: UInt32, peerAddressOpt: Option[java.net.InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCOffer] def acceptDLCOffer( dlcOfferTLV: DLCOfferTLV, peerAddress: Option[InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCAccept] = { - acceptDLCOffer(DLCOffer.fromTLV(dlcOfferTLV), - peerAddress, - externalPayoutAddressOpt, - externalChangeAddressOpt) + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCAccept] = { + acceptDLCOffer( + DLCOffer.fromTLV(dlcOfferTLV), + peerAddress, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) } def acceptDLCOffer( dlcOffer: DLCOffer, peerAddress: Option[InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCAccept] + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCAccept] def signDLC(acceptTLV: DLCAcceptTLV): Future[DLCSign] @@ -109,29 +121,43 @@ trait DLCWalletApi { self: WalletApi => def broadcastDLCFundingTx(contractId: ByteVector): Future[Transaction] - /** Creates the CET for the given contractId and oracle signature, does not broadcast it */ + /** Creates the CET for the given contractId and oracle signature, does not + * broadcast it + */ def executeDLC( contractId: ByteVector, - oracleSig: OracleAttestmentTLV): Future[Option[Transaction]] = + oracleSig: OracleAttestmentTLV + ): Future[Option[Transaction]] = executeDLC(contractId, Vector(oracleSig)) - /** Creates the CET for the given contractId and oracle signature, does not broadcast it */ + /** Creates the CET for the given contractId and oracle signature, does not + * broadcast it + */ def executeDLC( contractId: ByteVector, - oracleSigs: Seq[OracleAttestmentTLV]): Future[Option[Transaction]] + oracleSigs: Seq[OracleAttestmentTLV] + ): Future[Option[Transaction]] - /** Creates the CET for the given contractId and oracle signature, does not broadcast it */ + /** Creates the CET for the given contractId and oracle signature, does not + * broadcast it + */ def executeDLC( contractId: ByteVector, - oracleSig: OracleSignatures): Future[Option[Transaction]] = + oracleSig: OracleSignatures + ): Future[Option[Transaction]] = executeDLC(contractId, Vector(oracleSig)) - /** Creates the CET for the given contractId and oracle signature, does not broadcast it */ + /** Creates the CET for the given contractId and oracle signature, does not + * broadcast it + */ def executeDLC( contractId: ByteVector, - oracleSigs: Vector[OracleSignatures]): Future[Option[Transaction]] + oracleSigs: Vector[OracleSignatures] + ): Future[Option[Transaction]] - /** Creates the refund transaction for the given contractId, does not broadcast it */ + /** Creates the refund transaction for the given contractId, does not + * broadcast it + */ def executeDLCRefund(contractId: ByteVector): Future[Transaction] /** Fetches all DLCs with the given set of states */ @@ -142,7 +168,8 @@ trait DLCWalletApi { self: WalletApi => def findDLC(dlcId: Sha256Digest): Future[Option[DLCStatus]] def findDLCByTemporaryContractId( - tempContractId: Sha256Digest): Future[Option[DLCStatus]] + tempContractId: Sha256Digest + ): Future[Option[DLCStatus]] def cancelDLC(dlcId: Sha256Digest): Future[Unit] @@ -154,14 +181,16 @@ trait DLCWalletApi { self: WalletApi => def registerIncomingDLCOffer( offerTLV: DLCOfferTLV, peer: Option[String], - message: Option[String]): Future[Sha256Digest] + message: Option[String] + ): Future[Sha256Digest] def listIncomingDLCOffers(): Future[Vector[IncomingDLCOfferDb]] def rejectIncomingDLCOffer(offerHash: Sha256Digest): Future[Unit] def findIncomingDLCOffer( - offerHash: Sha256Digest): Future[Option[IncomingDLCOfferDb]] + offerHash: Sha256Digest + ): Future[Option[IncomingDLCOfferDb]] def listDLCContacts(): Future[Vector[DLCContactDb]] @@ -173,7 +202,8 @@ trait DLCWalletApi { self: WalletApi => def addDLCContactMapping( dlcId: Sha256Digest, - contactId: InetSocketAddress): Future[Unit] + contactId: InetSocketAddress + ): Future[Unit] def removeDLCContactMapping(dlcId: Sha256Digest): Future[Unit] diff --git a/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/db/DLCDb.scala b/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/db/DLCDb.scala index 898271d202..e519ef7534 100644 --- a/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/db/DLCDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/db/DLCDb.scala @@ -17,8 +17,8 @@ import scodec.bits.ByteVector import java.time.Instant -/** This table contains all the meta information about a DLC. - * This includes various identifiers as well as state and a BIP 32 key path. +/** This table contains all the meta information about a DLC. This includes + * various identifiers as well as state and a BIP 32 key path. */ case class DLCDb( dlcId: Sha256Digest, @@ -46,9 +46,11 @@ case class DLCDb( } def updateFundingOutPoint(outPoint: TransactionOutPoint): DLCDb = { - copy(fundingOutPointOpt = Some(outPoint), - fundingTxIdOpt = Some(outPoint.txIdBE), - lastUpdated = TimeUtil.now) + copy( + fundingOutPointOpt = Some(outPoint), + fundingTxIdOpt = Some(outPoint.txIdBE), + lastUpdated = TimeUtil.now + ) } def updateClosingTxId(txId: DoubleSha256DigestBE): DLCDb = { diff --git a/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/db/IncomingDLCOfferDb.scala b/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/db/IncomingDLCOfferDb.scala index c90eb59e3f..6cdc4a914c 100644 --- a/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/db/IncomingDLCOfferDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/dlc/wallet/db/IncomingDLCOfferDb.scala @@ -10,11 +10,16 @@ case class IncomingDLCOfferDb( receivedAt: Instant, peer: Option[String], message: Option[String], - offerTLV: DLCOfferTLV) { - require(peer.forall(_.length <= 1024), - "peer length must not exceed 1024 characters") - require(message.forall(_.length <= 1024), - "message length must not exceed 1024 characters") + offerTLV: DLCOfferTLV +) { + require( + peer.forall(_.length <= 1024), + "peer length must not exceed 1024 characters" + ) + require( + message.forall(_.length <= 1024), + "message length must not exceed 1024 characters" + ) def toTLV: SendOfferTLV = { require(peer.nonEmpty) diff --git a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/DLCOracleApi.scala b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/DLCOracleApi.scala index 9bbf85f64c..e10e0d726c 100644 --- a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/DLCOracleApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/DLCOracleApi.scala @@ -43,74 +43,84 @@ trait DLCOracleApi { isSigned: Boolean, numDigits: Int, unit: String, - precision: Int32): Future[OracleAnnouncementTLV] + precision: Int32 + ): Future[OracleAnnouncementTLV] def createNewEnumAnnouncement( eventName: String, maturationTime: Instant, - outcomes: Vector[String]): Future[OracleAnnouncementTLV] + outcomes: Vector[String] + ): Future[OracleAnnouncementTLV] def createNewAnnouncement( eventName: String, maturationTime: Instant, descriptor: EventDescriptorTLV, - signingVersion: SigningVersion = SigningVersion.latest): Future[ - OracleAnnouncementTLV] + signingVersion: SigningVersion = SigningVersion.latest + ): Future[OracleAnnouncementTLV] /** Signs an enumerated announcement - * @param eventName the event name of the announcement - * @param outcome the outcome for the give announcement + * @param eventName + * the event name of the announcement + * @param outcome + * the outcome for the give announcement */ def signEnum(eventName: String, outcome: EnumAttestation): Future[EventDb] /** Signs an enumerated announcement - * @param oracleEventTLV the tlv of the oracle event - * @param outcome the outcome for the give announcement + * @param oracleEventTLV + * the tlv of the oracle event + * @param outcome + * the outcome for the give announcement */ def signEnum( oracleEventTLV: OracleEventTLV, - outcome: EnumAttestation): Future[EventDb] + outcome: EnumAttestation + ): Future[EventDb] def createAttestation( nonce: SchnorrNonce, - outcome: DLCAttestationType): Future[EventDb] + outcome: DLCAttestationType + ): Future[EventDb] def signDigits(eventName: String, num: Long): Future[OracleEvent] def signDigits(oracleEventTLV: OracleEventTLV, num: Long): Future[OracleEvent] - /** Deletes an announcement with the given name - * WARNING: If this announcement has been published widely - * users will not be able to settle their DLCs. - * You likely should only use this in testing scenarios - * @return the deleted announcement + /** Deletes an announcement with the given name WARNING: If this announcement + * has been published widely users will not be able to settle their DLCs. You + * likely should only use this in testing scenarios + * @return + * the deleted announcement */ def deleteAnnouncement(eventName: String): Future[OracleAnnouncementTLV] - /** Deletes an announcement with the given name - * WARNING: If this announcement has been published widely - * users will not be able to settle their DLCs. - * You likely should only use this in testing scenarios - * @return the deleted announcement + /** Deletes an announcement with the given name WARNING: If this announcement + * has been published widely users will not be able to settle their DLCs. You + * likely should only use this in testing scenarios + * @return + * the deleted announcement */ def deleteAnnouncement( - announcementTLV: OracleAnnouncementTLV): Future[OracleAnnouncementTLV] + announcementTLV: OracleAnnouncementTLV + ): Future[OracleAnnouncementTLV] /** Deletes attestations for the given event * - * WARNING: if previous signatures have been made public - * the oracle private key will be revealed. + * WARNING: if previous signatures have been made public the oracle private + * key will be revealed. */ def deleteAttestation(eventName: String): Future[OracleEvent] /** Deletes attestations for the given event * - * WARNING: if previous signatures have been made public - * the oracle private key will be revealed. + * WARNING: if previous signatures have been made public the oracle private + * key will be revealed. */ def deleteAttestation(oracleEventTLV: OracleEventTLV): Future[OracleEvent] - /** Signs the SHA256 hash of the given string using the oracle's signing key */ + /** Signs the SHA256 hash of the given string using the oracle's signing key + */ def signMessage(message: String): SchnorrDigitalSignature = { signMessage(CryptoUtil.serializeForHash(message)) } @@ -118,8 +128,8 @@ trait DLCOracleApi { /** Signs the SHA256 hash of the given bytes using the oracle's signing key */ def signMessage(message: ByteVector): SchnorrDigitalSignature - /** Returns the staking address private key in wallet import format - * so a user can take it an recover the funds in another wallet + /** Returns the staking address private key in wallet import format so a user + * can take it an recover the funds in another wallet */ def exportSigningKeyWIF: String } diff --git a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/OracleEvent.scala b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/OracleEvent.scala index 2a21ed5ac1..5903a60822 100644 --- a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/OracleEvent.scala +++ b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/OracleEvent.scala @@ -10,9 +10,8 @@ import org.bitcoins.crypto._ import java.time.Instant -/** Represents an event that the oracle has committed to - * Contains all the necessary information to construct - * all the oracle TLV messages +/** Represents an event that the oracle has committed to Contains all the + * necessary information to construct all the oracle TLV messages */ sealed trait OracleEvent { @@ -37,13 +36,17 @@ sealed trait OracleEvent { def eventDescriptorTLV: EventDescriptorTLV def eventTLV: OracleEventTLV = { - require(eventDbsOpt.isDefined, - s"Event dbs must be defined to figure out ordering of nonces") + require( + eventDbsOpt.isDefined, + s"Event dbs must be defined to figure out ordering of nonces" + ) val v0NonceOrder = eventDbsOpt.get.sortBy(_.nonceIndex).map(_.nonce) - OracleEventV0TLV(v0NonceOrder, - UInt32(maturationTime.getEpochSecond), - eventDescriptorTLV, - eventName) + OracleEventV0TLV( + v0NonceOrder, + UInt32(maturationTime.getEpochSecond), + eventDescriptorTLV, + eventName + ) } def announcementTLV: OracleAnnouncementTLV = { @@ -53,8 +56,8 @@ sealed trait OracleEvent { } } - /** These are needed for old announcements/attesatations that do not follow the requirement - * to order nonces + /** These are needed for old announcements/attesatations that do not follow + * the requirement to order nonces */ protected def eventDbsOpt: Option[Vector[EventDb]] } @@ -66,8 +69,10 @@ sealed trait PendingOracleEvent extends OracleEvent sealed trait CompletedOracleEvent extends OracleEvent { def attestations: Vector[FieldElement] - require(attestations.size == nonces.size, - "Must have a signature for every nonce") + require( + attestations.size == nonces.size, + "Must have a signature for every nonce" + ) def signatures: OrderedSchnorrSignatures = { val unsorted = nonces.toVector @@ -80,16 +85,18 @@ sealed trait CompletedOracleEvent extends OracleEvent { announcementTLV match { case ann: OracleAnnouncementV0TLV => - //v0 announcements do not have a invariant stating that nonces neeed to be sorted - //a specific way, so we need to use the unsorted variant to make sure - //announcementSignatures evaluate to true + // v0 announcements do not have a invariant stating that nonces neeed to be sorted + // a specific way, so we need to use the unsorted variant to make sure + // announcementSignatures evaluate to true val unsorted = ann.eventTLV.nonces .zip(attestations) .map(sigPieces => SchnorrDigitalSignature(sigPieces._1, sigPieces._2)) - OracleAttestmentV0TLV(eventName, - pubkey, - unsorted, - outcomes.map(_.outcomeString)) + OracleAttestmentV0TLV( + eventName, + pubkey, + unsorted, + outcomes.map(_.outcomeString) + ) } } @@ -113,8 +120,8 @@ case class PendingEnumV0OracleEvent( maturationTime: Instant, announcementSignature: SchnorrDigitalSignature, eventDescriptorTLV: EnumEventDescriptorV0TLV, - eventDbsOpt: Option[Vector[EventDb]]) - extends PendingOracleEvent + eventDbsOpt: Option[Vector[EventDb]] +) extends PendingOracleEvent with EnumV0OracleEvent case class CompletedEnumV0OracleEvent( @@ -127,13 +134,15 @@ case class CompletedEnumV0OracleEvent( eventDescriptorTLV: EnumEventDescriptorV0TLV, outcome: EnumAttestation, attestation: FieldElement, - eventDbsOpt: Option[Vector[EventDb]]) - extends CompletedOracleEvent + eventDbsOpt: Option[Vector[EventDb]] +) extends CompletedOracleEvent with EnumV0OracleEvent { require( - OracleEvent.verifyAttestations(announcementTLV, - oracleAttestmentV0TLV, - signingVersion), + OracleEvent.verifyAttestations( + announcementTLV, + oracleAttestmentV0TLV, + signingVersion + ), s"Signatures given are invalid, eventId=${announcementTLV.eventTLV.eventId}" ) @@ -156,8 +165,8 @@ case class PendingDigitDecompositionV0OracleEvent( maturationTime: Instant, announcementSignature: SchnorrDigitalSignature, eventDescriptorTLV: DigitDecompositionEventDescriptorV0TLV, - eventDbsOpt: Option[Vector[EventDb]]) - extends PendingOracleEvent + eventDbsOpt: Option[Vector[EventDb]] +) extends PendingOracleEvent with DigitDecompositionV0OracleEvent case class CompletedDigitDecompositionV0OracleEvent( @@ -170,14 +179,16 @@ case class CompletedDigitDecompositionV0OracleEvent( eventDescriptorTLV: DigitDecompositionEventDescriptorV0TLV, dlcOutcome: NumericDLCOutcomeType, attestations: Vector[FieldElement], - eventDbsOpt: Option[Vector[EventDb]]) - extends CompletedOracleEvent + eventDbsOpt: Option[Vector[EventDb]] +) extends CompletedOracleEvent with DigitDecompositionV0OracleEvent { require( - OracleEvent.verifyAttestations(announcementTLV, - oracleAttestmentV0TLV, - signingVersion), + OracleEvent.verifyAttestations( + announcementTLV, + oracleAttestmentV0TLV, + signingVersion + ), s"Signatures given are invalid for eventId=${announcementTLV.eventTLV.eventId}" ) @@ -212,8 +223,10 @@ object OracleEvent { def fromEventDbs(eventDbs: Vector[EventDb]): OracleEvent = { val eventDb = eventDbs.head - require(eventDbs.forall(_.eventDescriptorTLV == eventDb.eventDescriptorTLV), - "EventDbs must all refer to the same event") + require( + eventDbs.forall(_.eventDescriptorTLV == eventDb.eventDescriptorTLV), + "EventDbs must all refer to the same event" + ) (eventDb.eventDescriptorTLV, eventDb.attestationOpt) match { case (enum: EnumEventDescriptorV0TLV, Some(sig)) => @@ -232,17 +245,21 @@ object OracleEvent { ) case (enum: EnumEventDescriptorV0TLV, None) => require(eventDbs.size == 1, "Enum events may only have one eventDb") - PendingEnumV0OracleEvent(eventDb.pubkey, - eventDb.nonce, - eventDb.eventName, - eventDb.signingVersion, - eventDb.maturationTime, - eventDb.announcementSignature, - enum, - Some(eventDbs)) + PendingEnumV0OracleEvent( + eventDb.pubkey, + eventDb.nonce, + eventDb.eventName, + eventDb.signingVersion, + eventDb.maturationTime, + eventDb.announcementSignature, + enum, + Some(eventDbs) + ) case (decomp: DigitDecompositionEventDescriptorV0TLV, Some(_)) => - require(eventDbs.forall(_.attestationOpt.isDefined), - "Cannot have a partially signed event") + require( + eventDbs.forall(_.attestationOpt.isDefined), + "Cannot have a partially signed event" + ) val sortedEventDbs = eventDbs.sortBy(_.nonceIndex) val attestations = sortedEventDbs.flatMap(_.attestationOpt) @@ -273,8 +290,10 @@ object OracleEvent { Some(eventDbs) ) case (decomp: DigitDecompositionEventDescriptorV0TLV, None) => - require(eventDbs.forall(_.attestationOpt.isEmpty), - "Cannot have a partially signed event") + require( + eventDbs.forall(_.attestationOpt.isEmpty), + "Cannot have a partially signed event" + ) val sortedEventDbs = eventDbs.sortBy(_.nonceIndex) @@ -291,12 +310,14 @@ object OracleEvent { } } - /** Verifies if the given attestations sign the outcomes of the given oracle announcement. + /** Verifies if the given attestations sign the outcomes of the given oracle + * announcement. */ def verifyAttestations( announcement: OracleAnnouncementTLV, attestationTLV: OracleAttestmentTLV, - signingVersion: SigningVersion): Boolean = { + signingVersion: SigningVersion + ): Boolean = { val tlvOutcomes = attestationTLV.outcomes val attestations = attestationTLV match { case v0: OracleAttestmentV0TLV => @@ -322,8 +343,10 @@ object OracleEvent { val attestationType = EnumAttestation(outcome) val hash = signingVersion.calcOutcomeHash(attestationType.bytes) - announcement.publicKey.verify(hash, - sig) && outcome == tlvOutcomes.head + announcement.publicKey.verify( + hash, + sig + ) && outcome == tlvOutcomes.head } case dd: DigitDecompositionEventDescriptorV0TLV => @@ -334,14 +357,16 @@ object OracleEvent { case _: SignedDigitDecompositionEventDescriptor => val signOutcomes = Vector( DigitDecompositionSignAttestation(true), - DigitDecompositionSignAttestation(false)) + DigitDecompositionSignAttestation(false) + ) val validSign = signOutcomes.exists { attestationType => val hash = signingVersion.calcOutcomeHash(attestationType.bytes) announcement.publicKey.verify( hash, - attestations.head) && tlvOutcomes.head.toString == attestationType.outcomeString + attestations.head + ) && tlvOutcomes.head.toString == attestationType.outcomeString } (validSign, attestations.tail, tlvOutcomes.tail) @@ -361,7 +386,8 @@ object OracleEvent { signingVersion.calcOutcomeHash(attestationType.bytes) announcement.publicKey.verify( hash, - sig) && attestationType.outcomeString == outcome.toString + sig + ) && attestationType.outcomeString == outcome.toString } } diff --git a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/EventDb.scala b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/EventDb.scala index a057a2ec68..35f7f6c8ca 100644 --- a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/EventDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/EventDb.scala @@ -12,12 +12,12 @@ import org.bitcoins.crypto.{ import java.time.Instant -/** These represent individual events at the nonce level - * You can aggregate 1 to n EventDbs into an [[OracleEvent]] to get all of the information - * about a particular descriptor +/** These represent individual events at the nonce level You can aggregate 1 to + * n EventDbs into an [[OracleEvent]] to get all of the information about a + * particular descriptor * - * In the case of [[EnumEventDescriptorV0TLV]] there is only 1 [[EventDb]] - * that corresponds to the enum descriptor + * In the case of [[EnumEventDescriptorV0TLV]] there is only 1 [[EventDb]] that + * corresponds to the enum descriptor * * In the case of [[DigitDecompositionEventDescriptorV0TLV]] you have * [[DigitDecompositionEventDescriptorV0TLV.numDigits]] with an optional +1 @@ -34,7 +34,8 @@ case class EventDb( attestationOpt: Option[FieldElement], outcomeOpt: Option[String], announcementSignature: SchnorrDigitalSignature, - eventDescriptorTLV: EventDescriptorTLV) { + eventDescriptorTLV: EventDescriptorTLV +) { lazy val sigOpt: Option[SchnorrDigitalSignature] = attestationOpt.map(SchnorrDigitalSignature(nonce, _)) diff --git a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/EventOutcomeDb.scala b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/EventOutcomeDb.scala index bc29549eeb..da6e328aa7 100644 --- a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/EventOutcomeDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/EventOutcomeDb.scala @@ -7,12 +7,14 @@ import scodec.bits.ByteVector case class EventOutcomeDb( nonce: SchnorrNonce, message: String, - hashedMessage: ByteVector) + hashedMessage: ByteVector +) object EventOutcomeDbHelper { def createEnumEventDescriptor( - outcomes: Vector[EventOutcomeDb]): EnumEventDescriptorV0TLV = { + outcomes: Vector[EventOutcomeDb] + ): EnumEventDescriptorV0TLV = { val strs = outcomes.map(_.message) EnumEventDescriptorV0TLV(strs) diff --git a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/RValueDb.scala b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/RValueDb.scala index d006dcabdf..7e7ca94170 100644 --- a/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/RValueDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/dlcoracle/db/RValueDb.scala @@ -10,10 +10,12 @@ case class RValueDb( accountCoin: HDCoinType, accountIndex: Int, chainType: Int, - keyIndex: Int) { + keyIndex: Int +) { val path: BIP32Path = BIP32Path.fromString( - s"m/${purpose.constant}'/${accountCoin.toInt}'/$accountIndex'/$chainType'/$keyIndex'") + s"m/${purpose.constant}'/${accountCoin.toInt}'/$accountIndex'/$chainType'/$keyIndex'" + ) } object RValueDbHelper { @@ -23,7 +25,8 @@ object RValueDbHelper { eventName: String, account: HDAccount, chainType: Int, - keyIndex: Int): RValueDb = { + keyIndex: Int + ): RValueDb = { RValueDb( nonce = nonce, eventName = eventName, diff --git a/core/src/main/scala/org/bitcoins/core/api/keymanager/KeyManagerCreateApi.scala b/core/src/main/scala/org/bitcoins/core/api/keymanager/KeyManagerCreateApi.scala index 05d15507f6..b7dffd55ec 100644 --- a/core/src/main/scala/org/bitcoins/core/api/keymanager/KeyManagerCreateApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/keymanager/KeyManagerCreateApi.scala @@ -11,16 +11,13 @@ import scodec.bits.BitVector trait KeyManagerCreateApi /** @define initialize - * Initializes the wallet, generating a wallet seed. - * This seed should be displayed to the user, so they - * can write it down. They should also be prompted - * to confirm at least parts of the code. + * Initializes the wallet, generating a wallet seed. This seed should be + * displayed to the user, so they can write it down. They should also be + * prompted to confirm at least parts of the code. * @define initializeWithEnt - * Initializes the with a user-provided seed, - * generating a wallet seed. - * This seed should be displayed to the user, so they - * can write it down. They should also be prompted - * to confirm at least parts of the code. + * Initializes the with a user-provided seed, generating a wallet seed. This + * seed should be displayed to the user, so they can write it down. They + * should also be prompted to confirm at least parts of the code. */ trait BIP39KeyManagerCreateApi[T <: BIP39KeyManagerApi] extends KeyManagerCreateApi { @@ -30,11 +27,14 @@ trait BIP39KeyManagerCreateApi[T <: BIP39KeyManagerApi] final def initialize( aesPasswordOpt: Option[AesPassword], kmParams: KeyManagerParams, - bip39PasswordOpt: Option[String]): Either[KeyManagerInitializeError, T] = - initializeWithEntropy(aesPasswordOpt = aesPasswordOpt, - entropy = MnemonicCode.getEntropy256Bits, - bip39PasswordOpt = bip39PasswordOpt, - kmParams = kmParams) + bip39PasswordOpt: Option[String] + ): Either[KeyManagerInitializeError, T] = + initializeWithEntropy( + aesPasswordOpt = aesPasswordOpt, + entropy = MnemonicCode.getEntropy256Bits, + bip39PasswordOpt = bip39PasswordOpt, + kmParams = kmParams + ) /** $initializeWithEnt */ @@ -42,9 +42,11 @@ trait BIP39KeyManagerCreateApi[T <: BIP39KeyManagerApi] aesPasswordOpt: Option[AesPassword], entropy: BitVector, bip39PasswordOpt: Option[String], - kmParams: KeyManagerParams): Either[KeyManagerInitializeError, T] + kmParams: KeyManagerParams + ): Either[KeyManagerInitializeError, T] - /** Helper method to initialize a [[KeyManagerApi KeyManager]] with a [[MnemonicCode MnemonicCode]] + /** Helper method to initialize a [[KeyManagerApi KeyManager]] with a + * [[MnemonicCode MnemonicCode]] * * @param mnemonicCode * @param kmParams @@ -54,11 +56,14 @@ trait BIP39KeyManagerCreateApi[T <: BIP39KeyManagerApi] aesPasswordOpt: Option[AesPassword], mnemonicCode: MnemonicCode, bip39PasswordOpt: Option[String], - kmParams: KeyManagerParams): Either[KeyManagerInitializeError, T] = { + kmParams: KeyManagerParams + ): Either[KeyManagerInitializeError, T] = { val entropy = mnemonicCode.toEntropy - initializeWithEntropy(aesPasswordOpt = aesPasswordOpt, - entropy = entropy, - bip39PasswordOpt = bip39PasswordOpt, - kmParams = kmParams) + initializeWithEntropy( + aesPasswordOpt = aesPasswordOpt, + entropy = entropy, + bip39PasswordOpt = bip39PasswordOpt, + kmParams = kmParams + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/api/node/NodeApi.scala b/core/src/main/scala/org/bitcoins/core/api/node/NodeApi.scala index af063e1388..5c2477cecd 100644 --- a/core/src/main/scala/org/bitcoins/core/api/node/NodeApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/node/NodeApi.scala @@ -18,7 +18,8 @@ trait NodeApi { */ def broadcastTransactions(transactions: Vector[Transaction]): Future[Unit] - /** Request the underlying node to download the given blocks from its peers and feed the blocks to [[org.bitcoins.node.NodeCallbacks]]. + /** Request the underlying node to download the given blocks from its peers + * and feed the blocks to [[org.bitcoins.node.NodeCallbacks]]. */ def downloadBlocks(blockHashes: Vector[DoubleSha256DigestBE]): Future[Unit] diff --git a/core/src/main/scala/org/bitcoins/core/api/node/Peer.scala b/core/src/main/scala/org/bitcoins/core/api/node/Peer.scala index b39845cdf8..15ae83208e 100644 --- a/core/src/main/scala/org/bitcoins/core/api/node/Peer.scala +++ b/core/src/main/scala/org/bitcoins/core/api/node/Peer.scala @@ -26,13 +26,15 @@ object Peer { def fromSocket( socket: InetSocketAddress, - socks5ProxyParams: Option[Socks5ProxyParams]): Peer = { + socks5ProxyParams: Option[Socks5ProxyParams] + ): Peer = { Peer(socket, socks5ProxyParams = socks5ProxyParams) } def fromURI( uri: URI, - socks5ProxyParamsOpt: Option[Socks5ProxyParams]): Peer = { + socks5ProxyParamsOpt: Option[Socks5ProxyParams] + ): Peer = { val socket = new InetSocketAddress(uri.getHost, uri.getPort) fromSocket(socket, socks5ProxyParamsOpt) } diff --git a/core/src/main/scala/org/bitcoins/core/api/node/PeerManagerApi.scala b/core/src/main/scala/org/bitcoins/core/api/node/PeerManagerApi.scala index 68f0247099..d6d32f2690 100644 --- a/core/src/main/scala/org/bitcoins/core/api/node/PeerManagerApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/node/PeerManagerApi.scala @@ -7,7 +7,9 @@ import scala.concurrent.Future trait PeerManagerApi { - /** Peers we are currently connected too and have completed the version/verack handshake with */ + /** Peers we are currently connected too and have completed the version/verack + * handshake with + */ def peers: Set[Peer] def disconnectPeer(peer: Peer): Future[Unit] @@ -20,14 +22,20 @@ trait PeerManagerApi { def isInitialized(peer: Peer): Future[Boolean] - /** Gossips the given message to all peers except the excluded peer. If None given as excluded peer, gossip message to all peers */ + /** Gossips the given message to all peers except the excluded peer. If None + * given as excluded peer, gossip message to all peers + */ def gossipMessage( msg: NetworkPayload, - excludedPeerOpt: Option[Peer]): Future[Unit] + excludedPeerOpt: Option[Peer] + ): Future[Unit] - /** Gossips the [[org.bitcoins.core.p2p.GetHeadersMessage]] to all of our peers to attempt ot get the best block headers */ + /** Gossips the [[org.bitcoins.core.p2p.GetHeadersMessage]] to all of our + * peers to attempt ot get the best block headers + */ def gossipGetHeadersMessage( - hashes: Vector[DoubleSha256DigestBE]): Future[Unit] + hashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] def sendToRandomPeer(payload: NetworkPayload): Future[Unit] } diff --git a/core/src/main/scala/org/bitcoins/core/api/tor/Socks5ProxyParams.scala b/core/src/main/scala/org/bitcoins/core/api/tor/Socks5ProxyParams.scala index 4e5023a451..2a3578ab7a 100644 --- a/core/src/main/scala/org/bitcoins/core/api/tor/Socks5ProxyParams.scala +++ b/core/src/main/scala/org/bitcoins/core/api/tor/Socks5ProxyParams.scala @@ -7,7 +7,8 @@ import java.net.InetSocketAddress case class Socks5ProxyParams( address: InetSocketAddress, credentialsOpt: Option[Credentials], - randomizeCredentials: Boolean) + randomizeCredentials: Boolean +) object Socks5ProxyParams { @@ -17,14 +18,18 @@ object Socks5ProxyParams { new Socks5ProxyParams( address = InetSocketAddress.createUnresolved("127.0.0.1", DefaultPort), credentialsOpt = None, - randomizeCredentials = true) + randomizeCredentials = true + ) def proxyCredentials(proxyParams: Socks5ProxyParams): Option[Credentials] = if (proxyParams.randomizeCredentials) { // randomize credentials for every proxy connection to enable Tor stream isolation Some( - Credentials(CryptoUtil.randomBytes(16).toHex, - CryptoUtil.randomBytes(16).toHex)) + Credentials( + CryptoUtil.randomBytes(16).toHex, + CryptoUtil.randomBytes(16).toHex + ) + ) } else { proxyParams.credentialsOpt } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/AddressInfo.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/AddressInfo.scala index fd176048af..b014c2192c 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/AddressInfo.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/AddressInfo.scala @@ -4,10 +4,11 @@ import org.bitcoins.core.config.NetworkParameters import org.bitcoins.core.hd.HDPath import org.bitcoins.crypto.ECPublicKey -/** This class represents the result of querying for address info - * from our wallet +/** This class represents the result of querying for address info from our + * wallet */ case class AddressInfo( pubkey: ECPublicKey, network: NetworkParameters, - path: HDPath) + path: HDPath +) diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelectionAlgo.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelectionAlgo.scala index 80e98b88c0..607119d953 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelectionAlgo.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelectionAlgo.scala @@ -12,19 +12,24 @@ object CoinSelectionAlgo extends StringFactory[CoinSelectionAlgo] { */ final case object RandomSelection extends CoinSelectionAlgo - /** Greedily selects from walletUtxos starting with the largest outputs, skipping outputs with values - * below their fees. Better for high fee environments than accumulateSmallestViable. + /** Greedily selects from walletUtxos starting with the largest outputs, + * skipping outputs with values below their fees. Better for high fee + * environments than accumulateSmallestViable. */ final case object AccumulateLargest extends CoinSelectionAlgo - /** Greedily selects from walletUtxos starting with the smallest outputs, skipping outputs with values - * below their fees. Good for low fee environments to consolidate UTXOs. + /** Greedily selects from walletUtxos starting with the smallest outputs, + * skipping outputs with values below their fees. Good for low fee + * environments to consolidate UTXOs. * - * Has the potential privacy breach of connecting a ton of UTXOs to one address. + * Has the potential privacy breach of connecting a ton of UTXOs to one + * address. */ final case object AccumulateSmallestViable extends CoinSelectionAlgo - /** Greedily selects from walletUtxos in order, skipping outputs with values below their fees */ + /** Greedily selects from walletUtxos in order, skipping outputs with values + * below their fees + */ final case object StandardAccumulate extends CoinSelectionAlgo /** Tries all coin selection algos and uses the one with the least waste */ @@ -35,10 +40,12 @@ object CoinSelectionAlgo extends StringFactory[CoinSelectionAlgo] { /** Coin selection algos that don't call other ones */ val independentAlgos: Vector[CoinSelectionAlgo] = - Vector(RandomSelection, - AccumulateLargest, - AccumulateSmallestViable, - StandardAccumulate) + Vector( + RandomSelection, + AccumulateLargest, + AccumulateSmallestViable, + StandardAccumulate + ) /** Coin selection algos that call upon other ones and choose the best */ val multiCoinSelectionAlgos: Vector[CoinSelectionAlgo] = Vector(LeastWaste) @@ -53,6 +60,7 @@ object CoinSelectionAlgo extends StringFactory[CoinSelectionAlgo] { override def fromString(string: String): CoinSelectionAlgo = { val algoOpt = fromStringOpt(string) algoOpt.getOrElse( - sys.error(s"Could not find coin selection algorithm=${string}")) + sys.error(s"Could not find coin selection algorithm=${string}") + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelector.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelector.scala index bbfd831c83..ce0565b6e8 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelector.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelector.scala @@ -9,7 +9,9 @@ import org.bitcoins.core.wallet.fee.FeeUnit import scala.annotation.tailrec import scala.util.{Random, Try} -/** Implements algorithms for selecting from a UTXO set to spend to an output set at a given fee rate. */ +/** Implements algorithms for selecting from a UTXO set to spend to an output + * set at a given fee rate. + */ trait CoinSelector { /** Randomly selects utxos until it has enough to fund the desired amount, @@ -18,44 +20,53 @@ trait CoinSelector { def randomSelection( walletUtxos: Vector[CoinSelectorUtxo], outputs: Vector[TransactionOutput], - feeRate: FeeUnit): Vector[CoinSelectorUtxo] = { + feeRate: FeeUnit + ): Vector[CoinSelectorUtxo] = { val randomUtxos = Random.shuffle(walletUtxos) accumulate(randomUtxos, outputs, feeRate) } - /** Greedily selects from walletUtxos starting with the largest outputs, skipping outputs with values - * below their fees. Better for high fee environments than accumulateSmallestViable. + /** Greedily selects from walletUtxos starting with the largest outputs, + * skipping outputs with values below their fees. Better for high fee + * environments than accumulateSmallestViable. */ def accumulateLargest( walletUtxos: Vector[CoinSelectorUtxo], outputs: Vector[TransactionOutput], - feeRate: FeeUnit): Vector[CoinSelectorUtxo] = { + feeRate: FeeUnit + ): Vector[CoinSelectorUtxo] = { val sortedUtxos = walletUtxos.sortBy(_.prevOut.value).reverse accumulate(sortedUtxos, outputs, feeRate) } - /** Greedily selects from walletUtxos starting with the smallest outputs, skipping outputs with values - * below their fees. Good for low fee environments to consolidate UTXOs. + /** Greedily selects from walletUtxos starting with the smallest outputs, + * skipping outputs with values below their fees. Good for low fee + * environments to consolidate UTXOs. * - * Has the potential privacy breach of connecting a ton of UTXOs to one address. + * Has the potential privacy breach of connecting a ton of UTXOs to one + * address. */ def accumulateSmallestViable( walletUtxos: Vector[CoinSelectorUtxo], outputs: Vector[TransactionOutput], - feeRate: FeeUnit): Vector[CoinSelectorUtxo] = { + feeRate: FeeUnit + ): Vector[CoinSelectorUtxo] = { val sortedUtxos = walletUtxos.sortBy(_.prevOut.value) accumulate(sortedUtxos, outputs, feeRate) } - /** Greedily selects from walletUtxos in order, skipping outputs with values below their fees */ + /** Greedily selects from walletUtxos in order, skipping outputs with values + * below their fees + */ def accumulate( walletUtxos: Vector[CoinSelectorUtxo], outputs: Vector[TransactionOutput], - feeRate: FeeUnit): Vector[CoinSelectorUtxo] = { + feeRate: FeeUnit + ): Vector[CoinSelectorUtxo] = { val totalValue = outputs.foldLeft(CurrencyUnits.zero) { case (totVal, output) => totVal + output.value } @@ -65,13 +76,15 @@ trait CoinSelector { alreadyAdded: Vector[CoinSelectorUtxo], valueSoFar: CurrencyUnit, bytesSoFar: Long, - utxosLeft: Vector[CoinSelectorUtxo]): Vector[CoinSelectorUtxo] = { + utxosLeft: Vector[CoinSelectorUtxo] + ): Vector[CoinSelectorUtxo] = { val fee = feeRate * bytesSoFar if (valueSoFar > totalValue + fee) { alreadyAdded } else if (utxosLeft.isEmpty) { throw new RuntimeException( - s"Not enough value in given outputs ($valueSoFar) to make transaction spending $totalValue plus fees $fee") + s"Not enough value in given outputs ($valueSoFar) to make transaction spending $totalValue plus fees $fee" + ) } else { val nextUtxo = utxosLeft.head val effectiveValue = calcEffectiveValue(nextUtxo, feeRate) @@ -82,10 +95,12 @@ trait CoinSelector { val newValue = valueSoFar + nextUtxo.prevOut.value val approxUtxoSize = CoinSelector.approximateUtxoSize(nextUtxo) - addUtxos(newAdded, - newValue, - bytesSoFar + approxUtxoSize, - utxosLeft.tail) + addUtxos( + newAdded, + newValue, + bytesSoFar + approxUtxoSize, + utxosLeft.tail + ) } } } @@ -95,14 +110,16 @@ trait CoinSelector { def calculateUtxoFee( utxo: CoinSelectorUtxo, - feeRate: FeeUnit): CurrencyUnit = { + feeRate: FeeUnit + ): CurrencyUnit = { val approxUtxoSize = CoinSelector.approximateUtxoSize(utxo) feeRate * approxUtxoSize } def calcEffectiveValue( utxo: CoinSelectorUtxo, - feeRate: FeeUnit): CurrencyUnit = { + feeRate: FeeUnit + ): CurrencyUnit = { val utxoFee = calculateUtxoFee(utxo, feeRate) utxo.prevOut.value - utxoFee } @@ -110,7 +127,9 @@ trait CoinSelector { object CoinSelector extends CoinSelector { - /** Cribbed from [[https://github.com/bitcoinjs/coinselect/blob/master/utils.js]] */ + /** Cribbed from + * [[https://github.com/bitcoinjs/coinselect/blob/master/utils.js]] + */ def approximateUtxoSize(utxo: CoinSelectorUtxo): Long = { val inputBase = 32 + 4 + 1 + 4 val scriptSize = utxo.redeemScriptOpt match { @@ -120,9 +139,9 @@ object CoinSelector extends CoinSelector { case Some(script) => script.bytes.length case None => utxo.prevOut.scriptPubKey match { - case _: NonWitnessScriptPubKey => 107 // P2PKH - case _: WitnessScriptPubKeyV0 => 107 // P2WPKH - case _: TaprootScriptPubKey => 64 // Single Schnorr signature + case _: NonWitnessScriptPubKey => 107 // P2PKH + case _: WitnessScriptPubKeyV0 => 107 // P2WPKH + case _: TaprootScriptPubKey => 64 // Single Schnorr signature case _: UnassignedWitnessScriptPubKey => 0 // unknown } } @@ -136,7 +155,8 @@ object CoinSelector extends CoinSelector { walletUtxos: Vector[CoinSelectorUtxo], outputs: Vector[TransactionOutput], feeRate: FeeUnit, - longTermFeeRateOpt: Option[FeeUnit] = None): Vector[CoinSelectorUtxo] = + longTermFeeRateOpt: Option[FeeUnit] = None + ): Vector[CoinSelectorUtxo] = coinSelectionAlgo match { case RandomSelection => randomSelection(walletUtxos, outputs, feeRate) @@ -152,7 +172,8 @@ object CoinSelector extends CoinSelector { selectByLeastWaste(walletUtxos, outputs, feeRate, longTermFeeRate) case None => throw new IllegalArgumentException( - "longTermFeeRateOpt must be defined for LeastWaste") + "longTermFeeRateOpt must be defined for LeastWaste" + ) } case SelectedUtxos(outPoints) => val result = walletUtxos.foldLeft(Vector.empty[CoinSelectorUtxo]) { @@ -167,7 +188,8 @@ object CoinSelector extends CoinSelector { utxo.outPoint.txId == outPoint._1 && utxo.outPoint.vout.toInt == outPoint._2) ) throw new IllegalArgumentException( - s"Unknown UTXO: ${outPoint._1}:${outPoint._2}") + s"Unknown UTXO: ${outPoint._1}:${outPoint._2}" + ) } } else if (result.size > outPoints.size) { throw new IllegalArgumentException(s"Found too many UTXOs") @@ -178,10 +200,11 @@ object CoinSelector extends CoinSelector { private case class CoinSelectionResults( waste: CurrencyUnit, totalSpent: CurrencyUnit, - selection: Vector[CoinSelectorUtxo]) + selection: Vector[CoinSelectorUtxo] + ) - implicit - private val coinSelectionResultsOrder: Ordering[CoinSelectionResults] = { + implicit private val coinSelectionResultsOrder + : Ordering[CoinSelectionResults] = { case (a: CoinSelectionResults, b: CoinSelectionResults) => if (a.waste == b.waste) { a.selection.size.compare(b.selection.size) @@ -199,21 +222,25 @@ object CoinSelector extends CoinSelector { // Skip failed selection attempts Try { val selection = - selectByAlgo(algo, - walletUtxos, - outputs, - feeRate, - Some(longTermFeeRate)) + selectByAlgo( + algo, + walletUtxos, + outputs, + feeRate, + Some(longTermFeeRate) + ) // todo for now just use 1 sat, when we have more complex selection algos // that just don't result in change (Branch and Bound), this will need to be calculated val changeCostOpt = Some(Satoshis.one) - val waste = calculateSelectionWaste(selection, - changeCostOpt, - target, - feeRate, - longTermFeeRate) + val waste = calculateSelectionWaste( + selection, + changeCostOpt, + target, + feeRate, + longTermFeeRate + ) val totalSpent = selection.map(_.prevOut.value).sum CoinSelectionResults(waste, totalSpent, selection) @@ -222,36 +249,47 @@ object CoinSelector extends CoinSelector { require( results.nonEmpty, - s"Not enough value in given outputs to make transaction spending $target plus fees") + s"Not enough value in given outputs to make transaction spending $target plus fees" + ) results.min.selection } - /** Compute the waste for this result given the cost of change - * and the opportunity cost of spending these inputs now vs in the future. - * If change exists, waste = changeCost + inputs * (effective_feerate - long_term_feerate) - * If no change, waste = excess + inputs * (effective_feerate - long_term_feerate) - * where excess = totalEffectiveValue - target - * change_cost = effective_feerate * change_output_size + long_term_feerate * change_spend_size + /** Compute the waste for this result given the cost of change and the + * opportunity cost of spending these inputs now vs in the future. If change + * exists, waste = changeCost + inputs * (effective_feerate - + * long_term_feerate) If no change, waste = excess + inputs * + * (effective_feerate - long_term_feerate) where excess = totalEffectiveValue + * \- target change_cost = effective_feerate * change_output_size + + * long_term_feerate * change_spend_size * * Copied from - * @see https://github.com/achow101/bitcoin/blob/4f5ad43b1e05cd7b403f87aae4c4d42e5aea810b/src/wallet/coinselection.cpp#L345 + * @see + * https://github.com/achow101/bitcoin/blob/4f5ad43b1e05cd7b403f87aae4c4d42e5aea810b/src/wallet/coinselection.cpp#L345 * - * @param utxos The selected inputs - * @param changeCostOpt The cost of creating change and spending it in the future. None if there is no change. - * @param target The amount targeted by the coin selection algorithm. - * @param longTermFeeRate The expected average fee rate used over the long term - * @return The waste + * @param utxos + * The selected inputs + * @param changeCostOpt + * The cost of creating change and spending it in the future. None if there + * is no change. + * @param target + * The amount targeted by the coin selection algorithm. + * @param longTermFeeRate + * The expected average fee rate used over the long term + * @return + * The waste */ def calculateSelectionWaste( utxos: Vector[CoinSelectorUtxo], changeCostOpt: Option[CurrencyUnit], target: CurrencyUnit, feeRate: FeeUnit, - longTermFeeRate: FeeUnit): CurrencyUnit = { + longTermFeeRate: FeeUnit + ): CurrencyUnit = { require( utxos.nonEmpty, - "This function should not be called with empty inputs as that would mean the selection failed") + "This function should not be called with empty inputs as that would mean the selection failed" + ) val (waste, selectedEffectiveValue) = utxos.foldLeft((CurrencyUnits.zero, CurrencyUnits.zero)) { @@ -271,8 +309,10 @@ object CoinSelector extends CoinSelector { case Some(changeCost) => // Consider the cost of making change and spending it in the future // If we aren't making change, the caller should've set changeCost to 0 - require(changeCost > Satoshis.zero, - "Cannot have a change cost less than 1") + require( + changeCost > Satoshis.zero, + "Cannot have a change cost less than 1" + ) waste + changeCost case None => // When we are not making change (changeCost == 0), consider the excess we are throwing away to fees diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelectorUtxo.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelectorUtxo.scala index 261df289b9..11a13a1d5c 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelectorUtxo.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/CoinSelectorUtxo.scala @@ -8,14 +8,17 @@ case class CoinSelectorUtxo( prevOut: TransactionOutput, outPoint: TransactionOutPoint, redeemScriptOpt: Option[ScriptPubKey], - scriptWitnessOpt: Option[ScriptWitness]) + scriptWitnessOpt: Option[ScriptWitness] +) object CoinSelectorUtxo { def fromSpendingInfoDb(db: SpendingInfoDb): CoinSelectorUtxo = { - CoinSelectorUtxo(db.output, - db.outPoint, - db.redeemScriptOpt, - db.scriptWitnessOpt) + CoinSelectorUtxo( + db.output, + db.outPoint, + db.redeemScriptOpt, + db.scriptWitnessOpt + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/HDWalletApi.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/HDWalletApi.scala index 24f8477d45..4e84a1ee7f 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/HDWalletApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/HDWalletApi.scala @@ -25,15 +25,17 @@ import scala.concurrent.{ExecutionContext, Future} * * This wallet API is BIP44 compliant. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]] */ trait HDWalletApi extends WalletApi { override def keyManager: BIP39KeyManagerApi /** Gets the balance of the given account */ - def getBalance(account: HDAccount)(implicit - ec: ExecutionContext): Future[CurrencyUnit] = { + def getBalance( + account: HDAccount + )(implicit ec: ExecutionContext): Future[CurrencyUnit] = { val confirmedF = getConfirmedBalance(account) val unconfirmedF = getUnconfirmedBalance(account) for { @@ -56,7 +58,8 @@ trait HDWalletApi extends WalletApi { def getNewChangeAddress(account: AccountDb): Future[BitcoinAddress] override def getNewChangeAddress()(implicit - ec: ExecutionContext): Future[BitcoinAddress] = { + ec: ExecutionContext + ): Future[BitcoinAddress] = { for { account <- getDefaultAccount() addr <- getNewChangeAddress(account) @@ -64,7 +67,8 @@ trait HDWalletApi extends WalletApi { } /** Fetches the default account from the DB - * @return Future[AccountDb] + * @return + * Future[AccountDb] */ def getDefaultAccount(): Future[AccountDb] @@ -79,16 +83,16 @@ trait HDWalletApi extends WalletApi { feeRate: FeeUnit, algo: CoinSelectionAlgo, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] def sendWithAlgo( address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, algo: CoinSelectionAlgo, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = sendWithAlgo(address, amount, feeRate, algo, fromAccount, Vector.empty) def sendWithAlgo( @@ -96,8 +100,8 @@ trait HDWalletApi extends WalletApi { amount: CurrencyUnit, feeRateOpt: Option[FeeUnit], algo: CoinSelectionAlgo, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = { + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- sendWithAlgo(address, amount, feeRate, algo, fromAccount) @@ -108,8 +112,8 @@ trait HDWalletApi extends WalletApi { address: BitcoinAddress, amount: CurrencyUnit, feeRateOpt: Option[FeeUnit], - algo: CoinSelectionAlgo)(implicit - ec: ExecutionContext): Future[Transaction] = { + algo: CoinSelectionAlgo + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendWithAlgo(address, amount, feeRateOpt, algo, account) @@ -120,8 +124,8 @@ trait HDWalletApi extends WalletApi { address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - algo: CoinSelectionAlgo)(implicit - ec: ExecutionContext): Future[Transaction] = { + algo: CoinSelectionAlgo + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendWithAlgo(address, amount, feeRate, algo, account) @@ -133,8 +137,8 @@ trait HDWalletApi extends WalletApi { amount: CurrencyUnit, feeRate: FeeUnit, algo: CoinSelectionAlgo, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = { + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendWithAlgo(address, amount, feeRate, algo, account, newTags) @@ -151,30 +155,32 @@ trait HDWalletApi extends WalletApi { amount: CurrencyUnit, feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = - sendFromOutPoints(outPoints, - address, - amount, - feeRate, - fromAccount, - Vector.empty) + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = + sendFromOutPoints( + outPoints, + address, + amount, + feeRate, + fromAccount, + Vector.empty + ) def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, amount: CurrencyUnit, feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = { + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- sendFromOutPoints(outPoints, address, amount, feeRate, fromAccount) @@ -197,7 +203,8 @@ trait HDWalletApi extends WalletApi { outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, amount: CurrencyUnit, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = { + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendFromOutPoints(outPoints, address, amount, feeRate, account) @@ -209,8 +216,8 @@ trait HDWalletApi extends WalletApi { address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = { + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- @@ -227,23 +234,23 @@ trait HDWalletApi extends WalletApi { amount: CurrencyUnit, feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = sendToAddress(address, amount, feeRate, fromAccount, Vector.empty) def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = { + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- sendToAddress(address, amount, feeRate, fromAccount) @@ -264,7 +271,8 @@ trait HDWalletApi extends WalletApi { override def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = { + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendToAddress(address, amount, feeRate, account) @@ -275,8 +283,8 @@ trait HDWalletApi extends WalletApi { address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = { + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendToAddress(address, amount, feeRate, account, newTags) @@ -292,23 +300,23 @@ trait HDWalletApi extends WalletApi { amounts: Vector[CurrencyUnit], feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = sendToAddresses(addresses, amounts, feeRate, fromAccount, Vector.empty) def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = { + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- sendToAddresses(addresses, amounts, feeRate, fromAccount) @@ -329,7 +337,8 @@ trait HDWalletApi extends WalletApi { override def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = { + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendToAddresses(addresses, amounts, feeRate, account) @@ -340,8 +349,8 @@ trait HDWalletApi extends WalletApi { addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], feeRate: FeeUnit, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = { + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendToAddresses(addresses, amounts, feeRate, account, newTags) @@ -356,21 +365,21 @@ trait HDWalletApi extends WalletApi { outputs: Vector[TransactionOutput], feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] def sendToOutputs( outputs: Vector[TransactionOutput], feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = sendToOutputs(outputs, feeRate, fromAccount, Vector.empty) def sendToOutputs( outputs: Vector[TransactionOutput], feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = { + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- sendToOutputs(outputs, feeRate, fromAccount) @@ -380,8 +389,8 @@ trait HDWalletApi extends WalletApi { def sendToOutputs( outputs: Vector[TransactionOutput], feeRate: FeeUnit, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = { + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendToOutputs(outputs, feeRate, account, newTags) @@ -400,7 +409,8 @@ trait HDWalletApi extends WalletApi { override def sendToOutputs( outputs: Vector[TransactionOutput], - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = { + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- sendToOutputs(outputs, feeRate, account) @@ -413,15 +423,15 @@ trait HDWalletApi extends WalletApi { message: String, hashMessage: Boolean, feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] def makeOpReturnCommitment( message: String, hashMessage: Boolean, feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = { + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- makeOpReturnCommitment(message, hashMessage, feeRate, fromAccount) @@ -431,7 +441,8 @@ trait HDWalletApi extends WalletApi { override def makeOpReturnCommitment( message: String, hashMessage: Boolean, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = { + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = { for { account <- getDefaultAccount() tx <- makeOpReturnCommitment(message, hashMessage, feeRate, account) @@ -444,18 +455,21 @@ trait HDWalletApi extends WalletApi { def listUtxos( hdAccount: HDAccount, - tag: AddressTag): Future[Vector[SpendingInfoDb]] + tag: AddressTag + ): Future[Vector[SpendingInfoDb]] def listUtxos( hdAccount: HDAccount, - state: TxoState): Future[Vector[SpendingInfoDb]] + state: TxoState + ): Future[Vector[SpendingInfoDb]] def listAddresses(account: HDAccount): Future[Vector[AddressDb]] def listSpentAddresses(account: HDAccount): Future[Vector[AddressDb]] def listFundedAddresses( - account: HDAccount): Future[Vector[(AddressDb, CurrencyUnit)]] + account: HDAccount + ): Future[Vector[(AddressDb, CurrencyUnit)]] def listUnusedAddresses(account: HDAccount): Future[Vector[AddressDb]] @@ -463,48 +477,51 @@ trait HDWalletApi extends WalletApi { def clearUtxos(account: HDAccount): Future[HDWalletApi] - /** Gets the address associated with the pubkey at - * the resulting `BIP32Path` determined by the - * default account and the given chainType and addressIndex + /** Gets the address associated with the pubkey at the resulting `BIP32Path` + * determined by the default account and the given chainType and addressIndex */ def getAddress(chainType: HDChainType, addressIndex: Int)(implicit - ec: ExecutionContext): Future[AddressDb] = { + ec: ExecutionContext + ): Future[AddressDb] = { for { account <- getDefaultAccount() address <- getAddress(account, chainType, addressIndex) } yield address } - /** Gets the address associated with the pubkey at - * the resulting `BIP32Path` determined the given - * account, chainType, and addressIndex + /** Gets the address associated with the pubkey at the resulting `BIP32Path` + * determined the given account, chainType, and addressIndex */ def getAddress( account: AccountDb, chainType: HDChainType, - addressIndex: Int): Future[AddressDb] + addressIndex: Int + ): Future[AddressDb] def listAccounts(): Future[Vector[AccountDb]] /** Lists all wallet accounts with the given type * @param purpose - * @return [[Future[Vector[AccountDb]] + * @return + * [[Future[Vector[AccountDb]] */ def listAccounts(purpose: HDPurpose)(implicit - ec: ExecutionContext): Future[Vector[AccountDb]] = + ec: ExecutionContext + ): Future[Vector[AccountDb]] = listAccounts().map(_.filter(_.hdAccount.purpose == purpose)) def createNewAccount(keyManagerParams: KeyManagerParams): Future[HDWalletApi] - /** Tries to create a new account in this wallet. Fails if the - * most recent account has no transaction history, as per - * BIP44 + /** Tries to create a new account in this wallet. Fails if the most recent + * account has no transaction history, as per BIP44 * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account BIP44 account section]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account BIP44 account section]] */ def createNewAccount( hdAccount: HDAccount, - keyManagerParams: KeyManagerParams): Future[HDWalletApi] + keyManagerParams: KeyManagerParams + ): Future[HDWalletApi] def findAccount(account: HDAccount): Future[Option[AccountDb]] @@ -512,6 +529,6 @@ trait HDWalletApi extends WalletApi { destinations: Vector[TransactionOutput], feeRate: FeeUnit, fromAccount: AccountDb, - markAsReserved: Boolean): Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] + markAsReserved: Boolean + ): Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/NeutrinoWalletApi.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/NeutrinoWalletApi.scala index d26e711011..b5c78ebca1 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/NeutrinoWalletApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/NeutrinoWalletApi.scala @@ -11,50 +11,65 @@ trait NeutrinoWalletApi { self: WalletApi => def processCompactFilter( blockHash: DoubleSha256DigestBE, - blockFilter: GolombFilter): Future[NeutrinoHDWalletApi] = + blockFilter: GolombFilter + ): Future[NeutrinoHDWalletApi] = processCompactFilters(Vector((blockHash, blockFilter))) def processCompactFilters( - blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)]): Future[ - NeutrinoHDWalletApi] + blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)] + ): Future[NeutrinoHDWalletApi] /** Recreates the account using BIP-157 approach * - * DANGER! This method removes all records from the wallet database - * and creates new ones while the account discovery process. + * DANGER! This method removes all records from the wallet database and + * creates new ones while the account discovery process. * - * The Wallet UI should check if the database is empty before calling - * this method and let the end users to decide whether they want to proceed or not. + * The Wallet UI should check if the database is empty before calling this + * method and let the end users to decide whether they want to proceed or + * not. * - * This method generates [[addressBatchSize]] of addresses, then matches them against the BIP-158 compact filters, - * and downloads and processes the matched blocks. This method keeps doing the steps until there are [[WalletConfig.addressGapLimit]] - * or more unused addresses in a row. In this case it considers the discovery process completed. + * This method generates [[addressBatchSize]] of addresses, then matches them + * against the BIP-158 compact filters, and downloads and processes the + * matched blocks. This method keeps doing the steps until there are + * [[WalletConfig.addressGapLimit]] or more unused addresses in a row. In + * this case it considers the discovery process completed. * - * [[addressBatchSize]] - the number of addresses we should generate from a keychain to attempt to match in in a rescan - * [[WalletConfig.addressGapLimit]] - the number of addresses required to go without a match before we determine that our wallet is "discovered". - * For instance, if addressBatchSize=100, and AddressGapLimit=20 we do a rescan and the last address we find containing - * funds is at index 75, we would not generate more addresses to try and rescan. However if the last index containing - * funds was 81, we would generate another 100 addresses from the keychain and attempt to rescan those. + * [[addressBatchSize]] - the number of addresses we should generate from a + * keychain to attempt to match in in a rescan + * [[WalletConfig.addressGapLimit]] - the number of addresses required to go + * without a match before we determine that our wallet is "discovered". For + * instance, if addressBatchSize=100, and AddressGapLimit=20 we do a rescan + * and the last address we find containing funds is at index 75, we would not + * generate more addresses to try and rescan. However if the last index + * containing funds was 81, we would generate another 100 addresses from the + * keychain and attempt to rescan those. * - * @param startOpt start block (if None it starts from the genesis block) - * @param endOpt end block (if None it ends at the current tip) - * @param addressBatchSize how many addresses to match in a single pass + * @param startOpt + * start block (if None it starts from the genesis block) + * @param endOpt + * end block (if None it ends at the current tip) + * @param addressBatchSize + * how many addresses to match in a single pass */ def rescanNeutrinoWallet( startOpt: Option[BlockStamp], endOpt: Option[BlockStamp], addressBatchSize: Int, useCreationTime: Boolean, - force: Boolean)(implicit ec: ExecutionContext): Future[RescanState] + force: Boolean + )(implicit ec: ExecutionContext): Future[RescanState] /** Helper method to rescan the ENTIRE blockchain. */ def fullRescanNeutrinoWallet(addressBatchSize: Int, force: Boolean = false)( - implicit ec: ExecutionContext): Future[RescanState] = - rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = addressBatchSize, - useCreationTime = false, - force = force) + implicit ec: ExecutionContext + ): Future[RescanState] = + rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = addressBatchSize, + useCreationTime = false, + force = force + ) def discoveryBatchSize(): Int @@ -64,6 +79,7 @@ object NeutrinoWalletApi { case class BlockMatchingResponse( blockHash: DoubleSha256DigestBE, - blockHeight: Int) + blockHeight: Int + ) } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/ProcessTxResult.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/ProcessTxResult.scala index 145f31e486..787f5e3c54 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/ProcessTxResult.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/ProcessTxResult.scala @@ -4,4 +4,5 @@ import org.bitcoins.core.api.wallet.db.SpendingInfoDb case class ProcessTxResult( updatedIncoming: Vector[SpendingInfoDb], - updatedOutgoing: Vector[SpendingInfoDb]) + updatedOutgoing: Vector[SpendingInfoDb] +) diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/WalletApi.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/WalletApi.scala index d95f0faaee..ab3c8eb410 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/WalletApi.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/WalletApi.scala @@ -39,7 +39,8 @@ import scala.util.{Failure, Success} * * This wallet API is BIP44 compliant. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]] */ trait WalletApi extends StartStopAsync[WalletApi] { @@ -57,26 +58,29 @@ trait WalletApi extends StartStopAsync[WalletApi] { def stop(): Future[WalletApi] - /** Processes the given transaction, updating our DB state if it's relevant to us. - * @param transaction The transaction we're processing - * @param blockHash Containing block hash + /** Processes the given transaction, updating our DB state if it's relevant to + * us. + * @param transaction + * The transaction we're processing + * @param blockHash + * Containing block hash */ def processTransaction( transaction: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE]): Future[WalletApi] + blockHashOpt: Option[DoubleSha256DigestBE] + ): Future[WalletApi] def processTransactions( transactions: Vector[Transaction], - blockHashOpt: Option[DoubleSha256DigestBE])(implicit - ec: ExecutionContext): Future[WalletApi] = { + blockHashOpt: Option[DoubleSha256DigestBE] + )(implicit ec: ExecutionContext): Future[WalletApi] = { transactions.foldLeft(Future.successful(this)) { case (wallet, tx) => wallet.flatMap(_.processTransaction(tx, blockHashOpt)) } } - /** Processes TXs originating from our wallet. - * This is called right after we've signed a TX, - * updating our UTXO state. + /** Processes TXs originating from our wallet. This is called right after + * we've signed a TX, updating our UTXO state. */ def processOurTransaction( transaction: Transaction, @@ -84,30 +88,34 @@ trait WalletApi extends StartStopAsync[WalletApi] { inputAmount: CurrencyUnit, sentAmount: CurrencyUnit, blockHashOpt: Option[DoubleSha256DigestBE], - newTags: Vector[AddressTag]): Future[ProcessTxResult] + newTags: Vector[AddressTag] + ): Future[ProcessTxResult] /** Processes the give block, updating our DB state if it's relevant to us. * - * @param block The block we're processing + * @param block + * The block we're processing */ def processBlock(block: Block): Future[WalletApi] def findTransaction(txId: DoubleSha256DigestBE): Future[Option[TransactionDb]] /** Funds a transaction from the wallet. - * @return funded transaction send funds to desinations with the given fee rate + * @return + * funded transaction send funds to desinations with the given fee rate */ def fundRawTransaction( destinations: Vector[TransactionOutput], feeRate: FeeUnit, fromTagOpt: Option[AddressTag], - markAsReserved: Boolean): Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] + markAsReserved: Boolean + ): Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] def listTransactions(): Future[Vector[TransactionDb]] /** Takes in a block header and updates our TxoStates to the new chain tip - * @param blockHeader Block header we are processing + * @param blockHeader + * Block header we are processing */ def updateUtxoPendingStates(): Future[Vector[SpendingInfoDb]] @@ -123,8 +131,9 @@ trait WalletApi extends StartStopAsync[WalletApi] { } /** Gets the sum of all UTXOs in this wallet with the address tag */ - def getBalance(tag: AddressTag)(implicit - ec: ExecutionContext): Future[CurrencyUnit] = { + def getBalance( + tag: AddressTag + )(implicit ec: ExecutionContext): Future[CurrencyUnit] = { val confirmedF = getConfirmedBalance(tag) val unconfirmedF = getUnconfirmedBalance(tag) @@ -145,7 +154,8 @@ trait WalletApi extends StartStopAsync[WalletApi] { def getUnconfirmedBalance(tag: AddressTag): Future[CurrencyUnit] /** Lists unspent transaction outputs in the wallet - * @return Vector[SpendingInfoDb] + * @return + * Vector[SpendingInfoDb] */ def listUtxos(): Future[Vector[SpendingInfoDb]] @@ -166,73 +176,75 @@ trait WalletApi extends StartStopAsync[WalletApi] { def watchScriptPubKey(scriptPubKey: ScriptPubKey): Future[ScriptPubKeyDb] def markUTXOsAsReserved( - utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] + utxos: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] /** Marks all utxos that are ours in this transactions as reserved */ def markUTXOsAsReserved(tx: Transaction): Future[Vector[SpendingInfoDb]] def unmarkUTXOsAsReserved( - utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] + utxos: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] - /** Unmarks all utxos that are ours in this transactions indicating they are no longer reserved */ + /** Unmarks all utxos that are ours in this transactions indicating they are + * no longer reserved + */ def unmarkUTXOsAsReserved(tx: Transaction): Future[Vector[SpendingInfoDb]] /** Checks if the wallet contains any data */ def isEmpty(): Future[Boolean] - /** Removes all utxos from the wallet. - * Don't call this unless you are sure you can recover - * your wallet + /** Removes all utxos from the wallet. Don't call this unless you are sure you + * can recover your wallet */ def clearAllUtxos(): Future[WalletApi] def clearAllAddresses(): Future[WalletApi] - /** Gets a new external address with the specified - * type. - * @param addressType + /** Gets a new external address with the specified type. + * @param addressType */ def getNewAddress(addressType: AddressType): Future[BitcoinAddress] - /** Gets a new external address - * Calling this method multiple - * times will return the same address, until it has - * received funds. + /** Gets a new external address Calling this method multiple times will return + * the same address, until it has received funds. */ def getNewAddress(): Future[BitcoinAddress] def getNewAddress( addressType: AddressType, - tags: Vector[AddressTag]): Future[BitcoinAddress] + tags: Vector[AddressTag] + ): Future[BitcoinAddress] def getNewAddress(tags: Vector[AddressTag]): Future[BitcoinAddress] - /** Gets a external address the given AddressType. Calling this - * method multiple times will return the same address, until it has - * received funds. + /** Gets a external address the given AddressType. Calling this method + * multiple times will return the same address, until it has received funds. */ def getUnusedAddress(addressType: AddressType): Future[BitcoinAddress] - /** Gets a external address. Calling this method multiple - * times will return the same address, until it has - * received funds. + /** Gets a external address. Calling this method multiple times will return + * the same address, until it has received funds. */ def getUnusedAddress: Future[BitcoinAddress] /** Mimics the `getaddressinfo` RPC call in Bitcoin Core * * @param address - * @return If the address is found in our database `Some(address)` - * is returned, otherwise `None` + * @return + * If the address is found in our database `Some(address)` is returned, + * otherwise `None` */ def getAddressInfo(address: BitcoinAddress): Future[Option[AddressInfo]] def getAddressInfo( spendingInfoDb: SpendingInfoDb, - networkParameters: NetworkParameters): Future[Option[AddressInfo]] = { + networkParameters: NetworkParameters + ): Future[Option[AddressInfo]] = { val addressT = BitcoinAddress.fromScriptPubKeyT( spk = spendingInfoDb.output.scriptPubKey, - np = networkParameters) + np = networkParameters + ) addressT match { case Success(addr) => getAddressInfo(addr) @@ -241,14 +253,17 @@ trait WalletApi extends StartStopAsync[WalletApi] { } } - /** Tags the address with the address tag, updates the tag if one of tag's TagType already exists */ + /** Tags the address with the address tag, updates the tag if one of tag's + * TagType already exists + */ def tagAddress(address: BitcoinAddress, tag: AddressTag): Future[AddressTagDb] def getAddressTags(address: BitcoinAddress): Future[Vector[AddressTagDb]] def getAddressTags( address: BitcoinAddress, - tagType: AddressTagType): Future[Vector[AddressTagDb]] + tagType: AddressTagType + ): Future[Vector[AddressTagDb]] def getAddressTags(): Future[Vector[AddressTagDb]] @@ -260,15 +275,18 @@ trait WalletApi extends StartStopAsync[WalletApi] { def dropAddressTagType( address: BitcoinAddress, - addressTagType: AddressTagType): Future[Int] + addressTagType: AddressTagType + ): Future[Int] def dropAddressTagName( address: BitcoinAddress, - tagName: AddressTagName): Future[Int] + tagName: AddressTagName + ): Future[Int] /** Generates a new change address */ protected[wallet] def getNewChangeAddress()(implicit - ec: ExecutionContext): Future[BitcoinAddress] + ec: ExecutionContext + ): Future[BitcoinAddress] def keyManager: KeyManagerApi @@ -284,7 +302,8 @@ trait WalletApi extends StartStopAsync[WalletApi] { outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, amount: CurrencyUnit, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], @@ -301,7 +320,8 @@ trait WalletApi extends StartStopAsync[WalletApi] { def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], @@ -316,11 +336,13 @@ trait WalletApi extends StartStopAsync[WalletApi] { /** Sends the entire wallet balance to the given address */ def sweepWallet(address: BitcoinAddress)(implicit - ec: ExecutionContext): Future[Transaction] = sweepWallet(address, None) + ec: ExecutionContext + ): Future[Transaction] = sweepWallet(address, None) /** Sends the entire wallet balance to the given address */ def sweepWallet(address: BitcoinAddress, feeRateOpt: Option[FeeUnit])(implicit - ec: ExecutionContext): Future[Transaction] = { + ec: ExecutionContext + ): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- sweepWallet(address, feeRate) @@ -329,14 +351,15 @@ trait WalletApi extends StartStopAsync[WalletApi] { /** Sends the entire wallet balance to the given address */ def sweepWallet(address: BitcoinAddress, feeRate: FeeUnit)(implicit - ec: ExecutionContext): Future[Transaction] + ec: ExecutionContext + ): Future[Transaction] def sendWithAlgo( address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - algo: CoinSelectionAlgo)(implicit - ec: ExecutionContext): Future[Transaction] + algo: CoinSelectionAlgo + )(implicit ec: ExecutionContext): Future[Transaction] def sendWithAlgo( address: BitcoinAddress, @@ -357,7 +380,8 @@ trait WalletApi extends StartStopAsync[WalletApi] { def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] def sendToAddress( address: BitcoinAddress, @@ -376,8 +400,8 @@ trait WalletApi extends StartStopAsync[WalletApi] { */ def sendToOutputs( outputs: Vector[TransactionOutput], - feeRateOpt: Option[FeeUnit])(implicit - ec: ExecutionContext): Future[Transaction] = { + feeRateOpt: Option[FeeUnit] + )(implicit ec: ExecutionContext): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- sendToOutputs(outputs, feeRate) @@ -385,15 +409,16 @@ trait WalletApi extends StartStopAsync[WalletApi] { } def sendToOutputs(outputs: Vector[TransactionOutput], feeRate: FeeUnit)( - implicit ec: ExecutionContext): Future[Transaction] + implicit ec: ExecutionContext + ): Future[Transaction] /** Sends funds to each address */ def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], - feeRateOpt: Option[FeeUnit])(implicit - ec: ExecutionContext): Future[Transaction] = { + feeRateOpt: Option[FeeUnit] + )(implicit ec: ExecutionContext): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- sendToAddresses(addresses, amounts, feeRate) @@ -403,37 +428,41 @@ trait WalletApi extends StartStopAsync[WalletApi] { def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] def bumpFeeRBF( txId: DoubleSha256DigestBE, - newFeeRate: FeeUnit): Future[Transaction] + newFeeRate: FeeUnit + ): Future[Transaction] - /** Bumps the fee of the parent transaction with a new - * child transaction with the given fee rate + /** Bumps the fee of the parent transaction with a new child transaction with + * the given fee rate */ def bumpFeeCPFP( txId: DoubleSha256DigestBE, - feeRate: FeeUnit): Future[Transaction] + feeRate: FeeUnit + ): Future[Transaction] def makeOpReturnCommitment( message: String, hashMessage: Boolean, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] def makeOpReturnCommitment( message: String, hashMessage: Boolean, - feeRateOpt: Option[FeeUnit])(implicit - ec: ExecutionContext): Future[Transaction] = { + feeRateOpt: Option[FeeUnit] + )(implicit ec: ExecutionContext): Future[Transaction] = { for { feeRate <- determineFeeRate(feeRateOpt) tx <- makeOpReturnCommitment(message, hashMessage, feeRate) } yield tx } - /** Determines if the given output is from this wallet and - * is a change output from this wallet + /** Determines if the given output is from this wallet and is a change output + * from this wallet */ def isChange(output: TransactionOutput): Future[Boolean] @@ -448,31 +477,38 @@ trait WalletApi extends StartStopAsync[WalletApi] { def getInfo(): Future[WalletInfo] def findByOutPoints( - outPoints: Vector[TransactionOutPoint]): Future[Vector[SpendingInfoDb]] + outPoints: Vector[TransactionOutPoint] + ): Future[Vector[SpendingInfoDb]] - def findByOutPoint(outPoint: TransactionOutPoint)(implicit - ec: ExecutionContext): Future[Option[SpendingInfoDb]] = { + def findByOutPoint( + outPoint: TransactionOutPoint + )(implicit ec: ExecutionContext): Future[Option[SpendingInfoDb]] = { findByOutPoints(Vector(outPoint)).map(_.headOption) } def findByTxIds( - txIds: Vector[DoubleSha256DigestBE]): Future[Vector[TransactionDb]] + txIds: Vector[DoubleSha256DigestBE] + ): Future[Vector[TransactionDb]] - def findByTxId(txId: DoubleSha256DigestBE)(implicit - ec: ExecutionContext): Future[Option[TransactionDb]] = { + def findByTxId( + txId: DoubleSha256DigestBE + )(implicit ec: ExecutionContext): Future[Option[TransactionDb]] = { findByTxIds(Vector(txId)).map(_.headOption) } - def findByTxId(txId: DoubleSha256Digest)(implicit - ec: ExecutionContext): Future[Option[TransactionDb]] = { + def findByTxId( + txId: DoubleSha256Digest + )(implicit ec: ExecutionContext): Future[Option[TransactionDb]] = { findByTxId(txId.flip) } - /** Finds all the outputs in our wallet being spent in the given transaction */ + /** Finds all the outputs in our wallet being spent in the given transaction + */ def findOutputsBeingSpent(tx: Transaction): Future[Vector[SpendingInfoDb]] def findByScriptPubKey( - scriptPubKey: ScriptPubKey): Future[Vector[SpendingInfoDb]] + scriptPubKey: ScriptPubKey + ): Future[Vector[SpendingInfoDb]] } case class WalletInfo( @@ -483,7 +519,8 @@ case class WalletInfo( height: Int, blockHash: DoubleSha256DigestBE, rescan: Boolean, - imported: Boolean) + imported: Boolean +) /** An HDWallet that uses Neutrino to sync */ trait NeutrinoHDWalletApi extends HDWalletApi with NeutrinoWalletApi diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/WalletStateDescriptor.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/WalletStateDescriptor.scala index 4abbebf86a..56fccf4bf0 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/WalletStateDescriptor.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/WalletStateDescriptor.scala @@ -22,7 +22,8 @@ object WalletStateDescriptorType case Some(state) => state case None => sys.error( - s"Could not find WalletStateDescriptorType for string=$string") + s"Could not find WalletStateDescriptorType for string=$string" + ) } } } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/AccountDb.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/AccountDb.scala index f4062d19dd..8c52285408 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/AccountDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/AccountDb.scala @@ -8,12 +8,12 @@ import org.bitcoins.core.crypto.{ import org.bitcoins.core.hd.HDAccount import org.bitcoins.core.util.HDUtil -/** Represents the xpub at the account level, NOT the root xpub - * that in conjunction with the path specified in hdAccount - * can be used to generate the account level xpub - * m / purpose' / coin_type' / account' +/** Represents the xpub at the account level, NOT the root xpub that in + * conjunction with the path specified in hdAccount can be used to generate the + * account level xpub m / purpose' / coin_type' / account' * - * @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#path-levels + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#path-levels */ case class AccountDb(xpub: ExtPublicKey, hdAccount: HDAccount) { def xpubVersion: ExtKeyPubVersion = xpub.version diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressDb.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressDb.scala index 435af27a45..861c76d527 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressDb.scala @@ -78,7 +78,8 @@ object AddressDbHelper { def getSegwitAddress( pub: ECPublicKey, path: SegWitHDPath, - np: NetworkParameters): SegWitAddressDb = { + np: NetworkParameters + ): SegWitAddressDb = { val witnessSpk = P2WPKHWitnessSPKV0(pub) val scriptWitness = P2WPKHWitnessV0(pub) @@ -97,38 +98,47 @@ object AddressDbHelper { def getLegacyAddress( pub: ECPublicKey, path: LegacyHDPath, - np: NetworkParameters): LegacyAddressDb = { + np: NetworkParameters + ): LegacyAddressDb = { val spk = P2PKHScriptPubKey(pub) val addr = P2PKHAddress(spk, np) - LegacyAddressDb(path = path, - ecPublicKey = pub, - hashedPubKey = spk.pubKeyHash, - address = addr, - scriptPubKey = spk) + LegacyAddressDb( + path = path, + ecPublicKey = pub, + hashedPubKey = spk.pubKeyHash, + address = addr, + scriptPubKey = spk + ) } /** Get a nested Segwit pay-to-pubkeyhash address */ def getNestedSegwitAddress( pub: ECPublicKey, path: NestedSegWitHDPath, - np: NetworkParameters): NestedSegWitAddressDb = { + np: NetworkParameters + ): NestedSegWitAddressDb = { val redeem = P2WPKHWitnessSPKV0(pub) val spk = P2SHScriptPubKey(redeem) val scriptWitness = P2WPKHWitnessV0(pub) val addr = P2SHAddress(spk, np) - NestedSegWitAddressDb(path = path, - ecPublicKey = pub, - hashedPubKey = redeem.pubKeyHash, - address = addr, - witnessScript = scriptWitness, - scriptPubKey = spk) + NestedSegWitAddressDb( + path = path, + ecPublicKey = pub, + hashedPubKey = redeem.pubKeyHash, + address = addr, + witnessScript = scriptWitness, + scriptPubKey = spk + ) } - /** Gets an address. Derives the correct type by looking at the kind of path passed in */ + /** Gets an address. Derives the correct type by looking at the kind of path + * passed in + */ def getAddress( pub: ECPublicKey, path: HDPath, - np: NetworkParameters): AddressDb = + np: NetworkParameters + ): AddressDb = path match { case legacy: LegacyHDPath => getLegacyAddress(pub, legacy, np) case nested: NestedSegWitHDPath => getNestedSegwitAddress(pub, nested, np) diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressRecord.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressRecord.scala index d1b7b80677..54f57ed9a6 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressRecord.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressRecord.scala @@ -27,45 +27,60 @@ case class AddressRecord( (purpose, address, scriptWitnessOpt) match { case (HDPurposes.SegWit, bechAddr: Bech32Address, Some(scriptWitness)) => val path = - SegWitHDPath(coinType = accountCoin, - accountIndex = accountIndex, - chainType = accountChain, - addressIndex = addressIndex) + SegWitHDPath( + coinType = accountCoin, + accountIndex = accountIndex, + chainType = accountChain, + addressIndex = addressIndex + ) - SegWitAddressDb(path, - ecPublicKey = pubKey, - hashedPubKey = hashedPubKey, - address = bechAddr, - witnessScript = scriptWitness, - scriptPubKey = scriptPubKey) + SegWitAddressDb( + path, + ecPublicKey = pubKey, + hashedPubKey = hashedPubKey, + address = bechAddr, + witnessScript = scriptWitness, + scriptPubKey = scriptPubKey + ) case (HDPurposes.Legacy, legacyAddr: P2PKHAddress, None) => - val path = LegacyHDPath(coinType = accountCoin, - accountIndex = accountIndex, - chainType = accountChain, - addressIndex = addressIndex) - LegacyAddressDb(path, - pubKey, - hashedPubKey, - legacyAddr, - scriptPubKey = scriptPubKey) + val path = LegacyHDPath( + coinType = accountCoin, + accountIndex = accountIndex, + chainType = accountChain, + addressIndex = addressIndex + ) + LegacyAddressDb( + path, + pubKey, + hashedPubKey, + legacyAddr, + scriptPubKey = scriptPubKey + ) - case (HDPurposes.NestedSegWit, + case ( + HDPurposes.NestedSegWit, address: P2SHAddress, - Some(scriptWitness)) => - val path = NestedSegWitHDPath(coinType = accountCoin, - accountIndex = accountIndex, - chainType = accountChain, - addressIndex = addressIndex) - NestedSegWitAddressDb(path, - pubKey, - hashedPubKey, - address, - witnessScript = scriptWitness, - scriptPubKey = scriptPubKey) + Some(scriptWitness) + ) => + val path = NestedSegWitHDPath( + coinType = accountCoin, + accountIndex = accountIndex, + chainType = accountChain, + addressIndex = addressIndex + ) + NestedSegWitAddressDb( + path, + pubKey, + hashedPubKey, + address, + witnessScript = scriptWitness, + scriptPubKey = scriptPubKey + ) case (purpose: HDPurpose, address: BitcoinAddress, scriptWitnessOpt) => throw new IllegalArgumentException( - s"Got invalid combination of HD purpose, address and script witness: $purpose, $address, $scriptWitnessOpt") + s"Got invalid combination of HD purpose, address and script witness: $purpose, $address, $scriptWitnessOpt" + ) } } } @@ -74,12 +89,14 @@ object AddressRecord { def fromAddressDb(addressDb: AddressDb, scriptPubKeyId: Long): AddressRecord = addressDb match { - case SegWitAddressDb(path, - pubKey, - hashedPubKey, - address, - scriptWitness, - _) => + case SegWitAddressDb( + path, + pubKey, + hashedPubKey, + address, + scriptWitness, + _ + ) => AddressRecord( path.purpose, path.coin.coinType, @@ -105,12 +122,14 @@ object AddressRecord { scriptPubKeyId, None // scriptwitness ) - case NestedSegWitAddressDb(path, - pubKey, - hashedPubKey, - address, - scriptWitness, - _) => + case NestedSegWitAddressDb( + path, + pubKey, + hashedPubKey, + address, + scriptWitness, + _ + ) => AddressRecord( path.purpose, path.coin.coinType, diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressTagDb.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressTagDb.scala index cdb5d7d756..3c94093575 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressTagDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/AddressTagDb.scala @@ -11,7 +11,8 @@ import org.bitcoins.core.wallet.utxo.{ case class AddressTagDb( address: BitcoinAddress, tagName: AddressTagName, - tagType: AddressTagType) { + tagType: AddressTagType +) { val addressTag: AddressTag = InternalAddressTag(tagName, tagType) diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/IncomingTransactionDb.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/IncomingTransactionDb.scala index bff84f9f22..416f1fd472 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/IncomingTransactionDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/IncomingTransactionDb.scala @@ -3,13 +3,15 @@ package org.bitcoins.core.api.wallet.db import org.bitcoins.core.currency.CurrencyUnit import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE} -/** Represents a relevant transaction for the wallet that we should be keeping track of +/** Represents a relevant transaction for the wallet that we should be keeping + * track of * - * @param txIdBE Transaction ID + * @param txIdBE + * Transaction ID */ case class IncomingTransactionDb( txIdBE: DoubleSha256DigestBE, - incomingAmount: CurrencyUnit) - extends TxDB { + incomingAmount: CurrencyUnit +) extends TxDB { lazy val txId: DoubleSha256Digest = txIdBE.flip } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/OutgoingTransactionDb.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/OutgoingTransactionDb.scala index f3c99cd413..c3a3bbe4ff 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/OutgoingTransactionDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/OutgoingTransactionDb.scala @@ -5,11 +5,16 @@ import org.bitcoins.core.protocol.transaction._ import org.bitcoins.core.wallet.fee.SatoshisPerByte import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE} -/** Represents a relevant transaction for the wallet that we should be keeping track of - * @param txIdBE Transaction ID - * @param actualFee fee paid by the transaction - * @param expectedFee Fee rate the wallet expected to pay - * @param feeRate Fee rate the transaction actually paid +/** Represents a relevant transaction for the wallet that we should be keeping + * track of + * @param txIdBE + * Transaction ID + * @param actualFee + * fee paid by the transaction + * @param expectedFee + * Fee rate the wallet expected to pay + * @param feeRate + * Fee rate the transaction actually paid */ case class OutgoingTransactionDb( txIdBE: DoubleSha256DigestBE, @@ -17,8 +22,8 @@ case class OutgoingTransactionDb( sentAmount: CurrencyUnit, actualFee: CurrencyUnit, expectedFee: CurrencyUnit, - feeRate: SatoshisPerByte) - extends TxDB { + feeRate: SatoshisPerByte +) extends TxDB { lazy val txId: DoubleSha256Digest = txIdBE.flip } @@ -28,14 +33,17 @@ object OutgoingTransactionDb { tx: Transaction, inputAmount: CurrencyUnit, sentAmount: CurrencyUnit, - expectedFee: CurrencyUnit): OutgoingTransactionDb = { + expectedFee: CurrencyUnit + ): OutgoingTransactionDb = { val totalOutput = tx.outputs.map(_.value).sum require( sentAmount <= totalOutput, - s"sentAmount ($sentAmount) cannot be greater than the transaction's total output ($totalOutput)") + s"sentAmount ($sentAmount) cannot be greater than the transaction's total output ($totalOutput)" + ) require( sentAmount <= inputAmount, - s"sentAmount ($sentAmount) cannot be greater than the amount the wallet input ($inputAmount)") + s"sentAmount ($sentAmount) cannot be greater than the amount the wallet input ($inputAmount)" + ) val feePaid = inputAmount - totalOutput val feeRate = SatoshisPerByte.calc(inputAmount, tx) diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/ScriptPubKeyDb.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/ScriptPubKeyDb.scala index c1c3d45a59..83dad6787f 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/ScriptPubKeyDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/ScriptPubKeyDb.scala @@ -7,8 +7,8 @@ import org.bitcoins.crypto.{CryptoUtil, Sha256Digest} case class ScriptPubKeyDb( scriptPubKey: ScriptPubKey, hash: Sha256Digest, - id: Option[Long] = None) - extends DbRowAutoInc[ScriptPubKeyDb] { + id: Option[Long] = None +) extends DbRowAutoInc[ScriptPubKeyDb] { override def copyWithId(id: Long): ScriptPubKeyDb = copy(id = Option(id)) } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/SpendingInfoDb.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/SpendingInfoDb.scala index 824b71ac0e..7d23e1a4f8 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/SpendingInfoDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/SpendingInfoDb.scala @@ -24,8 +24,7 @@ import org.bitcoins.core.wallet.utxo.{ } import org.bitcoins.crypto.{DoubleSha256DigestBE, HashType, Sign} -/** DB representation of a native V0 - * SegWit UTXO +/** DB representation of a native V0 SegWit UTXO */ case class SegwitV0SpendingInfo( outPoint: TransactionOutPoint, @@ -49,7 +48,8 @@ case class SegwitV0SpendingInfo( /** Updates the `spendingTxId` field */ override def copyWithSpendingTxId( - txId: DoubleSha256DigestBE): SegwitV0SpendingInfo = + txId: DoubleSha256DigestBE + ): SegwitV0SpendingInfo = copy(spendingTxIdOpt = Some(txId)) } @@ -77,12 +77,12 @@ case class LegacySpendingInfo( /** Updates the `spendingTxId` field */ override def copyWithSpendingTxId( - txId: DoubleSha256DigestBE): LegacySpendingInfo = + txId: DoubleSha256DigestBE + ): LegacySpendingInfo = copy(spendingTxIdOpt = Some(txId)) } -/** DB representation of a nested segwit V0 - * SegWit UTXO +/** DB representation of a nested segwit V0 SegWit UTXO */ case class NestedSegwitV0SpendingInfo( outPoint: TransactionOutPoint, @@ -107,27 +107,27 @@ case class NestedSegwitV0SpendingInfo( /** Updates the `spendingTxId` field */ override def copyWithSpendingTxId( - txId: DoubleSha256DigestBE): NestedSegwitV0SpendingInfo = + txId: DoubleSha256DigestBE + ): NestedSegwitV0SpendingInfo = copy(spendingTxIdOpt = Some(txId)) } -/** The database level representation of a UTXO. - * When storing a UTXO we don't want to store - * sensitive material such as private keys. - * We instead store the necessary information - * we need to derive the private keys, given - * the root wallet seed. +/** The database level representation of a UTXO. When storing a UTXO we don't + * want to store sensitive material such as private keys. We instead store the + * necessary information we need to derive the private keys, given the root + * wallet seed. */ sealed trait SpendingInfoDb extends DbRowAutoInc[SpendingInfoDb] { if (TxoState.spentStates.contains(state)) { require( spendingTxIdOpt.isDefined, - s"If we have spent a spendinginfodb, the spendingTxId must be defined. Outpoint=${outPoint.toString}") + s"If we have spent a spendinginfodb, the spendingTxId must be defined. Outpoint=${outPoint.toString}" + ) } - /** This type is here to ensure copyWithSpent returns the same - * type as the one it was called on. + /** This type is here to ensure copyWithSpent returns the same type as the one + * it was called on. */ protected type SpendingInfoType <: SpendingInfoDb @@ -142,7 +142,8 @@ sealed trait SpendingInfoDb extends DbRowAutoInc[SpendingInfoDb] { def isChange: Boolean = privKeyPath.chain.chainType == HDChainType.Change - /** The current [[org.bitcoins.core.wallet.utxo.TxoState state]] of the utxo */ + /** The current [[org.bitcoins.core.wallet.utxo.TxoState state]] of the utxo + */ def state: TxoState /** The TXID of the transaction this output was received in */ @@ -167,12 +168,13 @@ sealed trait SpendingInfoDb extends DbRowAutoInc[SpendingInfoDb] { /** Updates the `spendingTxId` field */ def copyWithSpendingTxId(txId: DoubleSha256DigestBE): SpendingInfoType - /** Converts a non-sensitive DB representation of a UTXO into - * a signable (and sensitive) real-world UTXO + /** Converts a non-sensitive DB representation of a UTXO into a signable (and + * sensitive) real-world UTXO */ def toUTXOInfo( keyManager: BIP39KeyManagerApi, - prevTransaction: Transaction): ScriptSignatureParams[InputInfo] = { + prevTransaction: Transaction + ): ScriptSignatureParams[InputInfo] = { val sign: Sign = keyManager.toSign(privKeyPath = privKeyPath) @@ -181,7 +183,8 @@ sealed trait SpendingInfoDb extends DbRowAutoInc[SpendingInfoDb] { def toUTXOInfo( sign: Sign, - prevTransaction: Transaction): ScriptSignatureParams[InputInfo] = { + prevTransaction: Transaction + ): ScriptSignatureParams[InputInfo] = { ScriptSignatureParams( InputInfo( outPoint, @@ -213,42 +216,53 @@ object SpendingInfoDb { scriptWitnessOpt: Option[ScriptWitness], state: TxoState, txId: DoubleSha256DigestBE, - spendingTxIdOpt: Option[DoubleSha256DigestBE]): SpendingInfoDb = { + spendingTxIdOpt: Option[DoubleSha256DigestBE] + ): SpendingInfoDb = { require( txId == outpoint.txIdBE, - s"Outpoint and crediting txid not the same, got=$txId expected=${outpoint.txIdBE}") + s"Outpoint and crediting txid not the same, got=$txId expected=${outpoint.txIdBE}" + ) output.scriptPubKey match { case _: P2SHScriptPubKey => if (scriptWitnessOpt.isDefined) { require( hdPath.isInstanceOf[NestedSegWitHDPath], - s"hdPath must be SegwitHdPath for SegwitV0SpendingInfo, got=$hdPath") - NestedSegwitV0SpendingInfo(outpoint, - output, - hdPath.asInstanceOf[NestedSegWitHDPath], - redeemScriptOpt.get, - scriptWitnessOpt.get, - state, - spendingTxIdOpt, - id) + s"hdPath must be SegwitHdPath for SegwitV0SpendingInfo, got=$hdPath" + ) + NestedSegwitV0SpendingInfo( + outpoint, + output, + hdPath.asInstanceOf[NestedSegWitHDPath], + redeemScriptOpt.get, + scriptWitnessOpt.get, + state, + spendingTxIdOpt, + id + ) } else { require( hdPath.isInstanceOf[LegacyHDPath], - s"hdPath must be LegacyHDPath for LegacySpendingInfo, got=$hdPath") - LegacySpendingInfo(outPoint = outpoint, - output = output, - privKeyPath = hdPath.asInstanceOf[LegacyHDPath], - state = state, - spendingTxIdOpt = spendingTxIdOpt, - id = id) + s"hdPath must be LegacyHDPath for LegacySpendingInfo, got=$hdPath" + ) + LegacySpendingInfo( + outPoint = outpoint, + output = output, + privKeyPath = hdPath.asInstanceOf[LegacyHDPath], + state = state, + spendingTxIdOpt = spendingTxIdOpt, + id = id + ) } case _: WitnessScriptPubKey => require( hdPath.isInstanceOf[SegWitHDPath], - s"hdPath must be SegwitHdPath for SegwitV0SpendingInfo, got=$hdPath") - require(scriptWitnessOpt.isDefined, - s"ScriptWitness must be defined for SegwitV0SpendingInfo") + s"hdPath must be SegwitHdPath for SegwitV0SpendingInfo, got=$hdPath" + ) + require( + scriptWitnessOpt.isDefined, + s"ScriptWitness must be defined for SegwitV0SpendingInfo" + ) SegwitV0SpendingInfo( outPoint = outpoint, output = output, @@ -261,13 +275,16 @@ object SpendingInfoDb { case _: RawScriptPubKey => require( hdPath.isInstanceOf[LegacyHDPath], - s"hdPath must be LegacyHDPath for LegacySpendingInfo, got=$hdPath") - LegacySpendingInfo(outPoint = outpoint, - output = output, - privKeyPath = hdPath.asInstanceOf[LegacyHDPath], - state = state, - spendingTxIdOpt = spendingTxIdOpt, - id = id) + s"hdPath must be LegacyHDPath for LegacySpendingInfo, got=$hdPath" + ) + LegacySpendingInfo( + outPoint = outpoint, + output = output, + privKeyPath = hdPath.asInstanceOf[LegacyHDPath], + state = state, + spendingTxIdOpt = spendingTxIdOpt, + id = id + ) } } } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/TransactionDb.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/TransactionDb.scala index f266ae0610..aca6d9f239 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/TransactionDb.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/TransactionDb.scala @@ -10,16 +10,26 @@ trait TxDB { def txIdBE: DoubleSha256DigestBE } -/** Represents a relevant transaction for the wallet that we should be keeping track of - * @param txIdBE Transaction ID - * @param transaction Serialized Transaction - * @param unsignedTxIdBE Transaction ID of the unsigned transaction - * @param unsignedTx Unsigned Transaction. This is useful so we can reconcile what our estimated - * fees were against our actual fees in the case of ECDSA signature size variability - * @param wTxIdBEOpt Witness Transaction ID - * @param numInputs Number of inputs in the transaction - * @param numOutputs Number of outputs in the transaction - * @param lockTime locktime of the transaction +/** Represents a relevant transaction for the wallet that we should be keeping + * track of + * @param txIdBE + * Transaction ID + * @param transaction + * Serialized Transaction + * @param unsignedTxIdBE + * Transaction ID of the unsigned transaction + * @param unsignedTx + * Unsigned Transaction. This is useful so we can reconcile what our + * estimated fees were against our actual fees in the case of ECDSA signature + * size variability + * @param wTxIdBEOpt + * Witness Transaction ID + * @param numInputs + * Number of inputs in the transaction + * @param numOutputs + * Number of outputs in the transaction + * @param lockTime + * locktime of the transaction */ case class TransactionDb( txIdBE: DoubleSha256DigestBE, @@ -31,10 +41,12 @@ case class TransactionDb( numInputs: Int, numOutputs: Int, lockTime: UInt32, - blockHashOpt: Option[DoubleSha256DigestBE]) - extends TxDB { - require(unsignedTx.inputs.forall(_.scriptSignature == EmptyScriptSignature), - s"All ScriptSignatures must be empty, got $unsignedTx") + blockHashOpt: Option[DoubleSha256DigestBE] +) extends TxDB { + require( + unsignedTx.inputs.forall(_.scriptSignature == EmptyScriptSignature), + s"All ScriptSignatures must be empty, got $unsignedTx" + ) lazy val txId: DoubleSha256Digest = txIdBE.flip lazy val unsignedTxId: DoubleSha256Digest = unsignedTxIdBE.flip @@ -45,41 +57,54 @@ object TransactionDbHelper { def fromTransaction( tx: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE]): TransactionDb = { + blockHashOpt: Option[DoubleSha256DigestBE] + ): TransactionDb = { val (unsignedTx, wTxIdBEOpt) = tx match { case btx: NonWitnessTransaction => val unsignedInputs = btx.inputs.map(input => - TransactionInput(input.previousOutput, - EmptyScriptSignature, - input.sequence)) - (BaseTransaction(btx.version, - unsignedInputs, - btx.outputs, - btx.lockTime), - None) + TransactionInput( + input.previousOutput, + EmptyScriptSignature, + input.sequence + )) + ( + BaseTransaction( + btx.version, + unsignedInputs, + btx.outputs, + btx.lockTime + ), + None + ) case wtx: WitnessTransaction => val unsignedInputs = wtx.inputs.map(input => - TransactionInput(input.previousOutput, - EmptyScriptSignature, - input.sequence)) - val uwtx = WitnessTransaction(wtx.version, - unsignedInputs, - wtx.outputs, - wtx.lockTime, - EmptyWitness.fromInputs(unsignedInputs)) + TransactionInput( + input.previousOutput, + EmptyScriptSignature, + input.sequence + )) + val uwtx = WitnessTransaction( + wtx.version, + unsignedInputs, + wtx.outputs, + wtx.lockTime, + EmptyWitness.fromInputs(unsignedInputs) + ) (uwtx, Some(uwtx.wTxIdBE)) } val totalOutput = tx.outputs.map(_.value).sum - TransactionDb(tx.txIdBE, - tx, - unsignedTx.txIdBE, - unsignedTx, - wTxIdBEOpt, - totalOutput, - tx.inputs.size, - tx.outputs.size, - tx.lockTime, - blockHashOpt) + TransactionDb( + tx.txIdBE, + tx, + unsignedTx.txIdBE, + unsignedTx, + wTxIdBEOpt, + totalOutput, + tx.inputs.size, + tx.outputs.size, + tx.lockTime, + blockHashOpt + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/db/UTXORecord.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/db/UTXORecord.scala index 1b7e42272f..393b19685a 100644 --- a/core/src/main/scala/org/bitcoins/core/api/wallet/db/UTXORecord.scala +++ b/core/src/main/scala/org/bitcoins/core/api/wallet/db/UTXORecord.scala @@ -49,12 +49,14 @@ case class UTXORecord( ) case (path: LegacyHDPath, None, None) => - LegacySpendingInfo(outPoint = outpoint, - output = TransactionOutput(value, scriptPubKey), - privKeyPath = path, - id = id, - state = state, - spendingTxIdOpt = spendingTxIdOpt) + LegacySpendingInfo( + outPoint = outpoint, + output = TransactionOutput(value, scriptPubKey), + privKeyPath = path, + id = id, + state = state, + spendingTxIdOpt = spendingTxIdOpt + ) case (path: NestedSegWitHDPath, Some(redeemScript), Some(scriptWitness)) if WitnessScriptPubKey.isValidAsm(redeemScript.asm) => @@ -71,7 +73,8 @@ case class UTXORecord( case _ => throw new IllegalArgumentException( - s"Could not construct SpendingInfoDb from bad record: $this.") + s"Could not construct SpendingInfoDb from bad record: $this." + ) } } @@ -79,7 +82,8 @@ object UTXORecord { def fromSpendingInfoDb( spendingInfoDb: SpendingInfoDb, - scriptPubKeyId: Long): UTXORecord = + scriptPubKeyId: Long + ): UTXORecord = UTXORecord( spendingInfoDb.outPoint, spendingInfoDb.state, // state diff --git a/core/src/main/scala/org/bitcoins/core/bloom/BloomFilter.scala b/core/src/main/scala/org/bitcoins/core/bloom/BloomFilter.scala index ba386ab7e8..5bf5bbca6a 100644 --- a/core/src/main/scala/org/bitcoins/core/bloom/BloomFilter.scala +++ b/core/src/main/scala/org/bitcoins/core/bloom/BloomFilter.scala @@ -19,8 +19,10 @@ import scala.util.hashing.MurmurHash3 /** Implements a bloom filter that abides by the semantics of BIP37 * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki BIP37]]. - * @see [[https://github.com/bitcoin/bitcoin/blob/master/src/bloom.h Bitcoin Core bloom.h]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki BIP37]]. + * @see + * [[https://github.com/bitcoin/bitcoin/blob/master/src/bloom.h Bitcoin Core bloom.h]] */ sealed abstract class BloomFilter extends NetworkElement { @@ -33,32 +35,38 @@ sealed abstract class BloomFilter extends NetworkElement { /** The number of hash functions used in the bloom filter */ def hashFuncs: UInt32 - /** An arbitrary value to add to the seed value in the hash function used by the bloom filter. */ + /** An arbitrary value to add to the seed value in the hash function used by + * the bloom filter. + */ def tweak: UInt32 - /** A set of flags that control how outpoints corresponding to a matched pubkey script are added to the filter. - * See the 'Comparing Transaction Elements to a Bloom Filter' section in this - * @see [[https://bitcoin.org/en/developer-reference#filterload link]] + /** A set of flags that control how outpoints corresponding to a matched + * pubkey script are added to the filter. See the 'Comparing Transaction + * Elements to a Bloom Filter' section in this + * @see + * [[https://bitcoin.org/en/developer-reference#filterload link]] */ def flags: BloomFlag - /** Inserts a sequence of bytes into the [[org.bitcoins.core.bloom.BloomFilter BloomFilter]] */ + /** Inserts a sequence of bytes into the + * [[org.bitcoins.core.bloom.BloomFilter BloomFilter]] + */ def insert(bytes: ByteVector): BloomFilter = { - //these are the bit indexes that need to be set inside of data + // these are the bit indexes that need to be set inside of data val bitIndexes = (0 until hashFuncs.toInt).map(i => murmurHash(i, bytes)) @tailrec def loop(remainingBitIndexes: Seq[Int], accum: ByteVector): ByteVector = { if (remainingBitIndexes.isEmpty) accum else { val currentIndex = remainingBitIndexes.head - //since we are dealing with a bit vector, this gets the byteIndex we need to set - //the bit inside of. + // since we are dealing with a bit vector, this gets the byteIndex we need to set + // the bit inside of. val byteIndex = currentIndex >>> 3 - //we need to calculate the bitIndex we need to set inside of our byte + // we need to calculate the bitIndex we need to set inside of our byte val bitIndex = (1 << (7 & currentIndex)).toByte val byte = accum(byteIndex) val setBitByte: Byte = (byte | bitIndex).toByte - //replace old byte with new byte with bit set + // replace old byte with new byte with bit set val newAccum: ByteVector = accum.update(byteIndex, setBitByte) loop(remainingBitIndexes.tail, newAccum) } @@ -82,16 +90,17 @@ sealed abstract class BloomFilter extends NetworkElement { /** Inserts a public key and it's corresponding hash into the bloom filter * - * @note The rationale for inserting both the pubkey and its hash is that - * in most cases where you have an "interesting pubkey" that you - * want to track on the P2P network what you really need to do is - * insert the hash of the public key, as that is what appears on - * the blockchain and that nodes you query with bloom filters will - * see. + * @note + * The rationale for inserting both the pubkey and its hash is that in most + * cases where you have an "interesting pubkey" that you want to track on + * the P2P network what you really need to do is insert the hash of the + * public key, as that is what appears on the blockchain and that nodes you + * query with bloom filters will see. * - * @see The - * [[https://github.com/bitcoinj/bitcoinj/blob/806afa04419ebdc3c15d5adf065979aa7303e7f6/core/src/main/java/org/bitcoinj/core/BloomFilter.java#L244 BitcoinJ]] - * implementation of this function + * @see + * The + * [[https://github.com/bitcoinj/bitcoinj/blob/806afa04419ebdc3c15d5adf065979aa7303e7f6/core/src/main/java/org/bitcoinj/core/BloomFilter.java#L244 BitcoinJ]] + * implementation of this function */ def insert(pubkey: ECPublicKey): BloomFilter = { val pubkeyBytes = pubkey.bytes @@ -124,21 +133,26 @@ sealed abstract class BloomFilter extends NetworkElement { /** Checks if `data` contains a [[DoubleSha256Digest DoubleSha256Digest]] */ def contains(hash: DoubleSha256Digest): Boolean = contains(hash.bytes) - /** Checks if `data` contains a [[org.bitcoins.core.protocol.transaction.TransactionOutPoint TransactionOutPoint]] */ + /** Checks if `data` contains a + * [[org.bitcoins.core.protocol.transaction.TransactionOutPoint TransactionOutPoint]] + */ def contains(outPoint: TransactionOutPoint): Boolean = contains(outPoint.bytes) /** Checks if `data` contains a [[DoubleSha256Digest Sha256Hash160Digest]] */ def contains(hash: Sha256Hash160Digest): Boolean = contains(hash.bytes) - /** Checks if the transaction's txid, or any of the constants in it's scriptPubKeys/scriptSigs match our BloomFilter + /** Checks if the transaction's txid, or any of the constants in it's + * scriptPubKeys/scriptSigs match our BloomFilter * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#filter-matching-algorithm BIP37]] - * for exact details on what is relevant to a bloom filter and what is not relevant + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#filter-matching-algorithm BIP37]] + * for exact details on what is relevant to a bloom filter and what is not + * relevant */ def isRelevant(transaction: Transaction): Boolean = { val scriptPubKeys = transaction.outputs.map(_.scriptPubKey) - //pull out all of the constants in the scriptPubKey's + // pull out all of the constants in the scriptPubKey's val constantsWithOutputIndex = scriptPubKeys.zipWithIndex.flatMap { case (scriptPubKey, index) => scriptPubKey.asm.collect { case c: ScriptConstant => @@ -146,7 +160,7 @@ sealed abstract class BloomFilter extends NetworkElement { } } - //check if the bloom filter contains any of the script constants in our outputs + // check if the bloom filter contains any of the script constants in our outputs val constantsOutput = constantsWithOutputIndex.filter { case (c, _) => contains(c.bytes) } @@ -158,11 +172,11 @@ sealed abstract class BloomFilter extends NetworkElement { (c, index) } } - //check if the filter contains any of the prevouts in this tx + // check if the filter contains any of the prevouts in this tx val containsOutPoint = transaction.inputs.filter(i => contains(i.previousOutput)) - //check if the bloom filter contains any of the script constants in our inputs + // check if the bloom filter contains any of the script constants in our inputs val constantsInput = constantsWithInputIndex.filter { case (c, _) => contains(c.bytes) } @@ -171,16 +185,19 @@ sealed abstract class BloomFilter extends NetworkElement { containsOutPoint.nonEmpty || contains(transaction.txId) } - /** Updates this bloom filter to contain the relevant information for the given Transaction + /** Updates this bloom filter to contain the relevant information for the + * given Transaction * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#filter-matching-algorithm BIP37]] - * for the exact details on what parts of a transaction is added to the bloom filter + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#filter-matching-algorithm BIP37]] + * for the exact details on what parts of a transaction is added to the + * bloom filter */ def update(transaction: Transaction): BloomFilter = flags match { case BloomUpdateAll => val scriptPubKeys = transaction.outputs.map(_.scriptPubKey) - //a sequence of outPoints that need to be inserted into the filter + // a sequence of outPoints that need to be inserted into the filter val outPoints: Seq[TransactionOutPoint] = scriptPubKeys.zipWithIndex.flatMap { case (scriptPubKey, index) => // we filter all constants, and create an outpoint if the constant matches our filter @@ -192,14 +209,14 @@ sealed abstract class BloomFilter extends NetworkElement { val outPointsBytes = outPoints.map(_.bytes) val filterWithOutPoints = insertByteVectors(outPointsBytes) - //add txid + // add txid val filterWithTxIdAndOutPoints = filterWithOutPoints.insert(transaction.txId) filterWithTxIdAndOutPoints case BloomUpdateNone => this case BloomUpdateP2PKOnly => - //update the filter with the outpoint if the filter matches any of the constants in a p2pkh or multisig script pubkey + // update the filter with the outpoint if the filter matches any of the constants in a p2pkh or multisig script pubkey val scriptPubKeysWithIndex = transaction.outputs.map(_.scriptPubKey).zipWithIndex updateP2PKOnly(scriptPubKeysWithIndex, transaction.txId) @@ -209,16 +226,19 @@ sealed abstract class BloomFilter extends NetworkElement { /** Updates a bloom filter according to the rules specified by the * [[org.bitcoins.core.bloom.BloomUpdateP2PKOnly BloomUpdateP2PKOnly]] flag * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#filter-matching-algorithm BIP37]] - * for the exact rules on updating a bloom filter with this flag set + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#filter-matching-algorithm BIP37]] + * for the exact rules on updating a bloom filter with this flag set */ def updateP2PKOnly( scriptPubKeysWithIndex: Seq[(ScriptPubKey, Int)], - txId: DoubleSha256Digest): BloomFilter = { + txId: DoubleSha256Digest + ): BloomFilter = { @tailrec def loop( constantsWithIndex: Seq[(ScriptToken, Int)], - accumFilter: BloomFilter): BloomFilter = + accumFilter: BloomFilter + ): BloomFilter = constantsWithIndex match { case h +: t if accumFilter.contains(h._1.bytes) => val filter = @@ -230,9 +250,9 @@ sealed abstract class BloomFilter extends NetworkElement { val p2pkOrMultiSigScriptPubKeys: Seq[(ScriptPubKey, Int)] = scriptPubKeysWithIndex.filter { case (s, _) => s.isInstanceOf[P2PKScriptPubKey] || - s.isInstanceOf[MultiSignatureScriptPubKey] + s.isInstanceOf[MultiSignatureScriptPubKey] } - //gets rid of all asm operations in the scriptPubKey except for the constants + // gets rid of all asm operations in the scriptPubKey except for the constants val scriptConstantsWithOutputIndex: Seq[(ScriptToken, Int)] = p2pkOrMultiSigScriptPubKeys.flatMap { case (scriptPubKey, index) => (scriptPubKey.asm.map(token => (token, index))).filter { @@ -242,16 +262,20 @@ sealed abstract class BloomFilter extends NetworkElement { loop(scriptConstantsWithOutputIndex, this) } - /** Performs the [[scala.util.hashing.MurmurHash3 MurmurHash3]] on the given hash + /** Performs the [[scala.util.hashing.MurmurHash3 MurmurHash3]] on the given + * hash * - * @param hashNum the nth hash function we are using - * @param bytes the bytes of the data that needs to be inserted into the - * [[org.bitcoins.core.bloom.BloomFilter BloomFilter]] - * @return the index of the bit inside of `data` that needs to be set to 1 + * @param hashNum + * the nth hash function we are using + * @param bytes + * the bytes of the data that needs to be inserted into the + * [[org.bitcoins.core.bloom.BloomFilter BloomFilter]] + * @return + * the index of the bit inside of `data` that needs to be set to 1 */ private def murmurHash(hashNum: Int, bytes: ByteVector): Int = { - //TODO: The call of .toInt is probably the source of a bug here, need to come back and look at this - //since this isn't consensus critical though I'm leaving this for now + // TODO: The call of .toInt is probably the source of a bug here, need to come back and look at this + // since this isn't consensus critical though I'm leaving this for now val seed = (hashNum * murmurConstant.toLong + tweak.toLong).toInt val murmurHash = MurmurHash3.bytesHash(bytes.toArray, seed) val uint32 = UInt32(BytesUtil.encodeHex(murmurHash)) @@ -259,22 +283,29 @@ sealed abstract class BloomFilter extends NetworkElement { modded.toInt } - /** See [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#bloom-filter-format BIP37]] + /** See + * [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#bloom-filter-format BIP37]] * to see where this number comes from */ private def murmurConstant = UInt32("fba4c795") - /** Adds a sequence of byte vectors to our bloom filter then returns that new filter */ + /** Adds a sequence of byte vectors to our bloom filter then returns that new + * filter + */ def insertByteVectors( - bytes: scala.collection.Seq[ByteVector]): BloomFilter = { + bytes: scala.collection.Seq[ByteVector] + ): BloomFilter = { @tailrec def loop( remainingByteVectors: scala.collection.Seq[ByteVector], - accumBloomFilter: BloomFilter): BloomFilter = { + accumBloomFilter: BloomFilter + ): BloomFilter = { if (remainingByteVectors.isEmpty) accumBloomFilter else - loop(remainingByteVectors.tail, - accumBloomFilter.insert(remainingByteVectors.head)) + loop( + remainingByteVectors.tail, + accumBloomFilter.insert(remainingByteVectors.head) + ) } loop(bytes, this) } @@ -289,31 +320,39 @@ object BloomFilter extends Factory[BloomFilter] { data: ByteVector, hashFuncs: UInt32, tweak: UInt32, - flags: BloomFlag) - extends BloomFilter + flags: BloomFlag + ) extends BloomFilter - /** Max bloom filter size as per [[https://bitcoin.org/en/developer-reference#filterload]] */ + /** Max bloom filter size as per + * [[https://bitcoin.org/en/developer-reference#filterload]] + */ val maxSize = UInt32(36000) - /** Max hashFunc size as per [[https://bitcoin.org/en/developer-reference#filterload]] */ + /** Max hashFunc size as per + * [[https://bitcoin.org/en/developer-reference#filterload]] + */ val maxHashFuncs = UInt32(50) - val empty: BloomFilter = BloomFilterImpl(CompactSizeUInt.zero, - ByteVector.empty, - UInt32.zero, - UInt32.zero, - BloomUpdateAll) + val empty: BloomFilter = BloomFilterImpl( + CompactSizeUInt.zero, + ByteVector.empty, + UInt32.zero, + UInt32.zero, + BloomUpdateAll + ) - /** Creates a bloom filter based on the number of elements to be inserted into the filter - * and the desired false positive rate. + /** Creates a bloom filter based on the number of elements to be inserted into + * the filter and the desired false positive rate. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#bloom-filter-format BIP37]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#bloom-filter-format BIP37]] */ // todo provide default flag? def apply( numElements: Int, falsePositiveRate: Double, - flags: BloomFlag): BloomFilter = { + flags: BloomFlag + ): BloomFilter = { val random = Math.floor(Math.random() * UInt32.max.toLong).toLong val tweak = UInt32(random) apply(numElements, falsePositiveRate, tweak, flags) @@ -322,41 +361,47 @@ object BloomFilter extends Factory[BloomFilter] { // todo: provide a apply method where you can pass in bloom-able filters // through a type class - /** Creates a bloom filter based on the number of elements to be inserted into the filter - * and the desired false positive rate. + /** Creates a bloom filter based on the number of elements to be inserted into + * the filter and the desired false positive rate. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#bloom-filter-format BIP37]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#bloom-filter-format BIP37]] * - * @param tweak A random value that only acts to randomize the filter and increase privacy + * @param tweak + * A random value that only acts to randomize the filter and increase + * privacy */ def apply( numElements: Int, falsePositiveRate: Double, tweak: UInt32, - flags: BloomFlag): BloomFilter = { + flags: BloomFlag + ): BloomFilter = { if (numElements == 0) { BloomFilter.empty } else { import scala.math._ - //m = number of bits in the array - //n = number of elements in the array - //from https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#bloom-filter-format + // m = number of bits in the array + // n = number of elements in the array + // from https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#bloom-filter-format val optimalFilterSize: Double = (-1 / pow(log(2), 2) * numElements * log(falsePositiveRate)) / 8 - //BIP37 places limitations on the filter size, namely it cannot be > 36,000 bytes + // BIP37 places limitations on the filter size, namely it cannot be > 36,000 bytes val actualFilterSize: Int = max(1, min(optimalFilterSize, maxSize.toInt * 8)).toInt val optimalHashFuncs: Double = actualFilterSize * 8 / numElements * log(2) - //BIP37 places a limit on the amount of hashFuncs we can use, which is 50 + // BIP37 places a limit on the amount of hashFuncs we can use, which is 50 val actualHashFuncs: Int = max(1, min(optimalHashFuncs, maxHashFuncs.toInt)).toInt val emptyByteArray = ByteVector(Array.fill(actualFilterSize)(0.toByte)) - BloomFilter(filterSize = CompactSizeUInt(UInt64(actualFilterSize)), - data = emptyByteArray, - hashFuncs = UInt32(actualHashFuncs), - tweak = tweak, - flags = flags) + BloomFilter( + filterSize = CompactSizeUInt(UInt64(actualFilterSize)), + data = emptyByteArray, + hashFuncs = UInt32(actualHashFuncs), + tweak = tweak, + flags = flags + ) } } @@ -366,7 +411,8 @@ object BloomFilter extends Factory[BloomFilter] { data: ByteVector, hashFuncs: UInt32, tweak: UInt32, - flags: BloomFlag): BloomFilter = { + flags: BloomFlag + ): BloomFilter = { BloomFilterImpl(filterSize, data, hashFuncs, tweak, flags) } diff --git a/core/src/main/scala/org/bitcoins/core/bloom/BloomFlag.scala b/core/src/main/scala/org/bitcoins/core/bloom/BloomFlag.scala index a56d5e42ab..8a286749d1 100644 --- a/core/src/main/scala/org/bitcoins/core/bloom/BloomFlag.scala +++ b/core/src/main/scala/org/bitcoins/core/bloom/BloomFlag.scala @@ -3,8 +3,7 @@ package org.bitcoins.core.bloom import org.bitcoins.crypto.Factory import scodec.bits.ByteVector -/** Created by chris on 8/3/16. - * Specifies how to update a bloom filter +/** Created by chris on 8/3/16. Specifies how to update a bloom filter * [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#filter-matching-algorithm]] */ sealed trait BloomFlag { @@ -16,16 +15,16 @@ case object BloomUpdateNone extends BloomFlag { def byte = 0.toByte } -/** If the filter matches any data element in a pubkey script, - * the corresponding outpoint is added to the filter. +/** If the filter matches any data element in a pubkey script, the corresponding + * outpoint is added to the filter. */ case object BloomUpdateAll extends BloomFlag { def byte = 1.toByte } /** If the filter matches any data element in a pubkey script and that - * scriptPubKey is either a P2PKH or non-P2SH pay-to-multisig script, - * the outpoint for this transaction is added to the filter. + * scriptPubKey is either a P2PKH or non-P2SH pay-to-multisig script, the + * outpoint for this transaction is added to the filter. */ case object BloomUpdateP2PKOnly extends BloomFlag { def byte = 2.toByte @@ -39,7 +38,8 @@ object BloomFlag extends Factory[BloomFlag] { if (flagOpt.isDefined) flagOpt.get else throw new IllegalArgumentException( - "The given byte was not defined for BloomFlag, got: " + byte) + "The given byte was not defined for BloomFlag, got: " + byte + ) } def fromBytes(bytes: ByteVector): BloomFlag = BloomFlag(bytes.head) diff --git a/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala b/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala index 4b86286731..3b07c0904b 100644 --- a/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala +++ b/core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala @@ -16,13 +16,15 @@ sealed abstract class NetworkParameters { chainParams.base58Prefix(Base58Type.ScriptAddress) def privateKey: ByteVector = chainParams.base58Prefix(Base58Type.SecretKey) - /** @see [[https://github.com/bitcoin/bitcoin/blob/84d0fdce11709c8e26b9c450d47727ab36641437/src/chainparams.cpp Bitcoin Core]] - * `chainparams.cpp nDefaultPort` + /** @see + * [[https://github.com/bitcoin/bitcoin/blob/84d0fdce11709c8e26b9c450d47727ab36641437/src/chainparams.cpp Bitcoin Core]] + * `chainparams.cpp nDefaultPort` */ def port: Int - /** @see [[https://github.com/bitcoin/bitcoin/blob/bccb4d29a8080bf1ecda1fc235415a11d903a680/src/chainparamsbase.cpp Bitcoin Core]] - * `chainparamsbase.cpp` + /** @see + * [[https://github.com/bitcoin/bitcoin/blob/bccb4d29a8080bf1ecda1fc235415a11d903a680/src/chainparamsbase.cpp Bitcoin Core]] + * `chainparamsbase.cpp` */ def rpcPort: Int @@ -33,9 +35,9 @@ sealed abstract class NetworkParameters { /** The seeds used to bootstrap the network */ def dnsSeeds: Seq[String] - /** The message start string is designed to be unlikely to occur in normal data. - * The characters are rarely used upper ASCII, not valid as UTF-8, and produce - * a large 32-bit integer with any alignment. + /** The message start string is designed to be unlikely to occur in normal + * data. The characters are rarely used upper ASCII, not valid as UTF-8, and + * produce a large 32-bit integer with any alignment. * https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.cpp#L108 */ def magicBytes: ByteVector @@ -68,11 +70,11 @@ sealed abstract class MainNet extends BitcoinNetwork { */ override def dnsSeeds: Vector[String] = { Vector( - //"seed.bitcoin.sipa.be", very slow, commenting out for now + // "seed.bitcoin.sipa.be", very slow, commenting out for now "dnsseed.bluematt.me", "dnsseed.bitcoin.dashjr.org", "seed.bitcoinstats.com", - //"seed.btc.petertodd.net", very slow, commenting out for now + // "seed.btc.petertodd.net", very slow, commenting out for now "seed.bitcoin.jonasschnelli.ch", "seed.bitcoin.sprovoost.nl", "dnsseed.emzy.de", @@ -102,10 +104,12 @@ sealed abstract class TestNet3 extends BitcoinNetwork { /** @inheritdoc */ override def dnsSeeds: Seq[String] = - Seq("testnet-seed.bitcoin.jonasschnelli.ch", - "seed.tbtc.petertodd.org", - "seed.testnet.bitcoin.sprovoost.nl", - "testnet-seed.bluematt.me") + Seq( + "testnet-seed.bitcoin.jonasschnelli.ch", + "seed.tbtc.petertodd.org", + "seed.testnet.bitcoin.sprovoost.nl", + "testnet-seed.bluematt.me" + ) /* * @inheritdoc */ @@ -151,9 +155,11 @@ sealed abstract class SigNet extends BitcoinNetwork { /** @inheritdoc */ override def dnsSeeds: Seq[String] = - Seq("178.128.221.177", - "2a01:7c8:d005:390::5", - "ntv3mtqw5wt63red.onion:38333") + Seq( + "178.128.221.177", + "2a01:7c8:d005:390::5", + "ntv3mtqw5wt63red.onion:38333" + ) /** @inheritdoc */ @@ -187,8 +193,11 @@ object Networks extends StringFactory[NetworkParameters] { def fromChainHash(chainHash: DoubleSha256DigestBE): NetworkParameters = { knownNetworks .find(_.chainParams.genesisBlock.blockHeader.hashBE == chainHash) - .getOrElse(throw new IllegalArgumentException( - s"$chainHash is not a recognized Chain Hash")) + .getOrElse( + throw new IllegalArgumentException( + s"$chainHash is not a recognized Chain Hash" + ) + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/consensus/Consensus.scala b/core/src/main/scala/org/bitcoins/core/consensus/Consensus.scala index 450e527e8b..22a8bfa08d 100644 --- a/core/src/main/scala/org/bitcoins/core/consensus/Consensus.scala +++ b/core/src/main/scala/org/bitcoins/core/consensus/Consensus.scala @@ -14,7 +14,8 @@ sealed abstract class Consensus { def maxBlockWeight: Long = maxBlockSize * weightScalar - /** BIP141 changes this from 20,000 -> 80,000, to see how sigops are counted please see BIP 141 + /** BIP141 changes this from 20,000 -> 80,000, to see how sigops are counted + * please see BIP 141 * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#sigops]] */ def maxSigOps = 80000 diff --git a/core/src/main/scala/org/bitcoins/core/consensus/Merkle.scala b/core/src/main/scala/org/bitcoins/core/consensus/Merkle.scala index b19237de67..d1b4345269 100644 --- a/core/src/main/scala/org/bitcoins/core/consensus/Merkle.scala +++ b/core/src/main/scala/org/bitcoins/core/consensus/Merkle.scala @@ -11,9 +11,8 @@ import org.bitcoins.crypto.{CryptoUtil, DoubleSha256Digest} import scala.annotation.tailrec -/** Created by chris on 5/24/16. - * This trait contains all functionality related to computing merkle trees - * Mimics this functionality inside of bitcoin core +/** Created by chris on 5/24/16. This trait contains all functionality related + * to computing merkle trees Mimics this functionality inside of bitcoin core * [[https://github.com/bitcoin/bitcoin/blob/master/src/consensus/merkle.cpp]] */ trait Merkle { @@ -21,21 +20,26 @@ trait Merkle { type MerkleTree = BinaryTree[DoubleSha256Digest] /** Computes the merkle root for the given block - * @param block the given block that needs the merkle root computed - * @return the hash representing the merkle root for this block + * @param block + * the given block that needs the merkle root computed + * @return + * the hash representing the merkle root for this block */ def computeBlockMerkleRoot(block: Block): DoubleSha256Digest = computeMerkleRoot(block.transactions) /** Computes the merkle root for the given sequence of transactions - * @param transactions the list of transactions whose merkle root needs to be computed - * @return the merkle root for the sequence of transactions + * @param transactions + * the list of transactions whose merkle root needs to be computed + * @return + * the merkle root for the sequence of transactions */ def computeMerkleRoot(transactions: Seq[Transaction]): DoubleSha256Digest = transactions match { case Nil => throw new IllegalArgumentException( - "We cannot have zero transactions in the block. There always should be ATLEAST one - the coinbase tx") + "We cannot have zero transactions in the block. There always should be ATLEAST one - the coinbase tx" + ) case h +: Nil => h.txId case _ +: _ => val leafs = transactions.map(tx => Leaf(tx.txId)) @@ -43,28 +47,33 @@ trait Merkle { merkleTree.value.get } - /** Builds a [[MerkleTree]] from sequence of sub merkle trees. - * This subTrees can be individual txids (leafs) or full blown subtrees - * @param subTrees the trees that need to be hashed - * @param accum the accumulated merkle trees, waiting to be hashed next round - * @return the entire Merkle tree computed from the given merkle trees + /** Builds a [[MerkleTree]] from sequence of sub merkle trees. This subTrees + * can be individual txids (leafs) or full blown subtrees + * @param subTrees + * the trees that need to be hashed + * @param accum + * the accumulated merkle trees, waiting to be hashed next round + * @return + * the entire Merkle tree computed from the given merkle trees */ @tailrec final def build( subTrees: Seq[MerkleTree], - accum: Seq[MerkleTree]): MerkleTree = + accum: Seq[MerkleTree] + ): MerkleTree = subTrees match { case Nil => if (accum.size == 1) accum.head else if (accum.isEmpty) throw new IllegalArgumentException( - "Should never have sub tree size of zero, this implies there was zero hashes given") + "Should never have sub tree size of zero, this implies there was zero hashes given" + ) else build(accum.reverse, Nil) case h +: h1 +: t => val newTree = computeTree(h, h1) build(t, newTree +: accum) case h +: t => - //means that we have an odd amount of txids, this means we duplicate the last hash in the tree + // means that we have an odd amount of txids, this means we duplicate the last hash in the tree val newTree = computeTree(h, h) build(t, newTree +: accum) } @@ -82,8 +91,8 @@ trait Merkle { Node(hash, tree1, tree2) } - /** Computes the commitment of the block to the wtxids - * See the definition of a block commitment in BIP141 + /** Computes the commitment of the block to the wtxids See the definition of a + * block commitment in BIP141 * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure]] * [[https://github.com/bitcoin/bitcoin/blob/7490ae8b699d2955b665cf849d86ff5bb5245c28/src/consensus/merkle.cpp#L168]] */ @@ -96,8 +105,8 @@ trait Merkle { build(coinbaseWTxId +: hashes) } - /** Computes the merkle root for the committment inside of a coinbase txs scriptPubKey - * See BIP141 + /** Computes the merkle root for the committment inside of a coinbase txs + * scriptPubKey See BIP141 * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure]] */ def computeBlockWitnessMerkleRoot(block: Block): DoubleSha256Digest = { diff --git a/core/src/main/scala/org/bitcoins/core/crypto/BIP39Seed.scala b/core/src/main/scala/org/bitcoins/core/crypto/BIP39Seed.scala index d95d3d73ea..5b48b4cdec 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/BIP39Seed.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/BIP39Seed.scala @@ -21,12 +21,14 @@ sealed abstract class BIP39Seed extends NetworkElement with MaskedToString { } } -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki# BIP32]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki# BIP32]] */ object BIP39Seed extends Factory[BIP39Seed] { private case class BIP39SeedImpl(bytes: ByteVector) extends BIP39Seed - /** Generates a [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]] + /** Generates a + * [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]] * seed from a sequence of bytes. Must be between 16 and 64 bytes. */ override def fromBytes(bytes: ByteVector): BIP39Seed = @@ -37,31 +39,38 @@ object BIP39Seed extends Factory[BIP39Seed] { private val ITERATION_COUNT = 2048 private val DERIVED_KEY_LENGTH = 512 - /** Generates a [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]] + /** Generates a + * [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]] * seed from a mnemonic code. An optional password can be supplied. - * @param password Defaults to the empty string + * @param password + * Defaults to the empty string */ def fromMnemonic( mnemonic: MnemonicCode, - password: String = EMPTY_PASSWORD): BIP39Seed = { + password: String = EMPTY_PASSWORD + ): BIP39Seed = { val salt = s"mnemonic$password" val words = mnemonic.mkString(" ") - val encodedBytes = CryptoUtil.pbkdf2WithSha512(words, - salt, - ITERATION_COUNT, - DERIVED_KEY_LENGTH) + val encodedBytes = CryptoUtil.pbkdf2WithSha512( + words, + salt, + ITERATION_COUNT, + DERIVED_KEY_LENGTH + ) BIP39Seed.fromBytes(encodedBytes) } - /** Generates a [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]] + /** Generates a + * [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]] * seed from a mnemonic code. An optional password can be supplied. */ def fromMnemonic( mnemonic: MnemonicCode, - passwordOpt: Option[String]): BIP39Seed = { + passwordOpt: Option[String] + ): BIP39Seed = { passwordOpt match { case Some(pass) => fromMnemonic(mnemonic, pass) diff --git a/core/src/main/scala/org/bitcoins/core/crypto/ChainCode.scala b/core/src/main/scala/org/bitcoins/core/crypto/ChainCode.scala index 3ca79719dd..3486eb73c6 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/ChainCode.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/ChainCode.scala @@ -4,8 +4,10 @@ import org.bitcoins.crypto.{Factory, NetworkElement} import scodec.bits.ByteVector case class ChainCode(bytes: ByteVector) extends NetworkElement { - require(bytes.size == 32, - "ChainCode must be 32 bytes in size, got: " + bytes.size) + require( + bytes.size == 32, + "ChainCode must be 32 bytes in size, got: " + bytes.size + ) } object ChainCode extends Factory[ChainCode] { diff --git a/core/src/main/scala/org/bitcoins/core/crypto/ECPrivateKeyUtil.scala b/core/src/main/scala/org/bitcoins/core/crypto/ECPrivateKeyUtil.scala index ea783ba287..e108122a48 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/ECPrivateKeyUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/ECPrivateKeyUtil.scala @@ -14,7 +14,7 @@ object ECPrivateKeyUtil { */ def toWIF(privKey: ECPrivateKeyBytes, network: NetworkParameters): String = { val networkByte = network.privateKey - //append 1 byte to the end of the priv key byte representation if we need a compressed pub key + // append 1 byte to the end of the priv key byte representation if we need a compressed pub key val fullBytes = if (privKey.isCompressed) networkByte ++ (privKey.bytes ++ ByteVector(1)) else networkByte ++ privKey.bytes @@ -24,11 +24,12 @@ object ECPrivateKeyUtil { Base58.encode(encodedPrivKey) } - /** Takes in a base58 string and converts it into a private key. - * Private keys starting with 'K', 'L', or 'c' correspond to compressed public keys. + /** Takes in a base58 string and converts it into a private key. Private keys + * starting with 'K', 'L', or 'c' correspond to compressed public keys. * https://en.bitcoin.it/wiki/Wallet_import_format * - * @param WIF Wallet Import Format. Encoded in Base58 + * @param WIF + * Wallet Import Format. Encoded in Base58 * @return */ def fromWIFToPrivateKey(WIF: String): ECPrivateKeyBytes = { @@ -37,11 +38,13 @@ object ECPrivateKeyUtil { ECPrivateKeyBytes(privateKeyBytes, isCompressed) } - /** Takes in WIF private key as a sequence of bytes and determines if it corresponds to a compressed public key. - * If the private key corresponds to a compressed public key, the last byte should be 0x01, and - * the WIF string will have started with K or L instead of 5 (or c instead of 9 on testnet). + /** Takes in WIF private key as a sequence of bytes and determines if it + * corresponds to a compressed public key. If the private key corresponds to + * a compressed public key, the last byte should be 0x01, and the WIF string + * will have started with K or L instead of 5 (or c instead of 9 on testnet). * - * @param bytes private key in bytes + * @param bytes + * private key in bytes * @return */ def isCompressed(bytes: ByteVector): Boolean = { @@ -59,17 +62,19 @@ object ECPrivateKeyUtil { isCompressed(bytes) } - /** When decoding a WIF private key, we drop the first byte (network byte), and the last 4 bytes (checksum). - * If the private key corresponds to a compressed public key, we drop the last byte again. + /** When decoding a WIF private key, we drop the first byte (network byte), + * and the last 4 bytes (checksum). If the private key corresponds to a + * compressed public key, we drop the last byte again. * https://en.bitcoin.it/wiki/Wallet_import_format - * @param WIF Wallet Import Format. Encoded in Base58 + * @param WIF + * Wallet Import Format. Encoded in Base58 * @return */ private def trimFunction(WIF: String): ByteVector = { val bytesChecked = Base58.decodeCheck(WIF) - //see https://en.bitcoin.it/wiki/List_of_address_prefixes - //for where '5' and '9' come from + // see https://en.bitcoin.it/wiki/List_of_address_prefixes + // for where '5' and '9' come from bytesChecked match { case Success(bytes) if uncompressedKeyPrefixes.contains(WIF.headOption) => bytes.tail @@ -89,7 +94,10 @@ object ECPrivateKeyUtil { (compressedKeyPrefixes ++ uncompressedKeyPrefixes).flatten.toVector } - /** Returns the [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] from a serialized WIF key */ + /** Returns the + * [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] from a + * serialized WIF key + */ def parseNetworkFromWIF(wif: String): Try[NetworkParameters] = { val decoded = Base58.decodeCheck(wif) decoded match { @@ -102,7 +110,9 @@ object ECPrivateKeyUtil { case None => Failure( new IllegalArgumentException( - "Failed to match network bytes for WIF")) + "Failed to match network bytes for WIF" + ) + ) } case Failure(exn) => Failure(exn) } diff --git a/core/src/main/scala/org/bitcoins/core/crypto/ExtKey.scala b/core/src/main/scala/org/bitcoins/core/crypto/ExtKey.scala index 7660adb33c..b6ca434e84 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/ExtKey.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/ExtKey.scala @@ -13,12 +13,15 @@ import scala.util.{Failure, Success, Try} * [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki]] */ sealed abstract class ExtKey extends NetworkElement { - require(bytes.size == 78, - "ExtKey must be 78 bytes in size, got: " + bytes.size) + require( + bytes.size == 78, + "ExtKey must be 78 bytes in size, got: " + bytes.size + ) require( depth != UInt8.zero || !(childNum != UInt32.zero || fingerprint != ExtKey.masterFingerprint), - "Cannot have a 0 depth with non-zero parent fingerprint") + "Cannot have a 0 depth with non-zero parent fingerprint" + ) protected type VersionType <: ExtKeyVersion @@ -31,15 +34,15 @@ sealed abstract class ExtKey extends NetworkElement { /** The fingerprint of the parent key */ def fingerprint: ByteVector - /** Child number. This is ser32(i) for i in xi = xpar/i, with xi the key being serialized. - * (0x00000000 if master key) + /** Child number. This is ser32(i) for i in xi = xpar/i, with xi the key being + * serialized. (0x00000000 if master key) */ def childNum: UInt32 - /** In order to prevent these from depending solely on the key itself, - * we extend both private and public keys first with an extra 256 bits of entropy. - * This extension, called the chain code, - * is identical for corresponding private and public keys, and consists of 32 bytes. + /** In order to prevent these from depending solely on the key itself, we + * extend both private and public keys first with an extra 256 bits of + * entropy. This extension, called the chain code, is identical for + * corresponding private and public keys, and consists of 32 bytes. */ def chainCode: ChainCode @@ -61,8 +64,7 @@ sealed abstract class ExtKey extends NetworkElement { Try(UInt32(idx)).flatMap(deriveChildPubKey) } - /** Derives the child pubkey at the specified index and - * hardening value + /** Derives the child pubkey at the specified index and hardening value */ def deriveChildPubKey(child: BIP32Node): Try[ExtPublicKey] = { deriveChildPubKey(child.toUInt32) @@ -78,7 +80,8 @@ sealed abstract class ExtKey extends NetworkElement { @tailrec def loop( remainingPath: List[BIP32Node], - accum: ExtPublicKey): Try[ExtPublicKey] = { + accum: ExtPublicKey + ): Try[ExtPublicKey] = { remainingPath match { case h :: t => accum.deriveChildPubKey(h) match { @@ -147,7 +150,8 @@ object ExtKey extends Factory[ExtKey] with StringFactory[ExtKey] { require( bytes(45) == 0, "Byte at index 46 must be zero for a ExtPrivateKey, got: " + BytesUtil - .encodeHex(bytes(45))) + .encodeHex(bytes(45)) + ) val priv = ECPrivateKey(bytes.slice(46, 78)) ExtPrivateKey(x, depth, fp, childNum, chainCode, priv) } @@ -184,11 +188,12 @@ sealed abstract class ExtPrivateKey override def key: ECPrivateKey /** Derives the child key corresponding to the given path. The given path - * could signify account levels, one sublevel for each currency, or - * how to derive change addresses. + * could signify account levels, one sublevel for each currency, or how to + * derive change addresses. * - * @see [[org.bitcoins.core.hd.HDPath HDPath]] for a more - * specialized version of a BIP32 path + * @see + * [[org.bitcoins.core.hd.HDPath HDPath]] for a more specialized version of + * a BIP32 path */ def deriveChildPrivKey(path: BIP32Path): ExtPrivateKey = { path.foldLeft(this)((accum: ExtPrivateKey, curr: BIP32Node) => @@ -197,16 +202,16 @@ sealed abstract class ExtPrivateKey def deriveChildPrivKey(idx: UInt32): ExtPrivateKey = { val data: ByteVector = if (idx >= ExtKey.hardenedIdx) { - //derive hardened key + // derive hardened key hex"0" ++ key.bytes ++ idx.bytes } else { - //derive non hardened key + // derive non hardened key key.publicKey.bytes ++ idx.bytes } val hmac = CryptoUtil.hmac512(chainCode.bytes, data) val (il, ir) = hmac.splitAt(32) - //should be ECGroup addition - //parse256(IL) + kpar (mod n) + // should be ECGroup addition + // parse256(IL) + kpar (mod n) val tweak = CryptoUtil.add(il, key) val childKey = ECPrivateKey(tweak) val fp = CryptoUtil.sha256Hash160(key.publicKey.bytes).bytes.take(4) @@ -241,21 +246,24 @@ sealed abstract class ExtPrivateKey override def signWithEntropy( bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature = { + entropy: ByteVector + ): ECDigitalSignature = { key.signWithEntropy(bytes, entropy) } override def adaptorSign( adaptorPoint: ECPublicKey, msg: ByteVector, - auxRand: ByteVector): ECAdaptorSignature = { + auxRand: ByteVector + ): ECAdaptorSignature = { key.adaptorSign(adaptorPoint, msg, auxRand) } /** Signs the given bytes with the given [[BIP32Path path]] */ override def deriveAndSign( bytes: ByteVector, - path: BIP32Path): ECDigitalSignature = { + path: BIP32Path + ): ECDigitalSignature = { deriveChildPrivKey(path).sign(bytes) } @@ -278,10 +286,12 @@ object ExtPrivateKey fingerprint: ByteVector, childNum: UInt32, chainCode: ChainCode, - key: ECPrivateKey) - extends ExtPrivateKey { - require(fingerprint.size == 4, - "Fingerprint must be 4 bytes in size, got: " + fingerprint) + key: ECPrivateKey + ) extends ExtPrivateKey { + require( + fingerprint.size == 4, + "Fingerprint must be 4 bytes in size, got: " + fingerprint + ) } def freshRootKey(version: ExtKeyPrivVersion): ExtPrivateKey = { @@ -298,14 +308,18 @@ object ExtPrivateKey ) } - /** Takes in a base58 string and tries to convert it to an extended private key */ + /** Takes in a base58 string and tries to convert it to an extended private + * key + */ override def fromStringT(base58: String): Try[ExtPrivateKey] = ExtKey.fromStringT(base58) match { case Success(priv: ExtPrivateKey) => Success(priv) case Success(_: ExtPublicKey) => Failure( new IllegalArgumentException( - "Got extended public key, expected private")) + "Got extended public key, expected private" + ) + ) // we get warnings about unchecked generics // if we do fail: Failure[ExtPrivateKey] and // compile error if we do fail: Failure[_] @@ -327,7 +341,8 @@ object ExtPrivateKey case Success(priv: ExtPrivateKey) => priv case Success(_: ExtPublicKey) => throw new IllegalArgumentException( - "Cannot create ext public in ExtPrivateKey") + "Cannot create ext public in ExtPrivateKey" + ) case f: Failure[_] => throw f.exception } } @@ -338,7 +353,8 @@ object ExtPrivateKey fingerprint: ByteVector, child: UInt32, chainCode: ChainCode, - privateKey: ECPrivateKey): ExtPrivateKey = { + privateKey: ECPrivateKey + ): ExtPrivateKey = { ExtPrivateKeyImpl(version, depth, fingerprint, child, chainCode, privateKey) } @@ -357,7 +373,8 @@ object ExtPrivateKey def apply( version: ExtKeyPrivVersion, seedOpt: Option[ByteVector] = None, - path: BIP32Path = BIP32Path.empty): ExtPrivateKey = { + path: BIP32Path = BIP32Path.empty + ): ExtPrivateKey = { val seed: ByteVector = seedOpt match { case Some(bytes) => bytes case None => ECPrivateKey().bytes @@ -368,12 +385,14 @@ object ExtPrivateKey val masterPrivKey = ECPrivateKey(masterPrivBytes) val chaincode = ChainCode(chaincodeBytes) val fingerprint = UInt32.zero.bytes - val root = ExtPrivateKey(version, - depth = UInt8.zero, - fingerprint = fingerprint, - child = UInt32.zero, - chaincode, - masterPrivKey) + val root = ExtPrivateKey( + version, + depth = UInt8.zero, + fingerprint = fingerprint, + child = UInt32.zero, + chaincode, + masterPrivKey + ) path.foldLeft(root)((accum, curr) => accum.deriveChildPrivKey(curr.toUInt32)) @@ -383,7 +402,8 @@ object ExtPrivateKey def fromBIP39Seed( version: ExtKeyPrivVersion, seed: BIP39Seed, - path: BIP32Path = BIP32Path.empty): ExtPrivateKey = + path: BIP32Path = BIP32Path.empty + ): ExtPrivateKey = ExtPrivateKey(version, Some(seed.bytes), path) } @@ -393,10 +413,12 @@ case class ExtPrivateKeyHardened( fingerprint: ByteVector, childNum: UInt32, chainCode: ChainCode, - key: ECPrivateKey) - extends ExtPrivateKey { - require(fingerprint.size == 4, - "Fingerprint must be 4 bytes in size, got: " + fingerprint) + key: ECPrivateKey +) extends ExtPrivateKey { + require( + fingerprint.size == 4, + "Fingerprint must be 4 bytes in size, got: " + fingerprint + ) /** @inheritdoc */ override def deriveChildPrivKey(path: BIP32Path): ExtPrivateKeyHardened = { @@ -435,7 +457,9 @@ object ExtPrivateKeyHardened ) } - /** Takes in a base58 string and tries to convert it to an extended private key */ + /** Takes in a base58 string and tries to convert it to an extended private + * key + */ override def fromStringT(base58: String): Try[ExtPrivateKeyHardened] = ExtPrivateKey.fromStringT(base58).map(_.toHardened) @@ -457,7 +481,8 @@ object ExtPrivateKeyHardened def apply( version: ExtKeyPrivVersion, seedOpt: Option[ByteVector] = None, - path: BIP32Path = BIP32Path.empty): ExtPrivateKeyHardened = { + path: BIP32Path = BIP32Path.empty + ): ExtPrivateKeyHardened = { ExtPrivateKey(version, seedOpt, path).toHardened } @@ -465,7 +490,8 @@ object ExtPrivateKeyHardened def fromBIP39Seed( version: ExtKeyPrivVersion, seed: BIP39Seed, - path: BIP32Path = BIP32Path.empty): ExtPrivateKeyHardened = + path: BIP32Path = BIP32Path.empty + ): ExtPrivateKeyHardened = ExtPrivateKey(version, Some(seed.bytes), path).toHardened } @@ -476,8 +502,11 @@ sealed abstract class ExtPublicKey extends ExtKey { final override def deriveChildPubKey(idx: UInt32): Try[ExtPublicKey] = { if (idx >= ExtKey.hardenedIdx) { - Failure(new IllegalArgumentException( - s"Cannot derive hardened child from extended public key, got=$idx limit=${ExtKey.hardenedIdx}")) + Failure( + new IllegalArgumentException( + s"Cannot derive hardened child from extended public key, got=$idx limit=${ExtKey.hardenedIdx}" + ) + ) } else { val data = key.bytes ++ idx.bytes val hmac = CryptoUtil.hmac512(chainCode.bytes, data) @@ -485,14 +514,15 @@ sealed abstract class ExtPublicKey extends ExtKey { val priv = ECPrivateKey(il) val childPubKey = CryptoUtil.pubKeyTweakAdd(key, priv) - //we do not handle this case since it is impossible - //In case parse256(IL) ≥ n or Ki is the point at infinity, the resulting key is invalid, - //and one should proceed with the next value for i. - //https://botbot.me/freenode/bitcoin-wizards/2017-11-20/?tz=America/Chicago + // we do not handle this case since it is impossible + // In case parse256(IL) ≥ n or Ki is the point at infinity, the resulting key is invalid, + // and one should proceed with the next value for i. + // https://botbot.me/freenode/bitcoin-wizards/2017-11-20/?tz=America/Chicago val cc = ChainCode(ir) val fp = CryptoUtil.sha256Hash160(key.bytes).bytes.take(4) Success( - ExtPublicKey(version, depth + UInt8.one, fp, idx, cc, childPubKey)) + ExtPublicKey(version, depth + UInt8.one, fp, idx, cc, childPubKey) + ) } } } @@ -510,8 +540,8 @@ object ExtPublicKey fingerprint: ByteVector, childNum: UInt32, chainCode: ChainCode, - key: ECPublicKey) - extends ExtPublicKey + key: ECPublicKey + ) extends ExtPublicKey def apply( version: ExtKeyPubVersion, @@ -519,18 +549,22 @@ object ExtPublicKey fingerprint: ByteVector, child: UInt32, chainCode: ChainCode, - publicKey: ECPublicKey): ExtPublicKey = { + publicKey: ECPublicKey + ): ExtPublicKey = { ExtPublicKeyImpl(version, depth, fingerprint, child, chainCode, publicKey) } - /** Takes in a base58 string and tries to convert it to an extended public key */ + /** Takes in a base58 string and tries to convert it to an extended public key + */ override def fromStringT(base58: String): Try[ExtPublicKey] = ExtKey.fromStringT(base58) match { case Success(pub: ExtPublicKey) => Success(pub) case Success(_: ExtPrivateKey) => Failure( new IllegalArgumentException( - "Got extended private key, expected public")) + "Got extended private key, expected public" + ) + ) // we get warnings about unchecked generics // if we do fail: Failure[ExtPublicKey] and // compile error if we do fail: Failure[_] @@ -551,26 +585,22 @@ object ExtPublicKey ExtKey.fromStringT(base58) match { case Success(_: ExtPrivateKey) => throw new IllegalArgumentException( - "Cannot create ext privatkey in ExtPublicKey") + "Cannot create ext privatkey in ExtPublicKey" + ) case Success(pub: ExtPublicKey) => pub case f: Failure[_] => throw f.exception } } def tupled: ( - ( - ExtKeyPubVersion, - UInt8, - ByteVector, - UInt32, - ChainCode, - ECPublicKey)) => ExtPublicKey = { + (ExtKeyPubVersion, UInt8, ByteVector, UInt32, ChainCode, ECPublicKey) + ) => ExtPublicKey = { ExtPublicKeyImpl.tupled } def unapply: ExtPublicKey => Option[ - (ExtKeyPubVersion, UInt8, ByteVector, UInt32, ChainCode, ECPublicKey)] = { - extPubKey => - ExtPublicKeyImpl.unapply(extPubKey.asInstanceOf[ExtPublicKeyImpl]) + (ExtKeyPubVersion, UInt8, ByteVector, UInt32, ChainCode, ECPublicKey) + ] = { extPubKey => + ExtPublicKeyImpl.unapply(extPubKey.asInstanceOf[ExtPublicKeyImpl]) } } diff --git a/core/src/main/scala/org/bitcoins/core/crypto/ExtKeyVersion.scala b/core/src/main/scala/org/bitcoins/core/crypto/ExtKeyVersion.scala index 40bd5606fb..866184f651 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/ExtKeyVersion.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/ExtKeyVersion.scala @@ -9,8 +9,9 @@ sealed abstract class ExtKeyPrivVersion extends ExtKeyVersion sealed abstract class ExtKeyPubVersion extends ExtKeyVersion -/** @see [[https://github.com/satoshilabs/slips/blob/master/slip-0132.md#registered-hd-version-bytes SLIP132]] - * for a list of registered HD version bytes +/** @see + * [[https://github.com/satoshilabs/slips/blob/master/slip-0132.md#registered-hd-version-bytes SLIP132]] + * for a list of registered HD version bytes */ object ExtKeyVersion extends Factory[ExtKeyVersion] { @@ -37,47 +38,49 @@ object ExtKeyVersion extends Factory[ExtKeyVersion] { override def fromBytesOpt(bytes: ByteVector): Option[ExtKeyVersion] = all.find(_.bytes == bytes) - /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] - * with this version makes keys start with `xprv` + /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] with + * this version makes keys start with `xprv` */ final case object LegacyMainNetPriv extends ExtKeyPrivVersion { override val bytes = hex"0x0488ADE4" } - /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] - * with this version makes keys start with `tprv` + /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] with + * this version makes keys start with `tprv` */ final case object LegacyTestNet3Priv extends ExtKeyPrivVersion { override val bytes = hex"0x04358394" } - /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] - * with this version makes keys start with `zprv` + /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] with + * this version makes keys start with `zprv` */ final case object SegWitMainNetPriv extends ExtKeyPrivVersion { override val bytes = hex"0x04b2430c" } - /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] - * with this version makes keys start with `vprv` + /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] with + * this version makes keys start with `vprv` */ final case object SegWitTestNet3Priv extends ExtKeyPrivVersion { override val bytes = hex"0x045f18bc" } - /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] - * with this version makes keys start with `yprv` + /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] with + * this version makes keys start with `yprv` * - * @see [[https://github.com/Samourai-Wallet/ExtLibJ/blob/87fcb87f87ed86c38d4b82aefac6c59ec981bdad/java/com/samourai/wallet/util/FormatsUtilGeneric.java#L39 Samourai Wallet]] + * @see + * [[https://github.com/Samourai-Wallet/ExtLibJ/blob/87fcb87f87ed86c38d4b82aefac6c59ec981bdad/java/com/samourai/wallet/util/FormatsUtilGeneric.java#L39 Samourai Wallet]] */ final case object NestedSegWitMainNetPriv extends ExtKeyPrivVersion { override val bytes = hex"0x049D7878" } - /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] - * with this version makes keys start with `uprv` + /** Generating a [[org.bitcoins.core.crypto.ExtPrivateKey ExtPrivateKey]] with + * this version makes keys start with `uprv` * - * @see [[https://github.com/Samourai-Wallet/ExtLibJ/blob/87fcb87f87ed86c38d4b82aefac6c59ec981bdad/java/com/samourai/wallet/util/FormatsUtilGeneric.java#L40 Samourai wallet]] + * @see + * [[https://github.com/Samourai-Wallet/ExtLibJ/blob/87fcb87f87ed86c38d4b82aefac6c59ec981bdad/java/com/samourai/wallet/util/FormatsUtilGeneric.java#L40 Samourai wallet]] */ final case object NestedSegWitTestNet3Priv extends ExtKeyPrivVersion { override val bytes = hex"0x044a4e28" @@ -95,18 +98,20 @@ object ExtKeyPubVersion extends Factory[ExtKeyPubVersion] { NestedSegWitTestNet3Pub ) - /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] - * with this version makes keys start with `xpub` + /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] with + * this version makes keys start with `xpub` */ final case object LegacyMainNetPub extends ExtKeyPubVersion { override val bytes = hex"0x0488b21E" } - /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] - * with this version makes keys start with `upub` + /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] with + * this version makes keys start with `upub` * - * @see [[https://github.com/trezor/trezor-firmware/blob/master/common/defs/bitcoin/bitcoin_testnet.json#L17 Trezor]] - * @see [[https://github.com/Samourai-Wallet/ExtLibJ/blob/87fcb87f87ed86c38d4b82aefac6c59ec981bdad/java/com/samourai/wallet/util/FormatsUtilGeneric.java#L33 Samourai wallet]] + * @see + * [[https://github.com/trezor/trezor-firmware/blob/master/common/defs/bitcoin/bitcoin_testnet.json#L17 Trezor]] + * @see + * [[https://github.com/Samourai-Wallet/ExtLibJ/blob/87fcb87f87ed86c38d4b82aefac6c59ec981bdad/java/com/samourai/wallet/util/FormatsUtilGeneric.java#L33 Samourai wallet]] */ final case object NestedSegWitTestNet3Pub extends ExtKeyPubVersion { // Value stolen from Trezor lib, see link above @@ -114,31 +119,32 @@ object ExtKeyPubVersion extends Factory[ExtKeyPubVersion] { override val bytes = hex"0x044a5262" } - /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] - * with this version makes keys start with `ypub` + /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] with + * this version makes keys start with `ypub` * - * @see [[https://github.com/Samourai-Wallet/ExtLibJ/blob/87fcb87f87ed86c38d4b82aefac6c59ec981bdad/java/com/samourai/wallet/util/FormatsUtilGeneric.java#L32 Samourai Wallet]] + * @see + * [[https://github.com/Samourai-Wallet/ExtLibJ/blob/87fcb87f87ed86c38d4b82aefac6c59ec981bdad/java/com/samourai/wallet/util/FormatsUtilGeneric.java#L32 Samourai Wallet]] */ final case object NestedSegWitMainNetPub extends ExtKeyPubVersion { override val bytes = hex"0x049D7CB2" } - /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] - * with this version makes keys start with `vpub` + /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] with + * this version makes keys start with `vpub` */ final case object SegWitTestNet3Pub extends ExtKeyPubVersion { override val bytes = hex"0x045f1cf6" } - /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] - * with this version makes keys start with `tpub` + /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] with + * this version makes keys start with `tpub` */ final case object LegacyTestNet3Pub extends ExtKeyPubVersion { override val bytes = hex"0x043587CF" } - /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] - * with this version makes keys start with `zpub` + /** Generating a [[org.bitcoins.core.crypto.ExtPublicKey ExtPublicKey]] with + * this version makes keys start with `zpub` */ final case object SegWitMainNetPub extends ExtKeyPubVersion { override val bytes = hex"0x04b24746" diff --git a/core/src/main/scala/org/bitcoins/core/crypto/ExtSign.scala b/core/src/main/scala/org/bitcoins/core/crypto/ExtSign.scala index 2202cf913b..1d11d4cf48 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/ExtSign.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/ExtSign.scala @@ -11,12 +11,16 @@ trait AsyncExtSign extends AsyncAdaptorSign { def asyncDeriveAndSign( bytes: ByteVector, - path: BIP32Path): Future[ECDigitalSignature] + path: BIP32Path + ): Future[ECDigitalSignature] - /** First derives the child key that corresponds to [[BIP32Path path]] and then signs */ + /** First derives the child key that corresponds to [[BIP32Path path]] and + * then signs + */ def asyncSign( bytes: ByteVector, - path: BIP32Path): Future[ECDigitalSignature] = { + path: BIP32Path + ): Future[ECDigitalSignature] = { asyncDeriveAndSign(bytes, path) } } @@ -27,11 +31,14 @@ trait ExtSign extends AsyncExtSign with AdaptorSign { override def asyncDeriveAndSign( bytes: ByteVector, - path: BIP32Path): Future[ECDigitalSignature] = { + path: BIP32Path + ): Future[ECDigitalSignature] = { Future.successful(deriveAndSign(bytes, path)) } - /** First derives the child key that corresponds to [[BIP32Path path]] and then signs */ + /** First derives the child key that corresponds to [[BIP32Path path]] and + * then signs + */ def sign(bytes: ByteVector, path: BIP32Path): ECDigitalSignature = { deriveAndSign(bytes, path) } diff --git a/core/src/main/scala/org/bitcoins/core/crypto/MnemonicCode.scala b/core/src/main/scala/org/bitcoins/core/crypto/MnemonicCode.scala index e6976179b5..448e164476 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/MnemonicCode.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/MnemonicCode.scala @@ -7,12 +7,13 @@ import scodec.bits.{BitVector, ByteVector} import scala.annotation.tailrec -/** A mnemonic code conforming to [[https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki BIP39]]. - * BIP39 mnemonic codes consist of a varying number of words (most often English, - * possible with other languages as well) that can be used to generate an - * [[ExtPrivateKey ExtPrivateKey ]] which again - * can be the root of a [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]] - * HD wallet. +/** A mnemonic code conforming to + * [[https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki BIP39]]. + * BIP39 mnemonic codes consist of a varying number of words (most often + * English, possible with other languages as well) that can be used to generate + * an [[ExtPrivateKey ExtPrivateKey]] which again can be the root of a + * [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]] HD + * wallet. */ sealed abstract class MnemonicCode extends SeqWrapper[String] @@ -24,11 +25,13 @@ sealed abstract class MnemonicCode } ) - require({ - val entropy = toEntropyWithChecksum - MnemonicCode.isEntropyWithChecksumValid(entropy, words) - }, - "Entropy checksum is not valid!") + require( + { + val entropy = toEntropyWithChecksum + MnemonicCode.isEntropyWithChecksumValid(entropy, words) + }, + "Entropy checksum is not valid!" + ) /** The mnemonic code itself */ @@ -36,8 +39,7 @@ sealed abstract class MnemonicCode override protected lazy val wrapped: Vector[String] = words - /** Returns the entropy initially provided to construct - * this mnemonic code + /** Returns the entropy initially provided to construct this mnemonic code */ def toEntropy: BitVector = { val entropyWithChecksumBits = toEntropyWithChecksum @@ -48,8 +50,8 @@ sealed abstract class MnemonicCode entropyWithChecksumBits.take(lengthNoEntropy) } - /** Returns the entropy _with checksum_ originally provided - * to construct this mnemonic code + /** Returns the entropy _with checksum_ originally provided to construct this + * mnemonic code */ def toEntropyWithChecksum: BitVector = { @@ -95,7 +97,8 @@ sealed abstract class MnemonicCode } } -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki BIP39]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki BIP39]] */ object MnemonicCode { @@ -104,8 +107,7 @@ object MnemonicCode { */ private[crypto] val VALID_LENGTHS = Vector(12, 15, 18, 21, 24) - /** Length of bit groups entropy is split into to - * derive words from wordlist + /** Length of bit groups entropy is split into to derive words from wordlist */ private[crypto] val BIT_GROUP_LENGTH = 11 @@ -163,7 +165,8 @@ object MnemonicCode { } private[crypto] def fromEntropyWithCheck( - entropyWithChecksum: BitVector): MnemonicCode = { + entropyWithChecksum: BitVector + ): MnemonicCode = { val bitGroups = entropyWithChecksum.grouped(BIT_GROUP_LENGTH) val words = bitGroups.map { group => val index = group.toInt(signed = false) @@ -176,8 +179,10 @@ object MnemonicCode { /** Generates the specified bits of entropy */ private def getEntropy(bits: Int): BitVector = { - require(bits % 8 == 0, - s"Given amount if bits ($bits) must be a multiple of 8!") + require( + bits % 8 == 0, + s"Given amount if bits ($bits) must be a multiple of 8!" + ) val bytes = CryptoUtil.randomBytes(bits / 8) val bitVector = BitVector(bytes) @@ -212,13 +217,15 @@ object MnemonicCode { entropyBits: Int, checksumLength: Int, entropyAndChecksumBits: Int, - words: Int) + words: Int + ) /** Taken from * [[https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#generating-the-mnemonic BIP39]] */ private[crypto] def getMnemonicCodeInfo( - words: Vector[String]): MnemonicCodeInfo = + words: Vector[String] + ): MnemonicCodeInfo = words.length match { case 12 => MnemonicCodeInfo(128, 4, 132, 12) case 15 => MnemonicCodeInfo(160, 5, 165, 15) @@ -233,12 +240,12 @@ object MnemonicCode { EnglishWordsBip39.getWords }.ensuring(words => words.length == 2048, "Word list must be 2048 words long") - /** Checks that the provided entropy has a valid checksum - * attached at the end + /** Checks that the provided entropy has a valid checksum attached at the end */ def isEntropyWithChecksumValid( entropyWithChecksum: BitVector, - words: Vector[String]): Boolean = { + words: Vector[String] + ): Boolean = { val codeInfo = MnemonicCode.getMnemonicCodeInfo(words) val entropyNoChecksum = entropyWithChecksum.take(codeInfo.entropyBits) diff --git a/core/src/main/scala/org/bitcoins/core/crypto/TaprootSerializationOptions.scala b/core/src/main/scala/org/bitcoins/core/crypto/TaprootSerializationOptions.scala index ad63f444b3..f02d33e2e5 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/TaprootSerializationOptions.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/TaprootSerializationOptions.scala @@ -3,17 +3,18 @@ package org.bitcoins.core.crypto import org.bitcoins.core.number.UInt32 import org.bitcoins.crypto.Sha256Digest -/** Options for the taproot signature serialization algorithm as defined - * in BIP341 +/** Options for the taproot signature serialization algorithm as defined in + * BIP341 */ case class TaprootSerializationOptions( tapLeafHashOpt: Option[Sha256Digest], annexHashOpt: Option[Sha256Digest], - codeSeparatorPosOpt: Option[UInt32]) { + codeSeparatorPosOpt: Option[UInt32] +) { def haveAnnex: Boolean = annexHashOpt.isDefined def codeSeparatorPos: UInt32 = { - //defaults to UInt32 max if not defined in BIP341 + // defaults to UInt32 max if not defined in BIP341 codeSeparatorPosOpt.getOrElse(UInt32.max) } } @@ -21,7 +22,9 @@ case class TaprootSerializationOptions( object TaprootSerializationOptions { val empty: TaprootSerializationOptions = - TaprootSerializationOptions(tapLeafHashOpt = None, - annexHashOpt = None, - codeSeparatorPosOpt = None) + TaprootSerializationOptions( + tapLeafHashOpt = None, + annexHashOpt = None, + codeSeparatorPosOpt = None + ) } diff --git a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala index 366dab1f1e..d1692627c3 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureChecker.scala @@ -26,62 +26,75 @@ import scodec.bits.ByteVector import scala.annotation.tailrec -/** Created by chris on 2/16/16. - * Responsible for checking digital signatures on inputs against their respective - * public keys +/** Created by chris on 2/16/16. Responsible for checking digital signatures on + * inputs against their respective public keys */ trait TransactionSignatureChecker { def checkSignature( txSignatureComponent: TxSigComponent, pubKeyBytes: ECPublicKeyBytes, - signature: ECDigitalSignature): TransactionSignatureCheckerResult = - checkSignature(txSignatureComponent, - PartialSignature(pubKeyBytes, signature)) + signature: ECDigitalSignature + ): TransactionSignatureCheckerResult = + checkSignature( + txSignatureComponent, + PartialSignature(pubKeyBytes, signature) + ) def checkSignature( txSignatureComponent: TxSigComponent, pubKey: ECPublicKey, - signature: ECDigitalSignature): TransactionSignatureCheckerResult = + signature: ECDigitalSignature + ): TransactionSignatureCheckerResult = checkSignature(txSignatureComponent, PartialSignature(pubKey, signature)) def checkSignature( txSignatureComponent: TxSigComponent, - partialSignature: PartialSignature): TransactionSignatureCheckerResult = { - checkSignature(txSignatureComponent, - txSignatureComponent.output.scriptPubKey.asm.toList, - partialSignature.pubKey, - partialSignature.signature) + partialSignature: PartialSignature + ): TransactionSignatureCheckerResult = { + checkSignature( + txSignatureComponent, + txSignatureComponent.output.scriptPubKey.asm.toList, + partialSignature.pubKey, + partialSignature.signature + ) } def checkSignature( txSignatureComponent: TxSigComponent, script: Seq[ScriptToken], - partialSignature: PartialSignature): TransactionSignatureCheckerResult = - checkSignature(txSignatureComponent, - script, - partialSignature.pubKey, - partialSignature.signature) + partialSignature: PartialSignature + ): TransactionSignatureCheckerResult = + checkSignature( + txSignatureComponent, + script, + partialSignature.pubKey, + partialSignature.signature + ) /** @param txSigComponent * @param schnorrSignature * @param pubKey - * @see https://github.com/bitcoin/bitcoin/blob/8ae4ba481ce8f7da173bef24432729c87a36cb70/src/script/interpreter.cpp#L1695 + * @see + * https://github.com/bitcoin/bitcoin/blob/8ae4ba481ce8f7da173bef24432729c87a36cb70/src/script/interpreter.cpp#L1695 * @return */ def checkSchnorrSignature( txSigComponent: TxSigComponent, pubKey: SchnorrPublicKey, witness: TaprootKeyPath, - taprootOptions: TaprootSerializationOptions): ScriptResult = { + taprootOptions: TaprootSerializationOptions + ): ScriptResult = { if (witness.hashTypeOpt.contains(HashType.sigHashDefault)) { ScriptErrorSchnorrSigHashType } else { - checkSchnorrSignature(txSigComponent = txSigComponent, - pubKey = pubKey, - schnorrSignature = witness.signature, - hashType = witness.hashType, - taprootOptions) + checkSchnorrSignature( + txSigComponent = txSigComponent, + pubKey = pubKey, + schnorrSignature = witness.signature, + hashType = witness.hashType, + taprootOptions + ) } } @@ -90,67 +103,82 @@ trait TransactionSignatureChecker { pubKey: SchnorrPublicKey, schnorrSignature: SchnorrDigitalSignature, hashType: HashType, - taprootOptions: TaprootSerializationOptions): ScriptResult = { + taprootOptions: TaprootSerializationOptions + ): ScriptResult = { require( txSigComponent.sigVersion == SigVersionTaprootKeySpend || txSigComponent.sigVersion == SigVersionTapscript, s"SigVerison must be Taproot or Tapscript, got=${txSigComponent.sigVersion}" ) - //bip341 restricts valid hash types: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message + // bip341 restricts valid hash types: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message val validHashType = checkTaprootHashType(hashType) if (!validHashType) { ScriptErrorSchnorrSigHashType } else { val hash = - TransactionSignatureSerializer.hashForSignature(txSigComponent, - hashType, - taprootOptions) + TransactionSignatureSerializer.hashForSignature( + txSigComponent, + hashType, + taprootOptions + ) val result = pubKey.verify(hash, schnorrSignature) if (result) ScriptOk else ScriptErrorSchnorrSig } } // (hash_type <= 0x03 || (hash_type >= 0x81 && hash_type <= 0x83)) - private val validTaprootHashTypes: Vector[Byte] = Vector(0x00.toByte, - 0x01.toByte, - 0x02.toByte, - 0x03.toByte, - 0x81.toByte, - 0x82.toByte, - 0x83.toByte) + private val validTaprootHashTypes: Vector[Byte] = Vector( + 0x00.toByte, + 0x01.toByte, + 0x02.toByte, + 0x03.toByte, + 0x81.toByte, + 0x82.toByte, + 0x83.toByte + ) def checkTaprootHashType(hashType: HashType): Boolean = { validTaprootHashTypes.contains(hashType.byte) } - /** Checks the signature of a scriptSig in the spending transaction against the - * given scriptPubKey & explicitly given public key - * This is useful for instances of non standard scriptSigs + /** Checks the signature of a scriptSig in the spending transaction against + * the given scriptPubKey & explicitly given public key This is useful for + * instances of non standard scriptSigs * - * @param txSignatureComponent the relevant transaction information for signature checking - * @param script the current script state inside the interpreter - this is needed in the case of OP_CODESEPARATORS - * @param pubKey the public key the signature is being checked against - * @param signature the signature which is being checked against the transaction & the public key - * @param flags the script flags used to check validity of the signature - * @return a boolean indicating if the signature is valid or not + * @param txSignatureComponent + * the relevant transaction information for signature checking + * @param script + * the current script state inside the interpreter - this is needed in the + * case of OP_CODESEPARATORS + * @param pubKey + * the public key the signature is being checked against + * @param signature + * the signature which is being checked against the transaction & the + * public key + * @param flags + * the script flags used to check validity of the signature + * @return + * a boolean indicating if the signature is valid or not */ def checkSignature( txSignatureComponent: TxSigComponent, script: Seq[ScriptToken], pubKey: ECPublicKeyBytes, signature: ECDigitalSignature, - flags: Seq[ScriptFlag] = - Policy.standardFlags): TransactionSignatureCheckerResult = { + flags: Seq[ScriptFlag] = Policy.standardFlags + ): TransactionSignatureCheckerResult = { txSignatureComponent.sigVersion match { case SigVersionTapscript | SigVersionTaprootKeySpend => sys.error( - s"Call checkTapScript signature to validate a tapscript signature") + s"Call checkTapScript signature to validate a tapscript signature" + ) case SigVersionWitnessV0 | SigVersionBase => val pubKeyEncodedCorrectly = BitcoinScriptUtil.isValidPubKeyEncoding( pubKey, txSignatureComponent.sigVersion, - flags) + flags + ) if ( ScriptFlagUtil.requiresStrictDerEncoding(flags) && !DERSignatureUtil .isValidSignatureEncoding(signature) @@ -163,7 +191,8 @@ trait TransactionSignatureChecker { SignatureValidationErrorHighSValue } else if ( ScriptFlagUtil.requireStrictEncoding( - flags) && signature.bytes.nonEmpty && + flags + ) && signature.bytes.nonEmpty && !HashType.isDefinedHashtypeSignature(signature) ) { SignatureValidationErrorHashType @@ -178,48 +207,57 @@ trait TransactionSignatureChecker { val sigsRemovedScript = BitcoinScriptUtil.calculateScriptForChecking( txSignatureComponent, signature, - script) + script + ) val hashTypeByte = if (signature.bytes.nonEmpty) signature.bytes.last else 0x00.toByte val hashType = HashType( - ByteVector(0.toByte, 0.toByte, 0.toByte, hashTypeByte)) + ByteVector(0.toByte, 0.toByte, 0.toByte, hashTypeByte) + ) val spk = ScriptPubKey.fromAsm(sigsRemovedScript) val hashForSignature = txSignatureComponent match { case w: WitnessTxSigComponent => TransactionSignatureSerializer.hashForSignature( w, hashType, - TaprootSerializationOptions.empty) + TaprootSerializationOptions.empty + ) case b: BaseTxSigComponent => val sigsRemovedTxSigComponent = BaseTxSigComponent( b.transaction, b.inputIndex, TransactionOutput(b.output.value, spk), - b.flags) + b.flags + ) TransactionSignatureSerializer.hashForSignature( sigsRemovedTxSigComponent, hashType, - TaprootSerializationOptions.empty) + TaprootSerializationOptions.empty + ) case r: WitnessTxSigComponentRebuilt => val sigsRemovedTxSigComponent = WitnessTxSigComponentRebuilt( wtx = r.transaction, inputIndex = r.inputIndex, output = TransactionOutput(r.output.value, spk), witScriptPubKey = r.witnessScriptPubKey, - flags = r.flags) + flags = r.flags + ) TransactionSignatureSerializer.hashForSignature( sigsRemovedTxSigComponent, hashType, - TaprootSerializationOptions.empty) + TaprootSerializationOptions.empty + ) } val sigWithoutHashType = stripHashType(signature) val isValid = pubKey.verify(hashForSignature, sigWithoutHashType) if (isValid) SignatureValidationSuccess else - nullFailCheck(Seq(signature), - SignatureValidationErrorIncorrectSignatures, - flags) + nullFailCheck( + Seq(signature), + SignatureValidationErrorIncorrectSignatures, + flags + ) } } } @@ -230,31 +268,45 @@ trait TransactionSignatureChecker { signature: SchnorrDigitalSignature, hashType: HashType, taprootOptions: TaprootSerializationOptions, - flags: Seq[ScriptFlag]): TransactionSignatureCheckerResult = { + flags: Seq[ScriptFlag] + ): TransactionSignatureCheckerResult = { val hash = - TransactionSignatureSerializer.hashForSignature(txSignatureComponent, - hashType, - taprootOptions) + TransactionSignatureSerializer.hashForSignature( + txSignatureComponent, + hashType, + taprootOptions + ) val result = pubKey.verify(hash, signature) if (result) { SignatureValidationSuccess } else { - nullFailCheckSchnorrSig(sigs = Vector(signature), - result = - SignatureValidationErrorIncorrectSignatures, - flags = flags) + nullFailCheckSchnorrSig( + sigs = Vector(signature), + result = SignatureValidationErrorIncorrectSignatures, + flags = flags + ) } } /** This is a helper function to check digital signatures against public keys * if the signature does not match this public key, check it against the next * public key in the sequence - * @param txSignatureComponent the tx signature component that contains all relevant transaction information - * @param script the script state this is needed in case there is an OP_CODESEPARATOR inside the script - * @param sigs the signatures that are being checked for validity - * @param pubKeys the public keys which are needed to verify that the signatures are correct - * @param flags the script verify flags which are rules to verify the signatures - * @return a boolean indicating if all of the signatures are valid against the given public keys + * @param txSignatureComponent + * the tx signature component that contains all relevant transaction + * information + * @param script + * the script state this is needed in case there is an OP_CODESEPARATOR + * inside the script + * @param sigs + * the signatures that are being checked for validity + * @param pubKeys + * the public keys which are needed to verify that the signatures are + * correct + * @param flags + * the script verify flags which are rules to verify the signatures + * @return + * a boolean indicating if all of the signatures are valid against the + * given public keys */ @tailrec final def multiSignatureEvaluator( @@ -263,17 +315,20 @@ trait TransactionSignatureChecker { sigs: List[ECDigitalSignature], pubKeys: List[ECPublicKeyBytes], flags: Seq[ScriptFlag], - requiredSigs: Long): TransactionSignatureCheckerResult = { - require(requiredSigs >= 0, - s"requiredSigs cannot be negative, got $requiredSigs") + requiredSigs: Long + ): TransactionSignatureCheckerResult = { + require( + requiredSigs >= 0, + s"requiredSigs cannot be negative, got $requiredSigs" + ) if (sigs.size > pubKeys.size) { - //this is how bitcoin core treats this. If there are ever any more - //signatures than public keys remaining we immediately return - //false https://github.com/bitcoin/bitcoin/blob/8c1dbc5e9ddbafb77e60e8c4e6eb275a3a76ac12/src/script/interpreter.cpp#L943-L945 + // this is how bitcoin core treats this. If there are ever any more + // signatures than public keys remaining we immediately return + // false https://github.com/bitcoin/bitcoin/blob/8c1dbc5e9ddbafb77e60e8c4e6eb275a3a76ac12/src/script/interpreter.cpp#L943-L945 nullFailCheck(sigs, SignatureValidationErrorIncorrectSignatures, flags) } else if (requiredSigs > sigs.size) { - //for the case when we do not have enough sigs left to check to meet the required signature threshold - //https://github.com/bitcoin/bitcoin/blob/8c1dbc5e9ddbafb77e60e8c4e6eb275a3a76ac12/src/script/interpreter.cpp#L990-L991 + // for the case when we do not have enough sigs left to check to meet the required signature threshold + // https://github.com/bitcoin/bitcoin/blob/8c1dbc5e9ddbafb77e60e8c4e6eb275a3a76ac12/src/script/interpreter.cpp#L990-L991 nullFailCheck(sigs, SignatureValidationErrorSignatureCount, flags) } else if (sigs.nonEmpty && pubKeys.nonEmpty) { val sig = sigs.head @@ -282,23 +337,27 @@ trait TransactionSignatureChecker { checkSignature(txSignatureComponent, script, pubKey, sig, flags) result match { case SignatureValidationSuccess => - multiSignatureEvaluator(txSignatureComponent, - script, - sigs.tail, - pubKeys.tail, - flags, - requiredSigs - 1) + multiSignatureEvaluator( + txSignatureComponent, + script, + sigs.tail, + pubKeys.tail, + flags, + requiredSigs - 1 + ) case SignatureValidationErrorIncorrectSignatures | SignatureValidationErrorNullFail => - //notice we pattern match on 'SignatureValidationErrorNullFail' here, this is because - //'checkSignature' may return that result, but we need to continue evaluating the signatures - //in the multisig script, we don't check for nullfail until evaluation the OP_CHECKMULTSIG is completely done - multiSignatureEvaluator(txSignatureComponent, - script, - sigs, - pubKeys.tail, - flags, - requiredSigs) + // notice we pattern match on 'SignatureValidationErrorNullFail' here, this is because + // 'checkSignature' may return that result, but we need to continue evaluating the signatures + // in the multisig script, we don't check for nullfail until evaluation the OP_CHECKMULTSIG is completely done + multiSignatureEvaluator( + txSignatureComponent, + script, + sigs, + pubKeys.tail, + flags, + requiredSigs + ) case x @ (SignatureValidationErrorNotStrictDerEncoding | SignatureValidationErrorSignatureCount | SignatureValidationErrorPubKeyEncoding | @@ -308,24 +367,26 @@ trait TransactionSignatureChecker { nullFailCheck(sigs, x, flags) } } else if (sigs.isEmpty) { - //means that we have checked all of the sigs against the public keys - //validation succeeds + // means that we have checked all of the sigs against the public keys + // validation succeeds SignatureValidationSuccess } else nullFailCheck(sigs, SignatureValidationErrorIncorrectSignatures, flags) } - /** If the NULLFAIL flag is set as defined in BIP146, it checks to make sure all failed signatures were an empty byte vector + /** If the NULLFAIL flag is set as defined in BIP146, it checks to make sure + * all failed signatures were an empty byte vector * [[https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#NULLFAIL]] */ private def nullFailCheck( sigs: Seq[ECDigitalSignature], result: TransactionSignatureCheckerResult, - flags: Seq[ScriptFlag]): TransactionSignatureCheckerResult = { + flags: Seq[ScriptFlag] + ): TransactionSignatureCheckerResult = { val nullFailEnabled = ScriptFlagUtil.requireScriptVerifyNullFail(flags) if (nullFailEnabled && !result.isValid && sigs.exists(_.bytes.nonEmpty)) { - //we need to check that all signatures were empty byte vectors, else this fails because of BIP146 and nullfail + // we need to check that all signatures were empty byte vectors, else this fails because of BIP146 and nullfail SignatureValidationErrorNullFail } else result } @@ -333,10 +394,11 @@ trait TransactionSignatureChecker { private def nullFailCheckSchnorrSig( sigs: Seq[SchnorrDigitalSignature], result: TransactionSignatureCheckerResult, - flags: Seq[ScriptFlag]): TransactionSignatureCheckerResult = { + flags: Seq[ScriptFlag] + ): TransactionSignatureCheckerResult = { val nullFailEnabled = ScriptFlagUtil.requireScriptVerifyNullFail(flags) if (nullFailEnabled && !result.isValid && sigs.exists(_.bytes.nonEmpty)) { - //we need to check that all signatures were empty byte vectors, else this fails because of BIP146 and nullfail + // we need to check that all signatures were empty byte vectors, else this fails because of BIP146 and nullfail SignatureValidationErrorNullFail } else result } diff --git a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCheckerResult.scala b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCheckerResult.scala index 6dfac02600..f0681277ea 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCheckerResult.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCheckerResult.scala @@ -9,8 +9,8 @@ sealed trait TransactionSignatureCheckerResult { def isValid: Boolean } -/** Represents the case that the signatures checked inside of the transaction were - * all validly encoded as per the script verify flag & that the signatures +/** Represents the case that the signatures checked inside of the transaction + * were all validly encoded as per the script verify flag & that the signatures * were valid when checked against the public keys */ case object SignatureValidationSuccess @@ -18,38 +18,44 @@ case object SignatureValidationSuccess def isValid = true } -/** Indicates that there was an error when evaluating the signature of a transaction */ +/** Indicates that there was an error when evaluating the signature of a + * transaction + */ sealed trait SignatureValidationError extends TransactionSignatureCheckerResult { def isValid = false } -/** Signature validation failed because a signature was not encoded - * per the BIP66 rules [[https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki#specification]] +/** Signature validation failed because a signature was not encoded per the + * BIP66 rules + * [[https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki#specification]] */ case object SignatureValidationErrorNotStrictDerEncoding extends SignatureValidationError -/** Signature validation failed because there were not enough correct signatures for the transaction - * we were given +/** Signature validation failed because there were not enough correct signatures + * for the transaction we were given */ case object SignatureValidationErrorIncorrectSignatures extends SignatureValidationError -/** This indicates that the signature validation failed because we have more signatures left to check - * than public keys remaining to check them against - * see [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L914-915]] +/** This indicates that the signature validation failed because we have more + * signatures left to check than public keys remaining to check them against + * see + * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L914-915]] */ case object SignatureValidationErrorSignatureCount extends SignatureValidationError -/** This indicates that the public key was not encoded correctly according to this function +/** This indicates that the public key was not encoded correctly according to + * this function * [[https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L214-L223]] */ case object SignatureValidationErrorPubKeyEncoding extends SignatureValidationError -/** This indicates that the digital signature did not have a Low S value as per BIP62 +/** This indicates that the digital signature did not have a Low S value as per + * BIP62 * [[https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures]] */ case object SignatureValidationErrorHighSValue extends SignatureValidationError @@ -58,14 +64,14 @@ case object SignatureValidationErrorHighSValue extends SignatureValidationError */ case object SignatureValidationErrorHashType extends SignatureValidationError -/** Fails the script if the given public key was not compressed and the [[org.bitcoins.core.script.flag.ScriptVerifyWitnessPubKeyType]] - * flag was set +/** Fails the script if the given public key was not compressed and the + * [[org.bitcoins.core.script.flag.ScriptVerifyWitnessPubKeyType]] flag was set */ case object SignatureValidationErrorWitnessPubKeyType extends SignatureValidationError -/** Fails the script if a an invalid signature is not an empty byte vector - * See BIP146 +/** Fails the script if a an invalid signature is not an empty byte vector See + * BIP146 * [[https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#nullfail]] */ case object SignatureValidationErrorNullFail extends SignatureValidationError diff --git a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCreator.scala b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCreator.scala index 89b906e19f..291d8d6561 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCreator.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureCreator.scala @@ -19,59 +19,78 @@ sealed abstract class TransactionSignatureCreator { /** Creates a signature from a tx signature component * - * @param txSignatureComponent contains the tx, inputIndex which specify which input we are creating a sig for - * @param privateKey the private key which we are signing the hash with - * @param hashType the procedure to use for hashing to transaction + * @param txSignatureComponent + * contains the tx, inputIndex which specify which input we are creating a + * sig for + * @param privateKey + * the private key which we are signing the hash with + * @param hashType + * the procedure to use for hashing to transaction * @return */ def createSig( txSignatureComponent: TxSigComponent, privateKey: ECPrivateKey, - hashType: HashType): ECDigitalSignature = { + hashType: HashType + ): ECDigitalSignature = { val sign: ByteVector => ECDigitalSignature = privateKey.sign(_: ByteVector) createSig(txSignatureComponent, sign, hashType) } - /** This is intended to be a low level hardware wallet API. - * At a fundamental level, a hardware wallet expects a scodec.bits.ByteVector as input, and returns an [[ECDigitalSignature]] - * if it is able to sign the scodec.bits.ByteVector's correctly. - * @param component - the information needed to sign the transaction - * @param sign - the implementation of the hardware wallet protocol to sign the scodec.bits.ByteVector w/ the given public key - * @param hashType - the hash type to be appended on the digital signature when the hardware wallet is done being signed - * @return the digital signature returned by the hardware wallet + /** This is intended to be a low level hardware wallet API. At a fundamental + * level, a hardware wallet expects a scodec.bits.ByteVector as input, and + * returns an [[ECDigitalSignature]] if it is able to sign the + * scodec.bits.ByteVector's correctly. + * @param component + * \- the information needed to sign the transaction + * @param sign + * \- the implementation of the hardware wallet protocol to sign the + * scodec.bits.ByteVector w/ the given public key + * @param hashType + * \- the hash type to be appended on the digital signature when the + * hardware wallet is done being signed + * @return + * the digital signature returned by the hardware wallet */ def createSig( component: TxSigComponent, sign: ByteVector => ECDigitalSignature, - hashType: HashType): ECDigitalSignature = { + hashType: HashType + ): ECDigitalSignature = { val hash = TransactionSignatureSerializer.hashForSignature( component, hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) val signature = sign(hash.bytes) - //append 1 byte hash type onto the end + // append 1 byte hash type onto the end val sig = ECDigitalSignature( - signature.bytes ++ ByteVector.fromByte(hashType.byte)) + signature.bytes ++ ByteVector.fromByte(hashType.byte) + ) require( sig.isStrictEncoded, - "We did not create a signature that is strictly encoded, got: " + sig) + "We did not create a signature that is strictly encoded, got: " + sig + ) require(DERSignatureUtil.isLowS(sig), "Sig does not have a low s value") sig } - /** This is the same as createSig above, except the 'sign' function returns a Future[ECDigitalSignature] */ + /** This is the same as createSig above, except the 'sign' function returns a + * Future[ECDigitalSignature] + */ @deprecated("use an InputSigningInfo[InputInfo] instead", since = "6/23/2020") def createSig( component: TxSigComponent, sign: ByteVector => Future[ECDigitalSignature], - hashType: HashType)(implicit - ec: ExecutionContext): Future[ECDigitalSignature] = { + hashType: HashType + )(implicit ec: ExecutionContext): Future[ECDigitalSignature] = { val hash = TransactionSignatureSerializer.hashForSignature( component, hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) val signature = sign(hash.bytes) // append 1 byte hash type onto the end val sig = signature.map(s => @@ -79,7 +98,8 @@ sealed abstract class TransactionSignatureCreator { sig.map { s => require( s.isStrictEncoded, - "We did not create a signature that is strictly encoded, got: " + sig) + "We did not create a signature that is strictly encoded, got: " + sig + ) require(DERSignatureUtil.isLowS(s), "Sig does not have a low s value") s } @@ -87,61 +107,77 @@ sealed abstract class TransactionSignatureCreator { /** Creates a signature from a tx signature component * - * @param privateKey the private key which we are signing the hash with - * @param hashType the procedure to use for hashing to transaction + * @param privateKey + * the private key which we are signing the hash with + * @param hashType + * the procedure to use for hashing to transaction * @return */ def createSig( spendingTransaction: Transaction, signingInfo: InputSigningInfo[InputInfo], privateKey: ECPrivateKey, - hashType: HashType): ECDigitalSignature = { + hashType: HashType + ): ECDigitalSignature = { val sign: ByteVector => ECDigitalSignature = privateKey.sign(_: ByteVector) createSig(spendingTransaction, signingInfo, sign, hashType) } - /** This is intended to be a low level hardware wallet API. - * At a fundamental level, a hardware wallet expects a scodec.bits.ByteVector as input, and returns an [[ECDigitalSignature]] - * if it is able to sign the scodec.bits.ByteVector's correctly. - * @param sign - the implementation of the hardware wallet protocol to sign the scodec.bits.ByteVector w/ the given public key - * @param hashType - the hash type to be appended on the digital signature when the hardware wallet is done being signed - * @return the digital signature returned by the hardware wallet + /** This is intended to be a low level hardware wallet API. At a fundamental + * level, a hardware wallet expects a scodec.bits.ByteVector as input, and + * returns an [[ECDigitalSignature]] if it is able to sign the + * scodec.bits.ByteVector's correctly. + * @param sign + * \- the implementation of the hardware wallet protocol to sign the + * scodec.bits.ByteVector w/ the given public key + * @param hashType + * \- the hash type to be appended on the digital signature when the + * hardware wallet is done being signed + * @return + * the digital signature returned by the hardware wallet */ def createSig( spendingTransaction: Transaction, signingInfo: InputSigningInfo[InputInfo], sign: ByteVector => ECDigitalSignature, - hashType: HashType): ECDigitalSignature = { + hashType: HashType + ): ECDigitalSignature = { val hash = TransactionSignatureSerializer.hashForSignature( spendingTransaction = spendingTransaction, signingInfo = signingInfo, hashType = hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) val signature = sign(hash.bytes) - //append 1 byte hash type onto the end + // append 1 byte hash type onto the end val sig = ECDigitalSignature( - signature.bytes ++ ByteVector.fromByte(hashType.byte)) + signature.bytes ++ ByteVector.fromByte(hashType.byte) + ) require( sig.isStrictEncoded, - "We did not create a signature that is strictly encoded, got: " + sig) + "We did not create a signature that is strictly encoded, got: " + sig + ) require(DERSignatureUtil.isLowS(sig), "Sig does not have a low s value") sig } - /** This is the same as createSig above, except the 'sign' function returns a Future[ECDigitalSignature] */ + /** This is the same as createSig above, except the 'sign' function returns a + * Future[ECDigitalSignature] + */ def createSig( spendingTransaction: Transaction, signingInfo: InputSigningInfo[InputInfo], sign: ByteVector => Future[ECDigitalSignature], - hashType: HashType)(implicit - ec: ExecutionContext): Future[ECDigitalSignature] = { + hashType: HashType + )(implicit ec: ExecutionContext): Future[ECDigitalSignature] = { val hash = TransactionSignatureSerializer.hashForSignature( spendingTransaction, signingInfo, hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) val signature = sign(hash.bytes) // append 1 byte hash type onto the end val sig = signature.map(s => @@ -149,7 +185,8 @@ sealed abstract class TransactionSignatureCreator { sig.map { s => require( s.isStrictEncoded, - "We did not create a signature that is strictly encoded, got: " + sig) + "We did not create a signature that is strictly encoded, got: " + sig + ) require(DERSignatureUtil.isLowS(s), "Sig does not have a low s value") s } @@ -158,12 +195,14 @@ sealed abstract class TransactionSignatureCreator { def createSig( component: TxSigComponent, adaptorSign: ByteVector => ECAdaptorSignature, - hashType: HashType): ECAdaptorSignature = { + hashType: HashType + ): ECAdaptorSignature = { val hash = TransactionSignatureSerializer.hashForSignature( component, hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) adaptorSign(hash.bytes) } } diff --git a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureSerializer.scala b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureSerializer.scala index f83eeb9b3f..5f5909bd43 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/TransactionSignatureSerializer.scala @@ -12,56 +12,64 @@ import org.bitcoins.core.wallet.utxo.{InputInfo, InputSigningInfo} import org.bitcoins.crypto._ import scodec.bits.ByteVector -/** Created by chris on 2/16/16. - * Wrapper that serializes like Transaction, but with the modifications - * required for the signature hash done +/** Created by chris on 2/16/16. Wrapper that serializes like Transaction, but + * with the modifications required for the signature hash done * [[https://github.com/bitcoin/bitcoin/blob/93c85d458ac3e2c496c1a053e1f5925f55e29100/src/script/interpreter.cpp#L1016-L1105]] * bitcoinj version of this * [[https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/org/bitcoinj/core/Transaction.java#L924-L1008]] */ sealed abstract class TransactionSignatureSerializer { - /** Bitcoin Core's bug is that SignatureHash was supposed to return a hash and on this codepath it - * actually returns the constant "1" to indicate an error + /** Bitcoin Core's bug is that SignatureHash was supposed to return a hash and + * on this codepath it actually returns the constant "1" to indicate an error */ private lazy val errorHash: DoubleSha256Digest = DoubleSha256Digest( BytesUtil.decodeHex( - "0100000000000000000000000000000000000000000000000000000000000000")) + "0100000000000000000000000000000000000000000000000000000000000000" + ) + ) - /** Implements the signature serialization algorithim that Satoshi Nakamoto originally created - * and the new signature serialization algorithm as specified by + /** Implements the signature serialization algorithim that Satoshi Nakamoto + * originally created and the new signature serialization algorithm as + * specified by * [[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki BIP143]]. * [[https://github.com/bitcoin/bitcoin/blob/f8528134fc188abc5c7175a19680206964a8fade/src/script/interpreter.cpp#L1113]] */ def serializeForSignature( txSigComponent: TxSigComponent, hashType: HashType, - taprootOptions: TaprootSerializationOptions): ByteVector = { + taprootOptions: TaprootSerializationOptions + ): ByteVector = { val spendingTransaction = txSigComponent.transaction val inputIndex = txSigComponent.inputIndex val output = txSigComponent.output val script = BitcoinScriptUtil.calculateScriptForSigning( txSigComponent, - output.scriptPubKey.asm) + output.scriptPubKey.asm + ) txSigComponent match { case _: BaseTxSigComponent | _: WitnessTxSigComponentRaw | _: WitnessTxSigComponentRebuilt => - serializeForSignature(spendingTransaction, - inputIndex, - hashType, - Vector(output), - script, - txSigComponent.sigVersion, - taprootOptions) + serializeForSignature( + spendingTransaction, + inputIndex, + hashType, + Vector(output), + script, + txSigComponent.sigVersion, + taprootOptions + ) case t: TaprootTxSigComponent => - serializeForSignature(spendingTransaction, - inputIndex, - hashType, - t.outputs, - script, - txSigComponent.sigVersion, - taprootOptions) + serializeForSignature( + spendingTransaction, + inputIndex, + hashType, + t.outputs, + script, + txSigComponent.sigVersion, + taprootOptions + ) } } @@ -73,14 +81,16 @@ sealed abstract class TransactionSignatureSerializer { outputs: Vector[TransactionOutput], script: Seq[ScriptToken], sigVersion: SignatureVersion, - taprootOptions: TaprootSerializationOptions): ByteVector = { + taprootOptions: TaprootSerializationOptions + ): ByteVector = { val keyVersion: Byte = 0.toByte sigVersion match { case SigVersionBase => require( outputs.length == 1, - s"Only one output needed for the original satoshis signature algorithm, got=$outputs") + s"Only one output needed for the original satoshis signature algorithm, got=$outputs" + ) // Clear input scripts in preparation for signing. If we're signing a fresh // CScript's inside the Bitcoin Core codebase retain their compactSizeUInt // while clearing out all of the actual asm operations in the CScript @@ -90,12 +100,15 @@ sealed abstract class TransactionSignatureSerializer { } yield TransactionInput( input.previousOutput, NonStandardScriptSignature(s.compactSizeUInt.hex), - input.sequence) + input.sequence + ) - //make sure all scriptSigs have empty asm + // make sure all scriptSigs have empty asm inputSigsRemoved.foreach(input => - require(input.scriptSignature.asm.isEmpty, - "Input asm was not empty " + input.scriptSignature.asm)) + require( + input.scriptSignature.asm.isEmpty, + "Input asm was not empty " + input.scriptSignature.asm + )) // This step has no purpose beyond being synchronized with Bitcoin Core's bugs. OP_CODESEPARATOR // is a legacy holdover from a previous, broken design of executing scripts that shipped in Bitcoin 0.1. @@ -117,9 +130,10 @@ sealed abstract class TransactionSignatureSerializer { val inputWithConnectedScript = TransactionInput( inputToSign.previousOutput, scriptSig, - inputToSign.sequence) + inputToSign.sequence + ) - //update the input at index i with inputWithConnectScript + // update the input at index i with inputWithConnectScript val updatedInputs = for { (input, index) <- inputSigsRemoved.zipWithIndex } yield { @@ -132,7 +146,8 @@ sealed abstract class TransactionSignatureSerializer { spendingTransaction.version, updatedInputs, spendingTransaction.outputs, - spendingTransaction.lockTime) + spendingTransaction.lockTime + ) val sigHashBytes = Int32(hashType.num).bytes.reverse hashType match { @@ -166,7 +181,8 @@ sealed abstract class TransactionSignatureSerializer { case _: SIGHASH_ANYONECANPAY => val txWithInputsRemoved = sigHashAnyoneCanPay( txWithInputSigsRemoved, - inputWithConnectedScript) + inputWithConnectedScript + ) txWithInputsRemoved.bytes ++ sigHashBytes case _: SIGHASH_ALL_ANYONECANPAY => @@ -191,7 +207,8 @@ sealed abstract class TransactionSignatureSerializer { case SigVersionWitnessV0 => require( outputs.length == 1, - s"Only one output needed for the original satoshis signature algorithm, got=$outputs") + s"Only one output needed for the original satoshis signature algorithm, got=$outputs" + ) val output = outputs.head val amount = output.value val isNotAnyoneCanPay = !HashType.isAnyoneCanPay(hashType) @@ -238,7 +255,8 @@ sealed abstract class TransactionSignatureSerializer { i.previousOutput.bytes ++ CompactSizeUInt.calc(scriptBytes).bytes ++ scriptBytes ++ amount.bytes ++ i.sequence.bytes.reverse ++ outputHash ++ spendingTransaction.lockTime.bytes.reverse ++ Int32( - hashType.num).bytes.reverse + hashType.num + ).bytes.reverse serializationForSig case taprootSigVersion: SigVersionTaproot => @@ -327,8 +345,10 @@ sealed abstract class TransactionSignatureSerializer { val tapScriptBytes = { if (sigVersion == SigVersionTapscript) { - require(taprootOptions.tapLeafHashOpt.isDefined, - "Must have a tapleaf hash to verify a tapscript") + require( + taprootOptions.tapLeafHashOpt.isDefined, + "Must have a tapleaf hash to verify a tapscript" + ) taprootOptions.tapLeafHashOpt.get.bytes ++ ByteVector.fromByte(keyVersion) ++ codeSeparatorPos.bytes.reverse @@ -347,14 +367,17 @@ sealed abstract class TransactionSignatureSerializer { if (isNotAnyoneCanPay) { if (!isNotSigHashSingle) { epoch ++ ByteVector.fromByte( - hashType.byte) ++ version ++ locktimeBytes ++ + hashType.byte + ) ++ version ++ locktimeBytes ++ outPointHash ++ amounts ++ spentSPKs ++ sequenceHash ++ ByteVector.fromByte( - spendType) ++ inputIndexBytes ++ + spendType + ) ++ inputIndexBytes ++ annexBytes ++ outputHash ++ tapScriptBytes } else { epoch ++ ByteVector.fromByte( - hashType.byte) ++ version ++ locktimeBytes ++ + hashType.byte + ) ++ version ++ locktimeBytes ++ outPointHash ++ amounts ++ spentSPKs ++ sequenceHash ++ outputHash ++ ByteVector.fromByte(spendType) ++ @@ -363,17 +386,20 @@ sealed abstract class TransactionSignatureSerializer { } else { if (isSigHashAllAnyoneCanPay) { - //different ordering if we use SIGHASH_ANYONECANPAY + // different ordering if we use SIGHASH_ANYONECANPAY epoch ++ ByteVector .fromByte( - hashType.byte) ++ version ++ locktimeBytes ++ outputHash ++ + hashType.byte + ) ++ version ++ locktimeBytes ++ outputHash ++ ByteVector.fromByte( - spendType) ++ outPointHash ++ amounts ++ spentSPKs ++ + spendType + ) ++ outPointHash ++ amounts ++ spentSPKs ++ sequenceHash ++ annexBytes ++ tapScriptBytes } else { - //different ordering if we use SIGHASH_ANYONECANPAY + // different ordering if we use SIGHASH_ANYONECANPAY epoch ++ ByteVector.fromByte( - hashType.byte) ++ version ++ locktimeBytes ++ ByteVector + hashType.byte + ) ++ version ++ locktimeBytes ++ ByteVector .fromByte(spendType) ++ outPointHash ++ amounts ++ spentSPKs ++ sequenceHash ++ annexBytes ++ outputHash ++ tapScriptBytes @@ -384,14 +410,15 @@ sealed abstract class TransactionSignatureSerializer { } } - /** Hashes a [[org.bitcoins.core.crypto.TxSigComponent TxSigComponent]] to give the value that needs to be signed - * by a [[Sign Sign]] to - * produce a valid [[ECDigitalSignature ECDigitalSignature]] for a transaction + /** Hashes a [[org.bitcoins.core.crypto.TxSigComponent TxSigComponent]] to + * give the value that needs to be signed by a [[Sign Sign]] to produce a + * valid [[ECDigitalSignature ECDigitalSignature]] for a transaction */ def hashForSignature( txSigComponent: TxSigComponent, hashType: HashType, - taprootOptions: TaprootSerializationOptions): HashDigest = { + taprootOptions: TaprootSerializationOptions + ): HashDigest = { val spendingTransaction = txSigComponent.transaction val inputIndex = txSigComponent.inputIndex if ( @@ -408,9 +435,11 @@ sealed abstract class TransactionSignatureSerializer { errorHash } else { val serializedTxForSignature = - serializeForSignature(txSigComponent = txSigComponent, - hashType = hashType, - taprootOptions = taprootOptions) + serializeForSignature( + txSigComponent = txSigComponent, + hashType = hashType, + taprootOptions = taprootOptions + ) val hash = txSigComponent.sigVersion match { case _: SigVersionTaproot => @@ -422,8 +451,9 @@ sealed abstract class TransactionSignatureSerializer { } } - /** Implements the signature serialization algorithm that Satoshi Nakamoto originally created - * and the new signature serialization algorithm as specified by + /** Implements the signature serialization algorithm that Satoshi Nakamoto + * originally created and the new signature serialization algorithm as + * specified by * [[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki BIP143]]. * [[https://github.com/bitcoin/bitcoin/blob/f8528134fc188abc5c7175a19680206964a8fade/src/script/interpreter.cpp#L1113]] */ @@ -431,38 +461,47 @@ sealed abstract class TransactionSignatureSerializer { spendingTransaction: Transaction, signingInfo: InputSigningInfo[InputInfo], hashType: HashType, - taprootOptions: TaprootSerializationOptions): ByteVector = { + taprootOptions: TaprootSerializationOptions + ): ByteVector = { val idx = TxUtil.inputIndex(signingInfo.inputInfo, spendingTransaction) require( signingInfo.prevTransaction != EmptyTransaction, - "prevTransaction can only be an EmptyTransaction when dummy signing") + "prevTransaction can only be an EmptyTransaction when dummy signing" + ) val inputIndex = UInt32(idx) val output = signingInfo.output val script = BitcoinScriptUtil.calculateScriptForSigning( spendingTransaction, signingInfo, - output.scriptPubKey.asm) + output.scriptPubKey.asm + ) - serializeForSignature(spendingTransaction, - inputIndex, - hashType, - Vector(output), - script, - signingInfo.sigVersion, - taprootOptions = taprootOptions) + serializeForSignature( + spendingTransaction, + inputIndex, + hashType, + Vector(output), + script, + signingInfo.sigVersion, + taprootOptions = taprootOptions + ) } - /** Hashes a [[org.bitcoins.core.wallet.utxo.InputSigningInfo InputSigningInfo]] to give the value that needs to be signed - * by a [[org.bitcoins.crypto.Sign Sign]] to - * produce a valid [[org.bitcoins.crypto.ECDigitalSignature ECDigitalSignature]] for a transaction + /** Hashes a + * [[org.bitcoins.core.wallet.utxo.InputSigningInfo InputSigningInfo]] to + * give the value that needs to be signed by a + * [[org.bitcoins.crypto.Sign Sign]] to produce a valid + * [[org.bitcoins.crypto.ECDigitalSignature ECDigitalSignature]] for a + * transaction */ def hashForSignature( spendingTransaction: Transaction, signingInfo: InputSigningInfo[InputInfo], hashType: HashType, - taprootOptions: TaprootSerializationOptions): DoubleSha256Digest = { + taprootOptions: TaprootSerializationOptions + ): DoubleSha256Digest = { val inputIndexOpt = TxUtil.inputIndexOpt(signingInfo.inputInfo, spendingTransaction) @@ -477,45 +516,55 @@ sealed abstract class TransactionSignatureSerializer { errorHash } else { val serializedTxForSignature = - serializeForSignature(spendingTransaction, - signingInfo, - hashType, - taprootOptions) + serializeForSignature( + spendingTransaction, + signingInfo, + hashType, + taprootOptions + ) CryptoUtil.doubleSHA256(serializedTxForSignature) } } - /** Sets the input's sequence number to zero EXCEPT for the input at inputIndex. */ + /** Sets the input's sequence number to zero EXCEPT for the input at + * inputIndex. + */ private def setSequenceNumbersZero( inputs: Seq[TransactionInput], - inputIndex: UInt32): Seq[TransactionInput] = + inputIndex: UInt32 + ): Seq[TransactionInput] = for { (input, index) <- inputs.zipWithIndex } yield { if (UInt32(index) == inputIndex) input else - TransactionInput(input.previousOutput, - input.scriptSignature, - UInt32.zero) + TransactionInput( + input.previousOutput, + input.scriptSignature, + UInt32.zero + ) } - /** Executes the [[SIGHASH_NONE SIGHASH_NONE]] - * procedure on a spending transaction for the input specified by inputIndex. + /** Executes the [[SIGHASH_NONE SIGHASH_NONE]] procedure on a spending + * transaction for the input specified by inputIndex. */ private def sigHashNone( spendingTransaction: Transaction, - inputIndex: UInt32): Transaction = { - //following this implementation from bitcoinj - //[[https://github.com/bitcoinj/bitcoinj/blob/09a2ca64d2134b0dcbb27b1a6eb17dda6087f448/core/src/main/java/org/bitcoinj/core/Transaction.java#L957]] - //means that no outputs are signed at all - //set the sequence number of all inputs to 0 EXCEPT the input at inputIndex + inputIndex: UInt32 + ): Transaction = { + // following this implementation from bitcoinj + // [[https://github.com/bitcoinj/bitcoinj/blob/09a2ca64d2134b0dcbb27b1a6eb17dda6087f448/core/src/main/java/org/bitcoinj/core/Transaction.java#L957]] + // means that no outputs are signed at all + // set the sequence number of all inputs to 0 EXCEPT the input at inputIndex val updatedInputs: Seq[TransactionInput] = setSequenceNumbersZero(spendingTransaction.inputs, inputIndex) - val sigHashNoneTx = BaseTransaction(spendingTransaction.version, - updatedInputs, - Nil, - spendingTransaction.lockTime) - //append hash type byte onto the end of the tx bytes + val sigHashNoneTx = BaseTransaction( + spendingTransaction.version, + updatedInputs, + Nil, + spendingTransaction.lockTime + ) + // append hash type byte onto the end of the tx bytes sigHashNoneTx } @@ -524,9 +573,10 @@ sealed abstract class TransactionSignatureSerializer { */ private def sigHashSingle( spendingTransaction: Transaction, - inputIndex: UInt32): Transaction = { - //following this implementation from bitcoinj - //[[https://github.com/bitcoinj/bitcoinj/blob/09a2ca64d2134b0dcbb27b1a6eb17dda6087f448/core/src/main/java/org/bitcoinj/core/Transaction.java#L964]] + inputIndex: UInt32 + ): Transaction = { + // following this implementation from bitcoinj + // [[https://github.com/bitcoinj/bitcoinj/blob/09a2ca64d2134b0dcbb27b1a6eb17dda6087f448/core/src/main/java/org/bitcoinj/core/Transaction.java#L964]] // In SIGHASH_SINGLE the outputs after the matching input index are deleted, and the outputs before // that position are "nulled out". Unintuitively, the value in a "null" transaction is set to -1. val updatedOutputsOpt: Seq[Option[TransactionOutput]] = for { @@ -539,14 +589,16 @@ sealed abstract class TransactionSignatureSerializer { } val updatedOutputs: Seq[TransactionOutput] = updatedOutputsOpt.flatten - //create blank inputs with sequence numbers set to zero EXCEPT - //the input at the inputIndex + // create blank inputs with sequence numbers set to zero EXCEPT + // the input at the inputIndex val updatedInputs: Seq[TransactionInput] = setSequenceNumbersZero(spendingTransaction.inputs, inputIndex) - val sigHashSingleTx = BaseTransaction(spendingTransaction.version, - updatedInputs, - updatedOutputs, - spendingTransaction.lockTime) + val sigHashSingleTx = BaseTransaction( + spendingTransaction.version, + updatedInputs, + updatedOutputs, + spendingTransaction.lockTime + ) sigHashSingleTx } @@ -557,19 +609,23 @@ sealed abstract class TransactionSignatureSerializer { spendingTransaction } - /** Executes the [[SIGHASH_ANYONECANPAY SIGHASH_ANYONECANPAY]] procedure - * on a spending transaction at inputIndex. + /** Executes the [[SIGHASH_ANYONECANPAY SIGHASH_ANYONECANPAY]] procedure on a + * spending transaction at inputIndex. */ private def sigHashAnyoneCanPay( spendingTransaction: Transaction, - input: TransactionInput): Transaction = { - BaseTransaction(spendingTransaction.version, - Seq(input), - spendingTransaction.outputs, - spendingTransaction.lockTime) + input: TransactionInput + ): Transaction = { + BaseTransaction( + spendingTransaction.version, + Seq(input), + spendingTransaction.outputs, + spendingTransaction.lockTime + ) } - /** Removes [[org.bitcoins.core.script.crypto.OP_CODESEPARATOR OP_CODESEPARATOR]] + /** Removes + * [[org.bitcoins.core.script.crypto.OP_CODESEPARATOR OP_CODESEPARATOR]] * operations then returns the script. */ def removeOpCodeSeparators(script: Seq[ScriptToken]): Seq[ScriptToken] = { diff --git a/core/src/main/scala/org/bitcoins/core/crypto/TxSigComponent.scala b/core/src/main/scala/org/bitcoins/core/crypto/TxSigComponent.scala index 45e8d52bff..515ca07c74 100644 --- a/core/src/main/scala/org/bitcoins/core/crypto/TxSigComponent.scala +++ b/core/src/main/scala/org/bitcoins/core/crypto/TxSigComponent.scala @@ -11,8 +11,8 @@ import org.bitcoins.core.wallet.utxo._ import scala.util.{Failure, Success, Try} -/** Created by chris on 4/6/16. - * Represents a transaction whose input is being checked against the spending conditions of a +/** Created by chris on 4/6/16. Represents a transaction whose input is being + * checked against the spending conditions of a * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] */ sealed abstract class TxSigComponent { @@ -28,19 +28,25 @@ sealed abstract class TxSigComponent { /** The script signature being checked */ def scriptSignature: ScriptSignature = input.scriptSignature - /** This is the output we are spending. We need this for script and digital signatures checks */ + /** This is the output we are spending. We need this for script and digital + * signatures checks + */ def output: TransactionOutput /** The scriptPubKey for which the input is being checked against */ def scriptPubKey: ScriptPubKey = output.scriptPubKey - /** The amount of [[org.bitcoins.core.currency.CurrencyUnit CurrencyUnit]] we are spending in this TxSigComponent */ + /** The amount of [[org.bitcoins.core.currency.CurrencyUnit CurrencyUnit]] we + * are spending in this TxSigComponent + */ def amount: CurrencyUnit = output.value /** The flags that are needed to verify if the signature is correct */ def flags: Seq[ScriptFlag] - /** Represents the serialization algorithm used to verify/create signatures for Bitcoin */ + /** Represents the serialization algorithm used to verify/create signatures + * for Bitcoin + */ def sigVersion: SignatureVersion } @@ -50,7 +56,8 @@ object TxSigComponent { inputInfo: InputInfo, unsignedTx: Transaction, outputMap: PreviousOutputMap, - flags: Seq[ScriptFlag] = Policy.standardFlags): TxSigComponent = { + flags: Seq[ScriptFlag] = Policy.standardFlags + ): TxSigComponent = { inputInfo match { case segwit: SegwitV0NativeInputInfo => fromWitnessInput(segwit, unsignedTx, flags) @@ -65,7 +72,8 @@ object TxSigComponent { private def setTransactionWitness( inputInfo: InputInfo, - unsignedTx: Transaction): WitnessTransaction = { + unsignedTx: Transaction + ): WitnessTransaction = { val idx = TxUtil.inputIndex(inputInfo, unsignedTx) val unsignedWtx = WitnessTransaction.toWitnessTx(unsignedTx) @@ -86,21 +94,25 @@ object TxSigComponent { def fromWitnessInput( inputInfo: SegwitV0NativeInputInfo, unsignedTx: Transaction, - flags: Seq[ScriptFlag]): TxSigComponent = { + flags: Seq[ScriptFlag] + ): TxSigComponent = { val idx = TxUtil.inputIndex(inputInfo, unsignedTx) val wtx = setTransactionWitness(inputInfo, unsignedTx) - WitnessTxSigComponentRaw(transaction = wtx, - inputIndex = UInt32(idx), - output = inputInfo.output, - flags = flags) + WitnessTxSigComponentRaw( + transaction = wtx, + inputIndex = UInt32(idx), + output = inputInfo.output, + flags = flags + ) } def fromWitnessInput( inputInfo: UnassignedSegwitNativeInputInfo, unsignedTx: Transaction, outputMap: PreviousOutputMap, - flags: Seq[ScriptFlag]): TxSigComponent = { + flags: Seq[ScriptFlag] + ): TxSigComponent = { val idx = TxUtil.inputIndex(inputInfo, unsignedTx) val wtx = setTransactionWitness(inputInfo, unsignedTx) @@ -110,13 +122,15 @@ object TxSigComponent { def fromWitnessInput( inputInfo: P2SHNestedSegwitV0InputInfo, unsignedTx: Transaction, - flags: Seq[ScriptFlag] = Policy.standardFlags): TxSigComponent = { + flags: Seq[ScriptFlag] = Policy.standardFlags + ): TxSigComponent = { val idx = TxUtil.inputIndex(inputInfo, unsignedTx) val emptyInput = unsignedTx.inputs(idx) val newInput = TransactionInput( emptyInput.previousOutput, P2SHScriptSignature(EmptyScriptSignature, inputInfo.redeemScript), - emptyInput.sequence) + emptyInput.sequence + ) val updatedTx = unsignedTx.updateInput(idx, newInput) val wtx = WitnessTransaction.toWitnessTx(updatedTx) @@ -129,7 +143,8 @@ object TxSigComponent { def fromP2SHInput( inputInfo: P2SHInputInfo, unsignedTx: Transaction, - flags: Seq[ScriptFlag]): TxSigComponent = { + flags: Seq[ScriptFlag] + ): TxSigComponent = { inputInfo match { case nonSegwit: P2SHNonSegwitInputInfo => fromP2SHInput(nonSegwit, unsignedTx, flags) @@ -141,7 +156,8 @@ object TxSigComponent { def fromP2SHInput( inputInfo: P2SHNonSegwitInputInfo, unsignedTx: Transaction, - flags: Seq[ScriptFlag]): TxSigComponent = { + flags: Seq[ScriptFlag] + ): TxSigComponent = { val idx = TxUtil.inputIndex(inputInfo, unsignedTx) val updatedTx = unsignedTx.inputs(idx).scriptSignature match { @@ -150,7 +166,8 @@ object TxSigComponent { val newInput = TransactionInput( emptyInput.previousOutput, P2SHScriptSignature(EmptyScriptSignature, inputInfo.redeemScript), - emptyInput.sequence) + emptyInput.sequence + ) unsignedTx.updateInput(idx, newInput) case _: P2SHScriptSignature => unsignedTx @@ -159,7 +176,8 @@ object TxSigComponent { _: NonStandardScriptSignature | _: P2PKHScriptSignature | _: P2PKScriptSignature | TrivialTrueScriptSignature) => throw new IllegalArgumentException( - s"Unexpected script sig with P2SHNonSegwitInputInfo, got $invalid") + s"Unexpected script sig with P2SHNonSegwitInputInfo, got $invalid" + ) } P2SHTxSigComponent(updatedTx, UInt32(idx), inputInfo.output, flags) @@ -168,7 +186,8 @@ object TxSigComponent { def fromRawInput( inputInfo: RawInputInfo, unsignedTx: Transaction, - flags: Seq[ScriptFlag] = Policy.standardFlags): TxSigComponent = { + flags: Seq[ScriptFlag] = Policy.standardFlags + ): TxSigComponent = { val idx = TxUtil.inputIndex(inputInfo, unsignedTx) BaseTxSigComponent(unsignedTx, UInt32(idx), inputInfo.output, flags) } @@ -178,14 +197,15 @@ object TxSigComponent { inputIndex: UInt32, output: TransactionOutput, outputMap: PreviousOutputMap, - flags: Seq[ScriptFlag]): TxSigComponent = { + flags: Seq[ScriptFlag] + ): TxSigComponent = { val scriptSig = transaction.inputs(inputIndex.toInt).scriptSignature output.scriptPubKey match { case _: WitnessScriptPubKey => transaction match { case _: NonWitnessTransaction => - //before soft fork activation, you can spend a segwit output with a base transaction - //as segwit outputs are ANYONECANSPEND before soft fork activation + // before soft fork activation, you can spend a segwit output with a base transaction + // as segwit outputs are ANYONECANSPEND before soft fork activation BaseTxSigComponent(transaction, inputIndex, output, flags) case wtx: WitnessTransaction => WitnessTxSigComponent(wtx, inputIndex, output, outputMap, flags) @@ -196,7 +216,8 @@ object TxSigComponent { transaction match { case _: NonWitnessTransaction => throw new IllegalArgumentException( - s"Cannot spend from segwit output ($output) with a base transaction ($transaction)") + s"Cannot spend from segwit output ($output) with a base transaction ($transaction)" + ) case wtx: WitnessTransaction => WitnessTxSigComponentP2SH(wtx, inputIndex, output, flags) } @@ -209,7 +230,8 @@ object TxSigComponent { } def getScriptWitness( - txSigComponent: TxSigComponent): Option[ScriptWitness] = { + txSigComponent: TxSigComponent + ): Option[ScriptWitness] = { txSigComponent.transaction match { case _: NonWitnessTransaction => None case wtx: WitnessTransaction => @@ -223,11 +245,12 @@ object TxSigComponent { } } -/** The [[org.bitcoins.core.crypto.TxSigComponent TxSigComponent]] - * used to evaluate the the original Satoshi transaction digest algorithm. - * Basically this is every spk that is not a - * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] EXCEPT in the case of a - * P2SH(witness script) [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] +/** The [[org.bitcoins.core.crypto.TxSigComponent TxSigComponent]] used to + * evaluate the the original Satoshi transaction digest algorithm. Basically + * this is every spk that is not a + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] + * EXCEPT in the case of a P2SH(witness script) + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] */ sealed abstract class BaseTxSigComponent extends TxSigComponent { override def sigVersion: SignatureVersion = SigVersionBase @@ -253,12 +276,13 @@ sealed abstract class P2SHTxSigComponent extends BaseTxSigComponent { input.scriptSignature.asInstanceOf[P2SHScriptSignature] } -/** The [[org.bitcoins.core.crypto.TxSigComponent TxSigComponent]] - * used to represent all the components necessarily for +/** The [[org.bitcoins.core.crypto.TxSigComponent TxSigComponent]] used to + * represent all the components necessarily for * [[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki BIP143]]. - * Examples of these [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]]'s - * are [[org.bitcoins.core.protocol.script.P2WPKHWitnessV0 P2WPKHWitnessSPKV0]], - * [[org.bitcoins.core.protocol.script.P2WSHWitnessSPKV0 P2WSHWitnessSPKV0]], + * Examples of these + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]]'s are + * [[org.bitcoins.core.protocol.script.P2WPKHWitnessV0 P2WPKHWitnessSPKV0]], + * [[org.bitcoins.core.protocol.script.P2WSHWitnessSPKV0 P2WSHWitnessSPKV0]], * and P2SH(witness script) */ sealed trait WitnessTxSigComponent extends TxSigComponent { @@ -270,8 +294,11 @@ sealed trait WitnessTxSigComponent extends TxSigComponent { def witnessVersion: WitnessVersion } -/** This represents checking the [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] - * against a [[org.bitcoins.core.protocol.script.P2WPKHWitnessSPKV0 P2WPKHWitnessSPKV0]] or a +/** This represents checking the + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] + * against a + * [[org.bitcoins.core.protocol.script.P2WPKHWitnessSPKV0 P2WPKHWitnessSPKV0]] + * or a * [[org.bitcoins.core.protocol.script.P2WSHWitnessSPKV0 P2WSHWitnessSPKV0]] */ sealed abstract class WitnessTxSigComponentRaw extends WitnessTxSigComponent { @@ -287,14 +314,16 @@ sealed abstract class WitnessTxSigComponentRaw extends WitnessTxSigComponent { scriptPubKey match { case t: TaprootScriptPubKey => sys.error( - s"Use TaprootTxSigComponent for taproot spks rather than WitnessTxSigComponentRaw, got=$t") + s"Use TaprootTxSigComponent for taproot spks rather than WitnessTxSigComponentRaw, got=$t" + ) case _: WitnessScriptPubKeyV0 | _: UnassignedWitnessScriptPubKey => SigVersionWitnessV0 } } } -/** This represents checking the [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] +/** This represents checking the + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] * against a P2SH(P2WSH) or P2SH(P2WPKH) scriptPubKey */ sealed abstract class WitnessTxSigComponentP2SH @@ -306,8 +335,10 @@ sealed abstract class WitnessTxSigComponentP2SH override def scriptSignature: P2SHScriptSignature = { val s = transaction.inputs(inputIndex.toInt).scriptSignature - require(s.isInstanceOf[P2SHScriptSignature], - "Must have P2SHScriptSignature for P2SH(WitSPK()), got: " + s) + require( + s.isInstanceOf[P2SHScriptSignature], + "Must have P2SHScriptSignature for P2SH(WitSPK()), got: " + s + ) val p2sh = s.asInstanceOf[P2SHScriptSignature] p2sh @@ -321,8 +352,11 @@ sealed abstract class WitnessTxSigComponentP2SH _: P2SHScriptPubKey | _: CSVScriptPubKey | _: CLTVScriptPubKey | _: ConditionalScriptPubKey | _: NonStandardScriptPubKey | _: WitnessCommitment | EmptyScriptPubKey) => - Failure(new IllegalArgumentException( - "Must have a witness scriptPubKey as redeemScript for P2SHScriptPubKey in WitnessTxSigComponentP2SH, got: " + x)) + Failure( + new IllegalArgumentException( + "Must have a witness scriptPubKey as redeemScript for P2SHScriptPubKey in WitnessTxSigComponentP2SH, got: " + x + ) + ) } @@ -337,12 +371,13 @@ sealed abstract class WitnessTxSigComponentP2SH override def sigVersion: SignatureVersion = SigVersionWitnessV0 } -/** This represents a 'rebuilt' [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] - * that was constructed from [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] - * After the - * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] is rebuilt, we need to use that rebuilt - * scriptpubkey to evaluate the [[org.bitcoins.core.protocol.script.ScriptSignature ScriptSignature]] - * See +/** This represents a 'rebuilt' + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] that was + * constructed from + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] + * After the [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] is + * rebuilt, we need to use that rebuilt scriptpubkey to evaluate the + * [[org.bitcoins.core.protocol.script.ScriptSignature ScriptSignature]] See * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program BIP141]] * for more info on rebuilding P2WSH and P2WPKH scriptpubkeys */ @@ -351,21 +386,23 @@ sealed abstract class WitnessTxSigComponentRebuilt extends TxSigComponent { override def scriptPubKey: ScriptPubKey = output.scriptPubKey - /** The [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] we used to - * rebuild the scriptPubKey above + /** The + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] + * we used to rebuild the scriptPubKey above */ def witnessScriptPubKey: WitnessScriptPubKey override def sigVersion: SignatureVersion = witnessScriptPubKey match { case _: WitnessScriptPubKeyV0 => SigVersionWitnessV0 case _: TaprootScriptPubKey => - //i believe we cannot have keypath spend here because we don't - //need to rebuild a spk with keypath spent - //https://github.com/bitcoin/bitcoin/blob/9e4fbebcc8e497016563e46de4c64fa094edab2d/src/script/interpreter.cpp#L399 + // i believe we cannot have keypath spend here because we don't + // need to rebuild a spk with keypath spent + // https://github.com/bitcoin/bitcoin/blob/9e4fbebcc8e497016563e46de4c64fa094edab2d/src/script/interpreter.cpp#L399 SigVersionTapscript case w: UnassignedWitnessScriptPubKey => sys.error( - s"Cannot determine sigVersion for an unassigned witness, got=$w") + s"Cannot determine sigVersion for an unassigned witness, got=$w" + ) } def witnessVersion: WitnessVersion = witnessScriptPubKey.witnessVersion @@ -375,25 +412,28 @@ sealed abstract class WitnessTxSigComponentRebuilt extends TxSigComponent { /** Tx sig component that contains the differences between BIP143 (segwit v0) * transaction signature serialization and BIP341. * - * The unique thing with BIP341 is the message commits to the scriptPubKeys - * of all outputs spent by the transaction, also + * The unique thing with BIP341 is the message commits to the scriptPubKeys of + * all outputs spent by the transaction, also * - * If the SIGHASH_ANYONECANPAY flag is not set, the message commits to the amounts of all transaction inputs.[18] + * If the SIGHASH_ANYONECANPAY flag is not set, the message commits to the + * amounts of all transaction inputs.[18] * - * This means we need to bring ALL the outputs we are spending, even though this data structure - * is for checking the signature of a _single_ output. + * This means we need to bring ALL the outputs we are spending, even though + * this data structure is for checking the signature of a _single_ output. * - * @see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#common-signature-message */ case class TaprootTxSigComponent( transaction: WitnessTransaction, inputIndex: UInt32, outputMap: PreviousOutputMap, - flags: Seq[ScriptFlag]) - extends WitnessTxSigComponent { + flags: Seq[ScriptFlag] +) extends WitnessTxSigComponent { require( scriptPubKey.isInstanceOf[TaprootScriptPubKey], - s"Can only spend taproot spks with TaprootTxSigComponent, got=$scriptPubKey") + s"Can only spend taproot spks with TaprootTxSigComponent, got=$scriptPubKey" + ) override lazy val output: TransactionOutput = { val outpoint = transaction.inputs(inputIndex.toInt).previousOutput @@ -414,7 +454,7 @@ case class TaprootTxSigComponent( override def sigVersion: SigVersionTaproot = { witness match { - case _: TaprootKeyPath => SigVersionTaprootKeySpend + case _: TaprootKeyPath => SigVersionTaprootKeySpend case _: TaprootScriptPath | _: TaprootUnknownPath => SigVersionTapscript } } @@ -426,14 +466,15 @@ object BaseTxSigComponent { transaction: Transaction, inputIndex: UInt32, output: TransactionOutput, - flags: Seq[ScriptFlag]) - extends BaseTxSigComponent + flags: Seq[ScriptFlag] + ) extends BaseTxSigComponent def apply( transaction: Transaction, inputIndex: UInt32, output: TransactionOutput, - flags: Seq[ScriptFlag]): BaseTxSigComponent = { + flags: Seq[ScriptFlag] + ): BaseTxSigComponent = { BaseTxSigComponentImpl(transaction, inputIndex, output, flags) } @@ -445,14 +486,15 @@ object P2SHTxSigComponent { transaction: Transaction, inputIndex: UInt32, output: TransactionOutput, - flags: Seq[ScriptFlag]) - extends P2SHTxSigComponent + flags: Seq[ScriptFlag] + ) extends P2SHTxSigComponent def apply( transaction: Transaction, inputIndex: UInt32, output: TransactionOutput, - flags: Seq[ScriptFlag]): P2SHTxSigComponent = { + flags: Seq[ScriptFlag] + ): P2SHTxSigComponent = { lazy val nonWitnessSigComponent = P2SHTxSigComponentImpl(transaction, inputIndex, output, flags) transaction match { @@ -474,7 +516,8 @@ object WitnessTxSigComponent { inputIndex: UInt32, output: TransactionOutput, outputMap: PreviousOutputMap, - flags: Seq[ScriptFlag]): WitnessTxSigComponent = + flags: Seq[ScriptFlag] + ): WitnessTxSigComponent = output.scriptPubKey match { case _: WitnessScriptPubKeyV0 | _: UnassignedWitnessScriptPubKey => WitnessTxSigComponentRaw(transaction, inputIndex, output, flags) @@ -488,7 +531,8 @@ object WitnessTxSigComponent { _: WitnessCommitment | _: NonStandardScriptPubKey | EmptyScriptPubKey) => throw new IllegalArgumentException( - s"Cannot create a WitnessTxSigComponent out of $x") + s"Cannot create a WitnessTxSigComponent out of $x" + ) } } @@ -499,14 +543,15 @@ object WitnessTxSigComponentRaw { transaction: WitnessTransaction, inputIndex: UInt32, output: TransactionOutput, - flags: Seq[ScriptFlag]) - extends WitnessTxSigComponentRaw + flags: Seq[ScriptFlag] + ) extends WitnessTxSigComponentRaw def apply( transaction: WitnessTransaction, inputIndex: UInt32, output: TransactionOutput, - flags: Seq[ScriptFlag]): WitnessTxSigComponentRaw = { + flags: Seq[ScriptFlag] + ): WitnessTxSigComponentRaw = { output.scriptPubKey match { case _: WitnessScriptPubKey => WitnessTxSigComponentRawImpl(transaction, inputIndex, output, flags) @@ -516,7 +561,8 @@ object WitnessTxSigComponentRaw { _: ConditionalScriptPubKey | _: NonStandardScriptPubKey | _: WitnessCommitment | EmptyScriptPubKey) => throw new IllegalArgumentException( - s"Cannot create a WitnessTxSigComponentRaw with a spk of $x") + s"Cannot create a WitnessTxSigComponentRaw with a spk of $x" + ) } } @@ -528,14 +574,15 @@ object WitnessTxSigComponentP2SH { transaction: WitnessTransaction, inputIndex: UInt32, output: TransactionOutput, - flags: Seq[ScriptFlag]) - extends WitnessTxSigComponentP2SH + flags: Seq[ScriptFlag] + ) extends WitnessTxSigComponentP2SH def apply( transaction: WitnessTransaction, inputIndex: UInt32, output: TransactionOutput, - flags: Seq[ScriptFlag]): WitnessTxSigComponentP2SH = { + flags: Seq[ScriptFlag] + ): WitnessTxSigComponentP2SH = { output.scriptPubKey match { case _: P2SHScriptPubKey => WitnessTxSigComponentP2SHImpl(transaction, inputIndex, output, flags) @@ -545,7 +592,8 @@ object WitnessTxSigComponentP2SH { _: NonStandardScriptPubKey | _: WitnessCommitment | _: WitnessScriptPubKey | EmptyScriptPubKey) => throw new IllegalArgumentException( - s"Cannot create a WitnessTxSigComponentP2SH with a spk of $x") + s"Cannot create a WitnessTxSigComponentP2SH with a spk of $x" + ) } } @@ -558,19 +606,22 @@ object WitnessTxSigComponentRebuilt { inputIndex: UInt32, output: TransactionOutput, witnessScriptPubKey: WitnessScriptPubKey, - flags: Seq[ScriptFlag]) - extends WitnessTxSigComponentRebuilt + flags: Seq[ScriptFlag] + ) extends WitnessTxSigComponentRebuilt def apply( wtx: WitnessTransaction, inputIndex: UInt32, output: TransactionOutput, witScriptPubKey: WitnessScriptPubKey, - flags: Seq[ScriptFlag]): WitnessTxSigComponentRebuilt = { - WitnessTxSigComponentRebuiltImpl(wtx, - inputIndex, - output, - witScriptPubKey, - flags) + flags: Seq[ScriptFlag] + ): WitnessTxSigComponentRebuilt = { + WitnessTxSigComponentRebuiltImpl( + wtx, + inputIndex, + output, + witScriptPubKey, + flags + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala b/core/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala index 8fb0f86e07..4599246b31 100644 --- a/core/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala +++ b/core/src/main/scala/org/bitcoins/core/currency/CurrencyUnits.scala @@ -79,12 +79,12 @@ sealed abstract class CurrencyUnit protected def underlying: A override def equals(obj: Any): Boolean = { - //needed for cases like - //1BTC == 100,000,000 satoshis should be true - //weirdly enough, this worked in scala version < 2.13.4 - //but seems to be broken in 2.13.4 :/ - //try removing this and running code, you should see - //failures in the 'walletTest' module + // needed for cases like + // 1BTC == 100,000,000 satoshis should be true + // weirdly enough, this worked in scala version < 2.13.4 + // but seems to be broken in 2.13.4 :/ + // try removing this and running code, you should see + // failures in the 'walletTest' module obj match { case cu: CurrencyUnit => cu.satoshis == satoshis case ln: LnCurrencyUnit => satoshis == ln.toSatoshis @@ -218,7 +218,8 @@ object Bitcoins extends BaseNumbers[Bitcoins] with Bounded[Bitcoins] { def apply( underlying: BigDecimal, - roundingMode: RoundingMode = RoundingMode.DOWN): Bitcoins = { + roundingMode: RoundingMode = RoundingMode.DOWN + ): Bitcoins = { // Bitcoin can't represent amounts lower than a satoshi // so we need to round to the nearest satoshi val rounded = underlying.setScale(8, roundingMode) diff --git a/core/src/main/scala/org/bitcoins/core/dlc/accounting/DLCAccounting.scala b/core/src/main/scala/org/bitcoins/core/dlc/accounting/DLCAccounting.scala index 19887993ba..ff3c19970c 100644 --- a/core/src/main/scala/org/bitcoins/core/dlc/accounting/DLCAccounting.scala +++ b/core/src/main/scala/org/bitcoins/core/dlc/accounting/DLCAccounting.scala @@ -8,5 +8,5 @@ case class DLCAccounting( myCollateral: CurrencyUnit, theirCollateral: CurrencyUnit, myPayout: CurrencyUnit, - theirPayout: CurrencyUnit) - extends PayoutAccounting + theirPayout: CurrencyUnit +) extends PayoutAccounting diff --git a/core/src/main/scala/org/bitcoins/core/dlc/accounting/DLCWalletAccounting.scala b/core/src/main/scala/org/bitcoins/core/dlc/accounting/DLCWalletAccounting.scala index 109349b8c2..0e90778fce 100644 --- a/core/src/main/scala/org/bitcoins/core/dlc/accounting/DLCWalletAccounting.scala +++ b/core/src/main/scala/org/bitcoins/core/dlc/accounting/DLCWalletAccounting.scala @@ -9,13 +9,14 @@ case class DLCWalletAccounting( myCollateral: CurrencyUnit, theirCollateral: CurrencyUnit, myPayout: CurrencyUnit, - theirPayout: CurrencyUnit) - extends PayoutAccounting + theirPayout: CurrencyUnit +) extends PayoutAccounting object DLCWalletAccounting { def fromDLCAccounting( - accountings: Vector[DLCAccounting]): DLCWalletAccounting = { + accountings: Vector[DLCAccounting] + ): DLCWalletAccounting = { val myCollateral = accountings.foldLeft(CurrencyUnits.zero)(_ + _.myCollateral) val theirCollateral = diff --git a/core/src/main/scala/org/bitcoins/core/dlc/accounting/PayoutAccounting.scala b/core/src/main/scala/org/bitcoins/core/dlc/accounting/PayoutAccounting.scala index 6f4bd1a1ea..205c1b4bf0 100644 --- a/core/src/main/scala/org/bitcoins/core/dlc/accounting/PayoutAccounting.scala +++ b/core/src/main/scala/org/bitcoins/core/dlc/accounting/PayoutAccounting.scala @@ -13,12 +13,14 @@ trait PayoutAccounting { def theirPayout: CurrencyUnit /** Profit and loss for the DLC - * @see https://www.investopedia.com/terms/p/plstatement.asp + * @see + * https://www.investopedia.com/terms/p/plstatement.asp */ def pnl: CurrencyUnit = myPayout - myCollateral /** Rate of return for the DLC - * @see https://www.investopedia.com/terms/r/rateofreturn.asp + * @see + * https://www.investopedia.com/terms/r/rateofreturn.asp */ def rateOfReturn: BigDecimal = if (myCollateral != Satoshis.zero) pnl.toBigDecimal / myCollateral.toBigDecimal diff --git a/core/src/main/scala/org/bitcoins/core/dlc/accounting/RateOfReturnUtil.scala b/core/src/main/scala/org/bitcoins/core/dlc/accounting/RateOfReturnUtil.scala index 774a4b5a7d..eb2514cce5 100644 --- a/core/src/main/scala/org/bitcoins/core/dlc/accounting/RateOfReturnUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/dlc/accounting/RateOfReturnUtil.scala @@ -2,12 +2,15 @@ package org.bitcoins.core.dlc.accounting object RateOfReturnUtil { - /** @see https://alvinalexander.com/scala/how-to-format-numbers-commas-international-currency-in-scala/ */ + /** @see + * https://alvinalexander.com/scala/how-to-format-numbers-commas-international-currency-in-scala/ + */ def prettyPrint(ror: BigDecimal): String = { toPercentage(ror, 2) + "%" } - /** Convert to default two decimal percentage representation without % label */ + /** Convert to default two decimal percentage representation without % label + */ def toPercentage(ror: BigDecimal, decimals: Int = 2): String = { s"%1.${decimals}f".format(ror * 100) } diff --git a/core/src/main/scala/org/bitcoins/core/gcs/BlockFilter.scala b/core/src/main/scala/org/bitcoins/core/gcs/BlockFilter.scala index c2aff6edc5..e798d835cd 100644 --- a/core/src/main/scala/org/bitcoins/core/gcs/BlockFilter.scala +++ b/core/src/main/scala/org/bitcoins/core/gcs/BlockFilter.scala @@ -11,9 +11,10 @@ import scodec.bits.ByteVector object BlockFilter { - /** Returns all ScriptPubKeys from a Block's outputs that are relevant - * to BIP 158 Basic Block Filters - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#contents]] + /** Returns all ScriptPubKeys from a Block's outputs that are relevant to BIP + * 158 Basic Block Filters + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#contents]] */ def getOutputScriptPubKeysFromBlock(block: Block): Vector[ScriptPubKey] = { val transactions: Vector[Transaction] = block.transactions.toVector @@ -26,12 +27,15 @@ object BlockFilter { .map(_.scriptPubKey) } - /** Given a Block and access to the previous output scripts, constructs a Block Filter for that block - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#block-filters]] + /** Given a Block and access to the previous output scripts, constructs a + * Block Filter for that block + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#block-filters]] */ def apply( block: Block, - prevOutputScripts: Vector[ScriptPubKey]): GolombFilter = { + prevOutputScripts: Vector[ScriptPubKey] + ): GolombFilter = { val keyBytes: ByteVector = block.blockHeader.hash.bytes.take(16) val key: SipHashKey = SipHashKey(keyBytes) @@ -51,17 +55,20 @@ object BlockFilter { def fromBytes( bytes: ByteVector, - blockHash: DoubleSha256Digest): GolombFilter = { + blockHash: DoubleSha256Digest + ): GolombFilter = { val n = CompactSizeUInt.fromBytes(bytes) val filterBytes = bytes.drop(n.bytes.length) val keyBytes: ByteVector = blockHash.bytes.take(16) val key: SipHashKey = SipHashKey(keyBytes) - GolombFilter(key, - FilterType.Basic.M, - FilterType.Basic.P, - n, - filterBytes.toBitVector) + GolombFilter( + key, + FilterType.Basic.M, + FilterType.Basic.P, + n, + filterBytes.toBitVector + ) } def fromHex(hex: String, blockHash: DoubleSha256Digest): GolombFilter = { diff --git a/core/src/main/scala/org/bitcoins/core/gcs/BlockFilterMatcher.scala b/core/src/main/scala/org/bitcoins/core/gcs/BlockFilterMatcher.scala index 973fa41042..a8a9abd27f 100644 --- a/core/src/main/scala/org/bitcoins/core/gcs/BlockFilterMatcher.scala +++ b/core/src/main/scala/org/bitcoins/core/gcs/BlockFilterMatcher.scala @@ -24,7 +24,9 @@ case class SimpleFilterMatcher(filter: GolombFilter) matchesHash(hash) } - /** Hashes the given vector of data and calls [[matchesAnyHash()]] to find a match */ + /** Hashes the given vector of data and calls [[matchesAnyHash()]] to find a + * match + */ override def matchesAny(data: Vector[ByteVector]): Boolean = { val hashes = data.map(filter.hashToRange) matchesAnyHash(hashes) @@ -46,7 +48,9 @@ case class SimpleFilterMatcher(filter: GolombFilter) matches } - /** It implements https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-coded-set-multi-match */ + /** It implements + * https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-coded-set-multi-match + */ def matchesAnyHash(hashes: Vector[UInt64]): Boolean = { val sortedHashes = hashes.sorted var matches = false @@ -86,7 +90,9 @@ case class BinarySearchFilterMatcher(filter: GolombFilter) matchesHash(hash) } - /** Hashes the given vector of data and calls [[matchesAnyHash()]] to find a match */ + /** Hashes the given vector of data and calls [[matchesAnyHash()]] to find a + * match + */ override def matchesAny(data: Vector[ByteVector]): Boolean = { val hashes = data.map(filter.hashToRange) matchesAnyHash(hashes) @@ -98,7 +104,8 @@ case class BinarySearchFilterMatcher(filter: GolombFilter) from: Int, to: Int, hash: UInt64, - set: Vector[UInt64]): Boolean = { + set: Vector[UInt64] + ): Boolean = { if (to < from) { false } else { diff --git a/core/src/main/scala/org/bitcoins/core/gcs/FilterHeader.scala b/core/src/main/scala/org/bitcoins/core/gcs/FilterHeader.scala index 1090fe0538..681c8bb2b3 100644 --- a/core/src/main/scala/org/bitcoins/core/gcs/FilterHeader.scala +++ b/core/src/main/scala/org/bitcoins/core/gcs/FilterHeader.scala @@ -6,13 +6,15 @@ import org.bitcoins.crypto.{ DoubleSha256DigestBE } -/** Bip 157 Block Filter Headers which commit to a chain of block filters, - * much in the same way that block headers commit to a block chain - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#filter-headers]] +/** Bip 157 Block Filter Headers which commit to a chain of block filters, much + * in the same way that block headers commit to a block chain + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#filter-headers]] */ case class FilterHeader( filterHash: DoubleSha256Digest, - prevHeaderHash: DoubleSha256Digest) { + prevHeaderHash: DoubleSha256Digest +) { val hash: DoubleSha256Digest = { CryptoUtil.doubleSHA256(filterHash.bytes ++ prevHeaderHash.bytes) @@ -25,7 +27,8 @@ case class FilterHeader( FilterHeader(filterHash = nextFilter.hash, prevHeaderHash = this.hash) } - /** Given the next Block Filter hash, constructs the next Block Filter Header */ + /** Given the next Block Filter hash, constructs the next Block Filter Header + */ def nextHeader(nextFilterHash: DoubleSha256Digest): FilterHeader = { FilterHeader(filterHash = nextFilterHash, prevHeaderHash = this.hash) } @@ -39,7 +42,8 @@ object FilterHeader { def apply( filterHash: DoubleSha256DigestBE, - prevHeaderHash: DoubleSha256DigestBE): FilterHeader = { + prevHeaderHash: DoubleSha256DigestBE + ): FilterHeader = { new FilterHeader(filterHash.flip, prevHeaderHash.flip) } diff --git a/core/src/main/scala/org/bitcoins/core/gcs/FilterType.scala b/core/src/main/scala/org/bitcoins/core/gcs/FilterType.scala index 0d1a40d223..4d76c78357 100644 --- a/core/src/main/scala/org/bitcoins/core/gcs/FilterType.scala +++ b/core/src/main/scala/org/bitcoins/core/gcs/FilterType.scala @@ -6,7 +6,8 @@ import scodec.bits._ /** Filter types for BIP158 block content filters * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#block-filters BIP158]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#block-filters BIP158]] */ sealed abstract class FilterType extends NetworkElement { val M: UInt64 @@ -24,7 +25,8 @@ object FilterType extends Factory[FilterType] with StringFactory[FilterType] { case Basic.bytes => Basic case other: ByteVector => throw new IllegalArgumentException( - s"'${other.toHex}' is not a known filter type") + s"'${other.toHex}' is not a known filter type" + ) } /** Currently the only defined filter type */ @@ -40,7 +42,8 @@ object FilterType extends Factory[FilterType] with StringFactory[FilterType] { case Some(code) => code case None => throw new IllegalArgumentException( - s"Unknown filter type: ${filterType}") + s"Unknown filter type: ${filterType}" + ) } def byCode(code: Short): FilterType = diff --git a/core/src/main/scala/org/bitcoins/core/gcs/GCS.scala b/core/src/main/scala/org/bitcoins/core/gcs/GCS.scala index cec0cdab37..faeaddf002 100644 --- a/core/src/main/scala/org/bitcoins/core/gcs/GCS.scala +++ b/core/src/main/scala/org/bitcoins/core/gcs/GCS.scala @@ -9,18 +9,21 @@ import scala.annotation.tailrec // TODO: Replace ByteVector with a type for keys /** Defines all functionality dealing with Golomb-Coded Sets - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#GolombCoded_Sets]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#GolombCoded_Sets]] */ object GCS { /** Given parameters and data, golomb-encodes the data - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#set-construction]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#set-construction]] */ def buildGCS( data: Vector[ByteVector], key: SipHashKey, p: UInt8, - m: UInt64): BitVector = { + m: UInt64 + ): BitVector = { val hashedValues = hashedSetConstruct(data, key, m) val sortedHashedValues = hashedValues.sortWith(_ < _) encodeSortedSet(sortedHashedValues, p) @@ -32,18 +35,22 @@ object GCS { data: Vector[ByteVector], key: SipHashKey, p: UInt8, - m: UInt64): GolombFilter = { + m: UInt64 + ): GolombFilter = { val encodedData = buildGCS(data, key, p, m) GolombFilter(key, m, p, CompactSizeUInt(UInt64(data.length)), encodedData) } - /** Given data, constructs a GolombFilter for that data using Basic Block Filter parameters - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#block-filters]] + /** Given data, constructs a GolombFilter for that data using Basic Block + * Filter parameters + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#block-filters]] */ def buildBasicBlockFilter( data: Vector[ByteVector], - key: SipHashKey): GolombFilter = { + key: SipHashKey + ): GolombFilter = { buildGolombFilter(data, key, FilterType.Basic.P, FilterType.Basic.M) } @@ -54,7 +61,8 @@ object GCS { } /** Hashes the item to the range [0, f) - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#hashing-data-objects]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#hashing-data-objects]] */ def hashToRange(item: ByteVector, f: UInt64, key: SipHashKey): UInt64 = { val hash = sipHash(item, key) @@ -65,12 +73,14 @@ object GCS { } /** Hashes the items of a set of items - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#hashing-data-objects]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#hashing-data-objects]] */ def hashedSetConstruct( rawItems: Vector[ByteVector], key: SipHashKey, - m: UInt64): Vector[UInt64] = { + m: UInt64 + ): Vector[UInt64] = { val n = rawItems.length val f = m * n @@ -85,9 +95,11 @@ object GCS { } /** Converts num to unary (6 = 1111110) - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-rice-coding]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-rice-coding]] * - * TODO: protect against large inputs which cause OutOfMemoryErrors and even larger ones which fail on toInt + * TODO: protect against large inputs which cause OutOfMemoryErrors and even + * larger ones which fail on toInt */ def toUnary(num: UInt64): BitVector = { if (num == UInt64.zero) { @@ -105,7 +117,8 @@ object GCS { } /** Encodes a hash into a unary prefix and binary suffix - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-rice-coding]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-rice-coding]] */ def golombEncode(item: UInt64, p: UInt8): BitVector = { val q = item >> p.toInt @@ -117,8 +130,10 @@ object GCS { prefix ++ pBits } - /** Decodes an item off of the front of a BitVector by reversing [[GCS.golombEncode]] - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-rice-coding]] + /** Decodes an item off of the front of a BitVector by reversing + * [[GCS.golombEncode]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-rice-coding]] */ def golombDecode(codedItem: BitVector, p: UInt8): UInt64 = { @tailrec @@ -152,10 +167,13 @@ object GCS { } } - /** Returns the first hash gcs-encoded at the front of a BitVector, as well as the remaining BitVector */ + /** Returns the first hash gcs-encoded at the front of a BitVector, as well as + * the remaining BitVector + */ private def golombDecodeItemFromSet( encodedData: BitVector, - p: UInt8): (UInt64, BitVector) = { + p: UInt8 + ): (UInt64, BitVector) = { val head = golombDecode(encodedData, p) val prefixSize = (head >> p.toInt).toInt + 1 @@ -163,8 +181,10 @@ object GCS { (head, encodedData.drop(prefixSize + p.toInt)) } - /** Decodes all hashes from golomb-encoded data, reversing [[GCS.encodeSortedSet]] - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#set-queryingdecompression]] + /** Decodes all hashes from golomb-encoded data, reversing + * [[GCS.encodeSortedSet]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#set-queryingdecompression]] */ def golombDecodeSet(encodedData: BitVector, p: UInt8): Vector[UInt64] = golombDecodeSetsWithPredicate(encodedData, p) { _ => @@ -172,15 +192,18 @@ object GCS { } /** Decodes all hashes while the given predicate returns true - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#set-queryingdecompression]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#set-queryingdecompression]] */ def golombDecodeSetsWithPredicate(encodedData: BitVector, p: UInt8)( - predicate: UInt64 => Boolean): Vector[UInt64] = { + predicate: UInt64 => Boolean + ): Vector[UInt64] = { @tailrec def loop( encoded: BitVector, lastHash: UInt64, - decoded: Vector[UInt64]): Vector[UInt64] = { + decoded: Vector[UInt64] + ): Vector[UInt64] = { if (encoded.length < p.toInt + 1) { // Only padding left decoded } else { @@ -198,7 +221,8 @@ object GCS { } /** Given a set of ascending hashes, golomb-encodes them - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#set-construction]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#set-construction]] */ def encodeSortedSet(hashes: Vector[UInt64], p: UInt8): BitVector = { val (golombStream, _) = hashes.foldLeft((BitVector.empty, UInt64.zero)) { diff --git a/core/src/main/scala/org/bitcoins/core/gcs/GolombFilter.scala b/core/src/main/scala/org/bitcoins/core/gcs/GolombFilter.scala index 35a287cd6c..053ea9fb85 100644 --- a/core/src/main/scala/org/bitcoins/core/gcs/GolombFilter.scala +++ b/core/src/main/scala/org/bitcoins/core/gcs/GolombFilter.scala @@ -12,7 +12,8 @@ import org.bitcoins.crypto.{ import scodec.bits.{BitVector, ByteVector} /** Represents a GCS encoded set with all parameters specified - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-coded-sets]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#golomb-coded-sets]] * * TODO: Replace ByteVector with a type for keys */ @@ -21,8 +22,8 @@ case class GolombFilter( m: UInt64, p: UInt8, n: CompactSizeUInt, - encodedData: BitVector) - extends NetworkElement { + encodedData: BitVector +) extends NetworkElement { lazy val f: UInt64 = n.num * m /** The hash of this serialized filter */ @@ -34,12 +35,16 @@ case class GolombFilter( hash.flip } - /** Given the previous FilterHeader, constructs the header corresponding to this */ + /** Given the previous FilterHeader, constructs the header corresponding to + * this + */ def getHeader(prevHeader: FilterHeader): FilterHeader = { FilterHeader(filterHash = this.hash, prevHeaderHash = prevHeader.hash) } - /** Given the previous FilterHeader hash, constructs the header corresponding to this */ + /** Given the previous FilterHeader hash, constructs the header corresponding + * to this + */ def getHeader(prevHeaderHash: DoubleSha256Digest): FilterHeader = { FilterHeader(filterHash = this.hash, prevHeaderHash = prevHeaderHash) } diff --git a/core/src/main/scala/org/bitcoins/core/hd/AddressType.scala b/core/src/main/scala/org/bitcoins/core/hd/AddressType.scala index 2b91ab5076..43dd37f4c4 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/AddressType.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/AddressType.scala @@ -14,8 +14,8 @@ object AddressType extends StringFactory[AddressType] { override def altName: String = "bech32" } - /** Uses BIP49 address derivation, gives SegWit addresses wrapped - * in P2SH addresses (`3...`) + /** Uses BIP49 address derivation, gives SegWit addresses wrapped in P2SH + * addresses (`3...`) */ final case object NestedSegWit extends AddressType { override def altName: String = "p2sh-segwit" diff --git a/core/src/main/scala/org/bitcoins/core/hd/BIP32Path.scala b/core/src/main/scala/org/bitcoins/core/hd/BIP32Path.scala index f7ab64ae07..a214724523 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/BIP32Path.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/BIP32Path.scala @@ -10,13 +10,12 @@ abstract class BIP32Path extends SeqWrapper[BIP32Node] { def path: Vector[BIP32Node] override protected lazy val wrapped: Vector[BIP32Node] = path - /** BIP32 paths can be subsets/superset of each other. - * If all elements in a path `p` is included in a path - * `P`, (i.e. `p` is a subset of `P`), `p.diff(P)` - * is the elements from `P` that is not in `p`. + /** BIP32 paths can be subsets/superset of each other. If all elements in a + * path `p` is included in a path `P`, (i.e. `p` is a subset of `P`), + * `p.diff(P)` is the elements from `P` that is not in `p`. * * @example - * {{{ + * {{{ * // equal paths * m/44'/1' diff m/44'/1' == Some(BIP32Path.empty) * @@ -30,7 +29,7 @@ abstract class BIP32Path extends SeqWrapper[BIP32Node] { * // any fields are unequal along the way * m/44'/1' diff m/43'/2' == None * m/44'/1'/0 diff m/44'/2'/1 == None - * }}} + * }}} */ def diff(otherPath: BIP32Path): Option[BIP32Path] = { @@ -96,11 +95,11 @@ abstract class BIP32Path extends SeqWrapper[BIP32Node] { object BIP32Path extends Factory[BIP32Path] with StringFactory[BIP32Path] { private case class BIP32PathImpl(path: Vector[BIP32Node]) extends BIP32Path - /** The empty BIP32 path "m", i.e. a path that does no - * child key derivation + /** The empty BIP32 path "m", i.e. a path that does no child key derivation * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#the-key-tree BIP44]] - * section on key trees + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#the-key-tree BIP44]] + * section on key trees */ val empty: BIP32Path = BIP32PathImpl(Vector.empty) @@ -108,20 +107,21 @@ object BIP32Path extends Factory[BIP32Path] with StringFactory[BIP32Path] { def apply(path: BIP32Node*): BIP32Path = BIP32Path(Vector(path: _*)) - /** Parses a string representation of a BIP32 path. This is on the form - * of + /** Parses a string representation of a BIP32 path. This is on the form of * * {{{ * m/level/hardenedLevel'/... * }}} * - * Where `level` is an integer index and hardenedLevel is an integer - * index followed by a `'`. Different notation is used in BIP32, but this - * is the most common way of writing down BIP32 paths. + * Where `level` is an integer index and hardenedLevel is an integer index + * followed by a `'`. Different notation is used in BIP32, but this is the + * most common way of writing down BIP32 paths. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki BIP43]] - * and [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]] - * for examples of this notation. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki BIP43]] + * and + * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]] + * for examples of this notation. */ override def fromString(string: String): BIP32Path = { val parts = string @@ -136,8 +136,10 @@ object BIP32Path extends Factory[BIP32Path] with StringFactory[BIP32Path] { } else { val head = parts.head val rest = parts.tail - require(head == "m", - """The first element in a BIP32 path string must be "m"""") + require( + head == "m", + """The first element in a BIP32 path string must be "m"""" + ) val path = rest.map { str => val (index: String, hardenedOpt: Option[HardenedType]) = { @@ -154,18 +156,23 @@ object BIP32Path extends Factory[BIP32Path] with StringFactory[BIP32Path] { } /** Takes in a BIP32 Path and verifies all paths are hardened - * @throws RuntimeException is a non hardened path is found + * @throws RuntimeException + * is a non hardened path is found */ def fromHardenedString(string: String): BIP32Path = { val path = BIP32Path.fromString(string) - require(path.forall(_.hardened), - s"Found non hardened path in string=$string") + require( + path.forall(_.hardened), + s"Found non hardened path in string=$string" + ) path } private def fromBytes(bytes: ByteVector, littleEndian: Boolean): BIP32Path = { - require(bytes.size % 4 == 0, - s"ByteVector is not suited for KeyPath, got=${bytes.length}") + require( + bytes.size % 4 == 0, + s"ByteVector is not suited for KeyPath, got=${bytes.length}" + ) val parts: Vector[ByteVector] = bytes.grouped(4).toVector @@ -193,8 +200,7 @@ case class BIP32Node(index: Int, hardenedOpt: Option[HardenedType]) { def hardened: Boolean = hardenedOpt.isDefined - /** Converts this node to a BIP32 notation - * unsigned 32 bit integer + /** Converts this node to a BIP32 notation unsigned 32 bit integer */ def toUInt32: UInt32 = if (hardenedOpt.isDefined) ExtKey.hardenedIdx + UInt32(index.toLong) diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDAccount.scala b/core/src/main/scala/org/bitcoins/core/hd/HDAccount.scala index ec3408af3b..893e4dd917 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDAccount.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDAccount.scala @@ -2,8 +2,7 @@ package org.bitcoins.core.hd /** Represents a * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#Account BIP44]], - * [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] - * and + * [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] and * [[https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki BIP49]] * account * @@ -39,17 +38,16 @@ object HDAccount { } } - /** This method is meant to take in an arbitrary bip32 path and see - * if it has the same account as the given account + /** This method is meant to take in an arbitrary bip32 path and see if it has + * the same account as the given account * - * This is tricky as an account is defined as - * m / purpose' / cointype' / account' + * This is tricky as an account is defined as m / purpose' / cointype' / + * account' * * whereas a bip32 path can be arbitrarily deep. * - * We want to just check the first 4 elements of the path - * and see if they are the same, which indicates we are in - * the same account + * We want to just check the first 4 elements of the path and see if they are + * the same, which indicates we are in the same account */ def isSameAccount(path: Vector[BIP32Node], account: HDAccount): Boolean = { if (account.path.length > path.length) { diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDAddress.scala b/core/src/main/scala/org/bitcoins/core/hd/HDAddress.scala index cbfa3faab8..87b6d08c14 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDAddress.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDAddress.scala @@ -34,14 +34,16 @@ object HDAddress { account: HDAccount, chain: HDChain, index: Int, - purpose: HDPurpose) - extends HDAddress + purpose: HDPurpose + ) extends HDAddress def apply(chain: HDChain, index: Int): HDAddress = - HDAddressImpl(coin = chain.coin, - account = chain.account, - chain = chain, - index = index, - purpose = chain.purpose) + HDAddressImpl( + coin = chain.coin, + account = chain.account, + chain = chain, + index = index, + purpose = chain.purpose + ) } diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDChain.scala b/core/src/main/scala/org/bitcoins/core/hd/HDChain.scala index bbdc7f2bfc..592ac0489b 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDChain.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDChain.scala @@ -31,8 +31,8 @@ object HDChain { coin: HDCoin, chainType: HDChainType, account: HDAccount, - purpose: HDPurpose) - extends HDChain + purpose: HDPurpose + ) extends HDChain def apply(chainType: HDChainType, account: HDAccount): HDChain = BIP44ChainImpl(account.coin, chainType, account, account.purpose) diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDChainType.scala b/core/src/main/scala/org/bitcoins/core/hd/HDChainType.scala index 7627b4de0c..20d230bf64 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDChainType.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDChainType.scala @@ -2,12 +2,10 @@ package org.bitcoins.core.hd /** Address chain (external vs. change) used by * - * Format: - * m / purpose' / coin_type' / account' / change + * Format: m / purpose' / coin_type' / account' / change * * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#change BIP44]], - * [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] - * and + * [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] and * [[https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki BIP49]] * * @see @@ -18,18 +16,15 @@ sealed abstract class HDChainType { object HDChainType { - /** External chain is used for addresses that - * are meant to be visible outside of the - * wallet (e.g. for receiving payments). + /** External chain is used for addresses that are meant to be visible outside + * of the wallet (e.g. for receiving payments). */ final case object External extends HDChainType { override val index: Int = 0 } - /** Internal chain is used for addresses which - * are not meant to be visible outside of the - * wallet and is used for return transaction - * change + /** Internal chain is used for addresses which are not meant to be visible + * outside of the wallet and is used for return transaction change */ final case object Change extends HDChainType { override val index: Int = 1 @@ -41,6 +36,7 @@ object HDChainType { case Change.index => HDChainType.Change case _: Int => throw new IllegalArgumentException( - s"$int is not a valid BIP44 change type!") + s"$int is not a valid BIP44 change type!" + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDCoin.scala b/core/src/main/scala/org/bitcoins/core/hd/HDCoin.scala index 494104c7fb..794a0fa9f3 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDCoin.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDCoin.scala @@ -1,8 +1,8 @@ package org.bitcoins.core.hd -/** Contains the path - * m / purpose' / coin_type' / - * @see https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#path-levels +/** Contains the path m / purpose' / coin_type' / + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#path-levels */ case class HDCoin(purpose: HDPurpose, coinType: HDCoinType) extends BIP32Path { diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDCoinType.scala b/core/src/main/scala/org/bitcoins/core/hd/HDCoinType.scala index c57cd646e0..30040616cb 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDCoinType.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDCoinType.scala @@ -4,8 +4,7 @@ import org.bitcoins.core.config._ /** Represents a * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#Coin_type BIP44]], - * [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] - * and + * [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] and * [[https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki BIP49]] * coin type. */ @@ -13,8 +12,9 @@ sealed trait HDCoinType { def toInt: Int } -/** @see [[https://github.com/satoshilabs/slips/blob/master/slip-0044.md SLIP-0044]] - * central registry of coin types +/** @see + * [[https://github.com/satoshilabs/slips/blob/master/slip-0044.md SLIP-0044]] + * central registry of coin types */ object HDCoinType { @@ -45,8 +45,10 @@ object HDCoinType { } def fromNode(node: BIP32Node): HDCoinType = { - require(node.hardened, - s"Cannot construct HDCoinType from un-hardened node: $node") + require( + node.hardened, + s"Cannot construct HDCoinType from un-hardened node: $node" + ) fromInt(node.index) } diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDPath.scala b/core/src/main/scala/org/bitcoins/core/hd/HDPath.scala index 6b2b080b1f..5deb83f92d 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDPath.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDPath.scala @@ -6,8 +6,7 @@ import scala.util.{Failure, Success, Try} trait HDPath extends BIP32Path { - /** This type is to give a cleaner return - * type of `next`. + /** This type is to give a cleaner return type of `next`. * * Consider: * @@ -34,9 +33,8 @@ trait HDPath extends BIP32Path { */ protected type NextPath <: HDPath - /** Increments the address index and returns the - * new path that can be passed into a - * [[org.bitcoins.core.crypto.ExtKey ExtKey]] + /** Increments the address index and returns the new path that can be passed + * into a [[org.bitcoins.core.crypto.ExtKey ExtKey]] */ def next: NextPath = HDAddress(chain, address.index + 1).toPath.asInstanceOf[NextPath] @@ -66,7 +64,9 @@ object HDPath extends StringFactory[HDPath] { if (path.path.isEmpty) { Failure( new IllegalArgumentException( - s"Cannot parse an empty HDPath, got str=$string")) + s"Cannot parse an empty HDPath, got str=$string" + ) + ) } else { val purpose = path.path.head.index if (purpose == LegacyHDPath.PURPOSE) { diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDPathFactory.scala b/core/src/main/scala/org/bitcoins/core/hd/HDPathFactory.scala index bab2bd92cd..e8211ec808 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDPathFactory.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDPathFactory.scala @@ -13,7 +13,8 @@ private[hd] trait HDPathFactory[PathType <: BIP32Path] coin: HDCoinType, accountIndex: Int, chainType: HDChainType, - addressIndex: Int): PathType + addressIndex: Int + ): PathType /** Tries to generate a HD path from the given path segments */ @@ -43,7 +44,8 @@ private[hd] trait HDPathFactory[PathType <: BIP32Path] val purpose: HDPurpose = maybePurpose match { case BIP32Node(_, None) => throw new IllegalArgumentException( - "The first child in a HD path must be hardened") + "The first child in a HD path must be hardened" + ) case BIP32Node(HDPurposes.Legacy.constant, Some(_)) => HDPurposes.Legacy case BIP32Node(HDPurposes.SegWit.constant, Some(_)) => HDPurposes.SegWit case BIP32Node(HDPurposes.NestedSegWit.constant, Some(_)) => @@ -52,42 +54,53 @@ private[hd] trait HDPathFactory[PathType <: BIP32Path] HDPurposes.Multisig case BIP32Node(unknown, Some(_)) => throw new IllegalArgumentException( - s"Purpose constant ($unknown) is not a known purpose constant") + s"Purpose constant ($unknown) is not a known purpose constant" + ) } require( purpose.constant == PURPOSE, - s"Expected $PURPOSE' as the purpose constant, got ${purpose.constant}'") + s"Expected $PURPOSE' as the purpose constant, got ${purpose.constant}'" + ) - require(children.length == 5, - s"A $pathName path string must have five elements") + require( + children.length == 5, + s"A $pathName path string must have five elements" + ) val (coinChild, accountChild, chainChild, addressChild) = { - require(children.length == 5, - s"Must have 5 elements in HDPath, got=$children") + require( + children.length == 5, + s"Must have 5 elements in HDPath, got=$children" + ) (children(1), children(2), children(3), children(4)) } require(coinChild.hardened, "The coin type child must be hardened!") require(accountChild.hardened, "The account child must be hardened!") require(!chainChild.hardened, "The chain child must not be hardened!") - require(!addressChild.hardened, - "The address index child must not be hardened!") + require( + !addressChild.hardened, + "The address index child must not be hardened!" + ) val chainType = HDChainType.fromInt(chainChild.index) val coinType = HDCoinType.fromInt(coinChild.index) - apply(coin = coinType, - accountIndex = accountChild.index, - chainType = chainType, - addressIndex = addressChild.index) + apply( + coin = coinType, + accountIndex = accountChild.index, + chainType = chainType, + addressIndex = addressChild.index + ) } protected def assembleAddress( coinType: HDCoinType, accountIndex: Int, chainType: HDChainType, - addressIndex: Int): HDAddress = { + addressIndex: Int + ): HDAddress = { val coin = HDCoin(hdPurpose, coinType) val account = HDAccount(coin = coin, index = accountIndex) val chain = @@ -97,7 +110,8 @@ private[hd] trait HDPathFactory[PathType <: BIP32Path] /** The purpose constant from BIP43 * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki#purpose BIP43]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki#purpose BIP43]] */ def PURPOSE: Int diff --git a/core/src/main/scala/org/bitcoins/core/hd/HDPurpose.scala b/core/src/main/scala/org/bitcoins/core/hd/HDPurpose.scala index f8d354fffe..d70dc71abb 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/HDPurpose.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/HDPurpose.scala @@ -1,24 +1,29 @@ package org.bitcoins.core.hd -/** This is a field that is used in conjunction with BIP44 to indicate - * what the purpose of this [[org.bitcoins.core.crypto.ExtKey ExtKey]] is. +/** This is a field that is used in conjunction with BIP44 to indicate what the + * purpose of this [[org.bitcoins.core.crypto.ExtKey ExtKey]] is. * - * This has been used for deploying keychains that are compatible with - * raw segwit, p2sh wrapped segwit, and raw scripts. + * This has been used for deploying keychains that are compatible with raw + * segwit, p2sh wrapped segwit, and raw scripts. * - * Format: - * m / purpose' + * Format: m / purpose' * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki BIP43]] - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#Purpose BIP44]] - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki#Purpose BIP45]] - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki BIP49]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki BIP43]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#Purpose BIP44]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki#Purpose BIP45]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki BIP49]] */ case class HDPurpose(constant: Int) extends BIP32Path { override val path: Vector[BIP32Node] = Vector( - BIP32Node(constant, HardenedType.defaultOpt)) + BIP32Node(constant, HardenedType.defaultOpt) + ) } object HDPurposes { @@ -36,8 +41,10 @@ object HDPurposes { def fromConstant(i: Int): Option[HDPurpose] = all.find(_.constant == i) def fromNode(node: BIP32Node): Option[HDPurpose] = { - require(node.hardened, - s"Cannot construct HDPurpose from un-hardened node: $node") + require( + node.hardened, + s"Cannot construct HDPurpose from un-hardened node: $node" + ) fromConstant(node.index) } } diff --git a/core/src/main/scala/org/bitcoins/core/hd/LegacyHDPath.scala b/core/src/main/scala/org/bitcoins/core/hd/LegacyHDPath.scala index c7d2ab5bd8..78ba1ac40e 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/LegacyHDPath.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/LegacyHDPath.scala @@ -8,7 +8,8 @@ object LegacyHDPath extends HDPathFactory[LegacyHDPath] { /** The purpose constant from BIP44 * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#purpose BIP44]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#purpose BIP44]] */ override val PURPOSE: Int = 44 @@ -18,7 +19,8 @@ object LegacyHDPath extends HDPathFactory[LegacyHDPath] { coinType: HDCoinType, accountIndex: Int, chainType: HDChainType, - addressIndex: Int): LegacyHDPath = { + addressIndex: Int + ): LegacyHDPath = { val address = assembleAddress(coinType, accountIndex, chainType, addressIndex) diff --git a/core/src/main/scala/org/bitcoins/core/hd/MultisigHDPath.scala b/core/src/main/scala/org/bitcoins/core/hd/MultisigHDPath.scala index c2f8c4ad9e..f272cb3c82 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/MultisigHDPath.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/MultisigHDPath.scala @@ -8,7 +8,8 @@ object MultisigHDPath extends HDPathFactory[MultisigHDPath] { /** The purpose constant from BIP45 * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki BIP45]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki BIP45]] */ override val PURPOSE: Int = 45 @@ -19,7 +20,8 @@ object MultisigHDPath extends HDPathFactory[MultisigHDPath] { coinType: HDCoinType, accountIndex: Int, chainType: HDChainType, - addressIndex: Int): MultisigHDPath = { + addressIndex: Int + ): MultisigHDPath = { val address = assembleAddress(coinType, accountIndex, chainType, addressIndex) diff --git a/core/src/main/scala/org/bitcoins/core/hd/NestedSegWitHDPath.scala b/core/src/main/scala/org/bitcoins/core/hd/NestedSegWitHDPath.scala index 86693e9922..70c9df3d5a 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/NestedSegWitHDPath.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/NestedSegWitHDPath.scala @@ -8,7 +8,8 @@ object NestedSegWitHDPath extends HDPathFactory[NestedSegWitHDPath] { /** The purpose constant from BIP49 * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki BIP49]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki BIP49]] */ override val PURPOSE: Int = 49 @@ -19,7 +20,8 @@ object NestedSegWitHDPath extends HDPathFactory[NestedSegWitHDPath] { coinType: HDCoinType, accountIndex: Int, chainType: HDChainType, - addressIndex: Int): NestedSegWitHDPath = { + addressIndex: Int + ): NestedSegWitHDPath = { val address = assembleAddress(coinType, accountIndex, chainType, addressIndex) diff --git a/core/src/main/scala/org/bitcoins/core/hd/SegWitHDPath.scala b/core/src/main/scala/org/bitcoins/core/hd/SegWitHDPath.scala index 980c57dfdb..1e5fe38198 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/SegWitHDPath.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/SegWitHDPath.scala @@ -8,7 +8,8 @@ object SegWitHDPath extends HDPathFactory[SegWitHDPath] { /** The purpose constant from BIP84 * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki BIP84]] */ override val PURPOSE = 84 @@ -18,7 +19,8 @@ object SegWitHDPath extends HDPathFactory[SegWitHDPath] { coinType: HDCoinType, accountIndex: Int, chainType: HDChainType, - addressIndex: Int): SegWitHDPath = { + addressIndex: Int + ): SegWitHDPath = { val address = assembleAddress(coinType, accountIndex, chainType, addressIndex) SegWitHDPathImpl(address) diff --git a/core/src/main/scala/org/bitcoins/core/hd/package.scala b/core/src/main/scala/org/bitcoins/core/hd/package.scala index b29c47da82..9bcbec350f 100644 --- a/core/src/main/scala/org/bitcoins/core/hd/package.scala +++ b/core/src/main/scala/org/bitcoins/core/hd/package.scala @@ -1,12 +1,13 @@ package org.bitcoins.core -/** This package contains different HD wallet - * key derivation paths. +/** This package contains different HD wallet key derivation paths. * - * @see [[http://bitcoin-s.github.io/bitcoin-s-core/latest/api/ Hierarchical Deterministic Key Creation]] - * on Bitcoin.org Developer Guide + * @see + * [[http://bitcoin-s.github.io/bitcoin-s-core/latest/api/ Hierarchical Deterministic Key Creation]] + * on Bitcoin.org Developer Guide * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]], - * Hierarchical Deterministic Wallets + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki BIP32]], + * Hierarchical Deterministic Wallets */ package object hd diff --git a/core/src/main/scala/org/bitcoins/core/number/BasicArithmetic.scala b/core/src/main/scala/org/bitcoins/core/number/BasicArithmetic.scala index 6c6fa76f8d..e5b0713c01 100644 --- a/core/src/main/scala/org/bitcoins/core/number/BasicArithmetic.scala +++ b/core/src/main/scala/org/bitcoins/core/number/BasicArithmetic.scala @@ -3,28 +3,25 @@ package org.bitcoins.core.number import scala.util.Try /** @define mulSafe - * Some classes have restrictions on upper bounds - * for it's underlying value. This might cause the `*` - * operator to throw. This method wraps it in a `Try` - * block. + * Some classes have restrictions on upper bounds for it's underlying value. + * This might cause the `*` operator to throw. This method wraps it in a + * `Try` block. */ trait BasicArithmetic[N] { def +(n: N): N - /** Some classes have restrictions on upper bounds - * for it's underlying value. This might cause the `+` - * operator to throw. This method wraps it in a `Try` - * block. + /** Some classes have restrictions on upper bounds for it's underlying value. + * This might cause the `+` operator to throw. This method wraps it in a + * `Try` block. */ def addSafe(n: N): Try[N] = Try { this + n } def -(n: N): N - /** Some classes have restrictions on lower bounds - * for it's underlying value. This might cause the `-` - * operator to throw. This method wraps it in a `Try` - * block. + /** Some classes have restrictions on lower bounds for it's underlying value. + * This might cause the `-` operator to throw. This method wraps it in a + * `Try` block. */ def subtractSafe(n: N): Try[N] = Try { this - n } diff --git a/core/src/main/scala/org/bitcoins/core/number/NumberCache.scala b/core/src/main/scala/org/bitcoins/core/number/NumberCache.scala index 1823c7fa5f..2bd7995ad6 100644 --- a/core/src/main/scala/org/bitcoins/core/number/NumberCache.scala +++ b/core/src/main/scala/org/bitcoins/core/number/NumberCache.scala @@ -1,8 +1,7 @@ package org.bitcoins.core.number -/** Helper trait to cache data types that represent numbers - * Examples are [[org.bitcoins.core.script.constant.ScriptNumber]] - * [[UInt32]] [[UInt64]] etc +/** Helper trait to cache data types that represent numbers Examples are + * [[org.bitcoins.core.script.constant.ScriptNumber]] [[UInt32]] [[UInt64]] etc */ trait NumberCache[T] { def fromNativeNumber(long: Long): T @@ -17,8 +16,8 @@ trait NumberCache[T] { minCached.to(maxCached).map(fromNativeNumber).toVector } - /** Checks if the given number is cached - * if not, allocates a new object to represent the number + /** Checks if the given number is cached if not, allocates a new object to + * represent the number */ def checkCached(long: Long): T = { if (long <= maxCached && long >= minCached) cache(long.toInt) @@ -46,13 +45,13 @@ trait NumberCacheBigInt[T] extends NumberCache[T] { /** The max number cached (inclusive) */ def maxCachedBigInt: BigInt = BigInt(maxCached) - /** [[org.bitcoins.core.protocol.CompactSizeUInt]] uses a UInt64 - * which means we have larger uint64s used on a regular basis + /** [[org.bitcoins.core.protocol.CompactSizeUInt]] uses a UInt64 which means + * we have larger uint64s used on a regular basis */ override def maxCached: Long = 2048 - /** Checks if the given number is cached - * if not, allocates a new object to represent the number + /** Checks if the given number is cached if not, allocates a new object to + * represent the number */ def checkCachedBigInt(bigInt: BigInt): T = { if (bigInt <= maxCachedBigInt && bigInt >= minCachedBigInt) diff --git a/core/src/main/scala/org/bitcoins/core/number/NumberType.scala b/core/src/main/scala/org/bitcoins/core/number/NumberType.scala index 2f793e3199..607fe5af90 100644 --- a/core/src/main/scala/org/bitcoins/core/number/NumberType.scala +++ b/core/src/main/scala/org/bitcoins/core/number/NumberType.scala @@ -24,14 +24,14 @@ sealed abstract class Number[T <: Number[T]] def toLong: Long = toBigInt.bigInteger.longExact def toBigInt: BigInt = underlying - /** This is used to determine the valid amount of bytes in a number - * for instance a UInt8 has an andMask of 0xff - * a UInt32 has an andMask of 0xffffffff + /** This is used to determine the valid amount of bytes in a number for + * instance a UInt8 has an andMask of 0xff a UInt32 has an andMask of + * 0xffffffff */ def andMask: BigInt - /** Factory function to create the underlying T, for instance a UInt32. - * This method must check if the parameter is in the required range. + /** Factory function to create the underlying T, for instance a UInt32. This + * method must check if the parameter is in the required range. */ def apply: A => T @@ -53,8 +53,8 @@ sealed abstract class Number[T <: Number[T]] } def >>(num: T): T = { - //this check is for weird behavior with the jvm and shift rights - //https://stackoverflow.com/questions/47519140/bitwise-shift-right-with-long-not-equaling-zero/47519728#47519728 + // this check is for weird behavior with the jvm and shift rights + // https://stackoverflow.com/questions/47519140/bitwise-shift-right-with-long-not-equaling-zero/47519728#47519728 if (num.toLong > 63) apply(0) else { val toInt = num.toInt @@ -90,23 +90,24 @@ sealed abstract class Number[T <: Number[T]] def truncatedBytes: ByteVector = bytes.dropWhile(_ == 0x00) } -/** Represents a signed number in our number system - * Instances of this are [[Int32]] or [[Int64]] +/** Represents a signed number in our number system Instances of this are + * [[Int32]] or [[Int64]] */ sealed abstract class SignedNumber[T <: Number[T]] extends Number[T] { final override def isSigned: Boolean = true } -/** Represents an unsigned number in our number system - * Instances of this are [[UInt32]] or [[UInt64]] +/** Represents an unsigned number in our number system Instances of this are + * [[UInt32]] or [[UInt64]] */ sealed abstract class UnsignedNumber[T <: Number[T]] extends Number[T] { final override def isSigned: Boolean = false } -/** This number type is useful for dealing with [[org.bitcoins.core.util.Bech32]] - * related applications. The native encoding for Bech32 is a 5 bit number which - * is what this abstraction is meant to be used for +/** This number type is useful for dealing with + * [[org.bitcoins.core.util.Bech32]] related applications. The native encoding + * for Bech32 is a 5 bit number which is what this abstraction is meant to be + * used for */ sealed abstract class UInt5 extends UnsignedNumber[UInt5] { override def apply: A => UInt5 = UInt5(_) @@ -128,7 +129,7 @@ sealed abstract class UInt8 extends UnsignedNumber[UInt8] { override val andMask = 0xff def toUInt5: UInt5 = { - //this will throw if not in range of a UInt5, come back and look later + // this will throw if not in range of a UInt5, come back and look later UInt5(toInt) } } @@ -156,28 +157,30 @@ sealed abstract class UInt64 extends UnsignedNumber[UInt64] { override val bytes: ByteVector = { if (underlying.isValidLong) { - //optimization, if our number fits into a long - //we can get much better performance from ByteVector + // optimization, if our number fits into a long + // we can get much better performance from ByteVector ByteVector.fromLong(underlying.toLong, 8) } else { - //else just do what we were doing before + // else just do what we were doing before ByteVector.fromValidHex(encodeHex(bigInt = underlying)) } } override def apply: A => UInt64 = UInt64(_) override val andMask = 0xffffffffffffffffL - /** Converts a [[BigInt]] to a 8 byte hex representation. - * [[BigInt]] will only allocate 1 byte for numbers like 1 which require 1 byte, giving us the hex representation 01 - * this function pads the hex chars to be 0000000000000001 + /** Converts a [[BigInt]] to a 8 byte hex representation. [[BigInt]] will only + * allocate 1 byte for numbers like 1 which require 1 byte, giving us the hex + * representation 01 this function pads the hex chars to be 0000000000000001 * - * @param bigInt The number to encode - * @return The hex encoded number + * @param bigInt + * The number to encode + * @return + * The hex encoded number */ private def encodeHex(bigInt: BigInt): String = { val hex = BytesUtil.encodeHex(bigInt) if (hex.length == 18) { - //means that encodeHex(BigInt) padded an extra byte, giving us 9 bytes instead of 8 + // means that encodeHex(BigInt) padded an extra byte, giving us 9 bytes instead of 8 hex.slice(2, hex.length) } else { val needed = 16 - hex.length @@ -205,7 +208,8 @@ sealed abstract class Int64 extends SignedNumber[Int64] { /** Represents number types that are bounded by minimum and maximum values * - * @tparam T Type of the numbers + * @tparam T + * Type of the numbers */ trait Bounded[T] { def min: T @@ -217,8 +221,7 @@ trait BaseNumbers[T] { def one: T } -/** Should be implemented inside of any companion - * object for a number +/** Should be implemented inside of any companion object for a number */ trait NumberObject[T <: Number[T]] extends BaseNumbers[T] { type A = BigInt @@ -233,8 +236,10 @@ object UInt5 with NumberCache[UInt5] { private case class UInt5Impl(underlying: BigInt) extends UInt5 { - require(isInBound(underlying), - s"Cannot create ${super.getClass.getSimpleName} from $underlying") + require( + isInBound(underlying), + s"Cannot create ${super.getClass.getSimpleName} from $underlying" + ) } lazy val zero = checkCached(0) @@ -261,7 +266,8 @@ object UInt5 def apply(bigInt: BigInt): UInt5 = { require( bigInt.toByteArray.length == 1, - s"To create a uint5 from a BigInt it must be less than 32. Got: ${bigInt.toString}") + s"To create a uint5 from a BigInt it must be less than 32. Got: ${bigInt.toString}" + ) UInt5.fromByte(bigInt.toByteArray.head) } @@ -269,7 +275,8 @@ object UInt5 override def fromBytes(bytes: ByteVector): UInt5 = { require( bytes.size == 1, - s"To create a uint5 from a ByteVector it must be of size one ${bytes.length}") + s"To create a uint5 from a ByteVector it must be of size one ${bytes.length}" + ) UInt5.fromByte(bytes.head) } @@ -293,8 +300,10 @@ object UInt8 with NumberCache[UInt8] { private case class UInt8Impl(underlying: BigInt) extends UInt8 { - require(isInBound(underlying), - s"Cannot create ${super.getClass.getSimpleName} from $underlying") + require( + isInBound(underlying), + s"Cannot create ${super.getClass.getSimpleName} from $underlying" + ) } lazy val zero = checkCached(0.toShort) lazy val one = checkCached(1.toShort) @@ -321,7 +330,8 @@ object UInt8 override def fromBytes(bytes: ByteVector): UInt8 = { require( bytes.size == 1, - "Can only create a uint8 from a byte array of size one, got: " + bytes) + "Can only create a uint8 from a byte array of size one, got: " + bytes + ) UInt8(NumberUtil.toUnsignedInt(bytes)) } @@ -348,8 +358,10 @@ object UInt16 with NumberCache[UInt16] { private case class UInt16Impl(underlying: BigInt) extends UInt16 { - require(isInBound(underlying), - s"Cannot create ${super.getClass.getSimpleName} from $underlying") + require( + isInBound(underlying), + s"Cannot create ${super.getClass.getSimpleName} from $underlying" + ) } lazy val zero = checkCached(0) @@ -372,7 +384,8 @@ object UInt16 override def fromBytes(bytes: ByteVector): UInt16 = { require( bytes.size <= 2, - "UInt16 byte array was too large, got: " + BytesUtil.encodeHex(bytes)) + "UInt16 byte array was too large, got: " + BytesUtil.encodeHex(bytes) + ) UInt16(bytes.toLong(signed = false, ordering = ByteOrdering.BigEndian)) } @@ -396,8 +409,10 @@ object UInt32 with NumberCache[UInt32] { private case class UInt32Impl(underlying: BigInt) extends UInt32 { - require(isInBound(underlying), - s"Cannot create ${super.getClass.getSimpleName} from $underlying") + require( + isInBound(underlying), + s"Cannot create ${super.getClass.getSimpleName} from $underlying" + ) } lazy val zero: UInt32 = checkCached(0) @@ -420,7 +435,8 @@ object UInt32 override def fromBytes(bytes: ByteVector): UInt32 = { require( bytes.size <= 4, - "UInt32 byte array was too large, got: " + BytesUtil.encodeHex(bytes)) + "UInt32 byte array was too large, got: " + BytesUtil.encodeHex(bytes) + ) UInt32(bytes.toLong(signed = false, ordering = ByteOrdering.BigEndian)) } @@ -448,8 +464,10 @@ object UInt64 with NumberCacheBigInt[UInt64] { private case class UInt64Impl(underlying: BigInt) extends UInt64 { - require(isInBound(underlying), - s"Cannot create ${super.getClass.getSimpleName} from $underlying") + require( + isInBound(underlying), + s"Cannot create ${super.getClass.getSimpleName} from $underlying" + ) } lazy val zero = checkCached(0) @@ -461,11 +479,11 @@ object UInt64 lazy val min = UInt64(minUnderlying) lazy val max = UInt64(maxUnderlying) - lazy val twentyThree = UInt64(BigInt(23)) //p2sh compact size uint - lazy val twentyFive = UInt64(BigInt(25)) //p2pkh compact size uint - lazy val oneHundredFive = UInt64(BigInt(105)) //multisig spk 3 public keys - lazy val thirtyFour = UInt64(BigInt(34)) //p2wsh compact size uint - lazy val twentyTwo = UInt64(BigInt(22)) //p2pwpkh compact size uint + lazy val twentyThree = UInt64(BigInt(23)) // p2sh compact size uint + lazy val twentyFive = UInt64(BigInt(25)) // p2pkh compact size uint + lazy val oneHundredFive = UInt64(BigInt(105)) // multisig spk 3 public keys + lazy val thirtyFour = UInt64(BigInt(34)) // p2wsh compact size uint + lazy val twentyTwo = UInt64(BigInt(22)) // p2pwpkh compact size uint override def isInBound(num: A): Boolean = num <= maxUnderlying && num >= minUnderlying @@ -501,8 +519,10 @@ object Int32 with NumberCache[Int32] { private case class Int32Impl(underlying: BigInt) extends Int32 { - require(isInBound(underlying), - s"Cannot create ${super.getClass.getSimpleName} from $underlying") + require( + isInBound(underlying), + s"Cannot create ${super.getClass.getSimpleName} from $underlying" + ) } val negOne = Int32(-1) @@ -542,8 +562,10 @@ object Int64 with NumberCache[Int64] { private case class Int64Impl(underlying: BigInt) extends Int64 { - require(isInBound(underlying), - s"Cannot create ${super.getClass.getSimpleName} from $underlying") + require( + isInBound(underlying), + s"Cannot create ${super.getClass.getSimpleName} from $underlying" + ) } lazy val zero = checkCached(0) diff --git a/core/src/main/scala/org/bitcoins/core/p2p/InetAddress.scala b/core/src/main/scala/org/bitcoins/core/p2p/InetAddress.scala index 73efba6966..86bf0c6466 100644 --- a/core/src/main/scala/org/bitcoins/core/p2p/InetAddress.scala +++ b/core/src/main/scala/org/bitcoins/core/p2p/InetAddress.scala @@ -6,8 +6,10 @@ trait InetAddress { def bytes: ByteVector def ipv4Bytes: ByteVector = { - require(bytes.take(12) == hex"00000000000000000000ffff", - "Cannot call ipv4Bytes for an IPv6 address") + require( + bytes.take(12) == hex"00000000000000000000ffff", + "Cannot call ipv4Bytes for an IPv6 address" + ) bytes.drop(12) } @@ -37,7 +39,8 @@ object InetAddress { trait TorAddress extends InetAddress { override def ipv4Bytes: ByteVector = throw new IllegalArgumentException( - "Tor address cannot be an IPv4 address") + "Tor address cannot be an IPv4 address" + ) } object TorAddress { diff --git a/core/src/main/scala/org/bitcoins/core/p2p/Inventory.scala b/core/src/main/scala/org/bitcoins/core/p2p/Inventory.scala index eaba4d73ba..747e9d9f8a 100644 --- a/core/src/main/scala/org/bitcoins/core/p2p/Inventory.scala +++ b/core/src/main/scala/org/bitcoins/core/p2p/Inventory.scala @@ -6,10 +6,13 @@ import scodec.bits.ByteVector /** These are used as unique identifiers inside the peer-to-peer network * - * @param typeIdentifier The type of object which was hashed - * @param hash SHA256(SHA256()) hash of the object in internal byte order. + * @param typeIdentifier + * The type of object which was hashed + * @param hash + * SHA256(SHA256()) hash of the object in internal byte order. * - * @see [[https://bitcoin.org/en/developer-reference#term-inventory]] + * @see + * [[https://bitcoin.org/en/developer-reference#term-inventory]] */ case class Inventory(typeIdentifier: TypeIdentifier, hash: DoubleSha256Digest) extends NetworkElement { @@ -19,7 +22,7 @@ case class Inventory(typeIdentifier: TypeIdentifier, hash: DoubleSha256Digest) override def toString: String = { typeIdentifier match { case TypeIdentifier.MsgTx | TypeIdentifier.MsgWitnessTx => - //want to make a better toString here so it is easier to search txids + // want to make a better toString here so it is easier to search txids s"Inventory($typeIdentifier,txIdBE=${hash.flip.hex})" case TypeIdentifier.MsgBlock | TypeIdentifier.MsgFilteredWitnessBlock | TypeIdentifier.MsgWitnessBlock => diff --git a/core/src/main/scala/org/bitcoins/core/p2p/NetworkHeader.scala b/core/src/main/scala/org/bitcoins/core/p2p/NetworkHeader.scala index 19a8b964a2..4e0ea32700 100644 --- a/core/src/main/scala/org/bitcoins/core/p2p/NetworkHeader.scala +++ b/core/src/main/scala/org/bitcoins/core/p2p/NetworkHeader.scala @@ -7,18 +7,24 @@ import org.bitcoins.crypto.{CryptoUtil, Factory, NetworkElement} import scodec.bits.ByteVector /** Represents a message header on the peer-to-peer network - * @see https://bitcoin.org/en/developer-reference#message-headers + * @see + * https://bitcoin.org/en/developer-reference#message-headers * - * @param network Each network has magic bytes indicating the originating network; - * used to seek to next message when stream state is unknown. - * @param commandName ASCII string which identifies what message type is contained in the payload. - * Followed by nulls (0x00) to pad out byte count; for example: version\0\0\0\0\0. - * @param payloadSize Number of bytes in payload. The current maximum number of bytes (MAX_SIZE) allowed in the payload - * by Bitcoin Core is 32 MiB—messages with a payload size larger than this will be dropped or rejected. - * @param checksum Added in protocol version 209. - * First 4 bytes of SHA256(SHA256(payload)) in internal byte order. - * If payload is empty, as in verack and getaddr messages, - * the checksum is always 0x5df6e0e2 (SHA256(SHA256(""))). + * @param network + * Each network has magic bytes indicating the originating network; used to + * seek to next message when stream state is unknown. + * @param commandName + * ASCII string which identifies what message type is contained in the + * payload. Followed by nulls (0x00) to pad out byte count; for example: + * version\0\0\0\0\0. + * @param payloadSize + * Number of bytes in payload. The current maximum number of bytes (MAX_SIZE) + * allowed in the payload by Bitcoin Core is 32 MiB—messages with a payload + * size larger than this will be dropped or rejected. + * @param checksum + * Added in protocol version 209. First 4 bytes of SHA256(SHA256(payload)) in + * internal byte order. If payload is empty, as in verack and getaddr + * messages, the checksum is always 0x5df6e0e2 (SHA256(SHA256(""))). */ case class NetworkHeader( network: NetworkParameters, @@ -26,8 +32,10 @@ case class NetworkHeader( payloadSize: UInt32, checksum: ByteVector ) extends NetworkElement { - require(bytes.length == NetworkHeader.bytesSize, - s"NetworkHeaders must be ${NetworkHeader.bytesSize} bytes") + require( + bytes.length == NetworkHeader.bytesSize, + s"NetworkHeaders must be ${NetworkHeader.bytesSize} bytes" + ) override def bytes: ByteVector = RawNetworkHeaderSerializer.write(this) @@ -40,17 +48,25 @@ object NetworkHeader extends Factory[NetworkHeader] { override def fromBytes(bytes: ByteVector): NetworkHeader = RawNetworkHeaderSerializer.read(bytes) - /** Creates a network header from it's [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] and [[NetworkPayload]] - * @param network the [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] object that indicates what network the payload needs to be sent on - * @param payload the payload object that needs to be sent on the network + /** Creates a network header from it's + * [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] and + * [[NetworkPayload]] + * @param network + * the [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] + * object that indicates what network the payload needs to be sent on + * @param payload + * the payload object that needs to be sent on the network */ def apply( network: NetworkParameters, - payload: NetworkPayload): NetworkHeader = { + payload: NetworkPayload + ): NetworkHeader = { val checksum = CryptoUtil.doubleSHA256(payload.bytes) - NetworkHeader(network, - payload.commandName, - UInt32(payload.bytes.size), - checksum.bytes.take(4)) + NetworkHeader( + network, + payload.commandName, + UInt32(payload.bytes.size), + checksum.bytes.take(4) + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/p2p/NetworkIpAddress.scala b/core/src/main/scala/org/bitcoins/core/p2p/NetworkIpAddress.scala index 71fd9efa6a..4c0c1176c5 100644 --- a/core/src/main/scala/org/bitcoins/core/p2p/NetworkIpAddress.scala +++ b/core/src/main/scala/org/bitcoins/core/p2p/NetworkIpAddress.scala @@ -6,16 +6,18 @@ import org.bitcoins.crypto.{Factory, NetworkElement} import scodec.bits._ /** Encapsulated network IP address currently uses the following structure - * @see https://bitcoin.org/en/developer-reference#addr + * @see + * https://bitcoin.org/en/developer-reference#addr */ sealed abstract class NetworkIpAddress extends NetworkElement { - /** Added in protocol version 31402. - * A time in Unix epoch time format. Nodes advertising their own IP address set this to the current time. - * Nodes advertising IP addresses they’ve connected to set this to the last time they connected to that node. - * Other nodes just relaying the IP address should not change the time. - * Nodes can use the time field to avoid relaying old addr messages. - * Malicious nodes may change times or even set them in the future. + /** Added in protocol version 31402. A time in Unix epoch time format. Nodes + * advertising their own IP address set this to the current time. Nodes + * advertising IP addresses they’ve connected to set this to the last time + * they connected to that node. Other nodes just relaying the IP address + * should not change the time. Nodes can use the time field to avoid relaying + * old addr messages. Malicious nodes may change times or even set them in + * the future. */ def time: UInt32 @@ -23,15 +25,15 @@ sealed abstract class NetworkIpAddress extends NetworkElement { */ def services: ServiceIdentifier - /** IPv6 address in big endian byte order. - * IPv4 addresses can be provided as IPv4-mapped IPv6 addresses + /** IPv6 address in big endian byte order. IPv4 addresses can be provided as + * IPv4-mapped IPv6 addresses */ def address: InetAddress - /** Port number in big endian byte order. - * Note that Bitcoin Core will only connect to nodes with non-standard port numbers as - * a last resort for finding peers. This is to prevent anyone from trying to use the - * network to disrupt non-Bitcoin services that run on other ports. + /** Port number in big endian byte order. Note that Bitcoin Core will only + * connect to nodes with non-standard port numbers as a last resort for + * finding peers. This is to prevent anyone from trying to use the network to + * disrupt non-Bitcoin services that run on other ports. */ def port: Int @@ -41,37 +43,40 @@ sealed abstract class NetworkIpAddress extends NetworkElement { object NetworkIpAddress extends Factory[NetworkIpAddress] { /** Writes an IP address to the representation that the p2p network requires. - * An IPv6 address is in big endian byte order. - * An IPv4 address has to be mapped to an IPv6 address. + * An IPv6 address is in big endian byte order. An IPv4 address has to be + * mapped to an IPv6 address. * - * @see https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses + * @see + * https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses */ def writeAddress(iNetAddress: InetAddress): ByteVector = { writeAddress(iNetAddress.getAddress) } /** Writes an IP address to the representation that the p2p network requires. - * An IPv6 address is in big endian byte order. - * An IPv4 address has to be mapped to an IPv6 address. + * An IPv6 address is in big endian byte order. An IPv4 address has to be + * mapped to an IPv6 address. * - * @see https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses + * @see + * https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses */ def writeAddress(bytes: Array[Byte]): ByteVector = { writeAddress(ByteVector(bytes)) } /** Writes an IP address to the representation that the p2p network requires. - * An IPv6 address is in big endian byte order. - * An IPv4 address has to be mapped to an IPv6 address. + * An IPv6 address is in big endian byte order. An IPv4 address has to be + * mapped to an IPv6 address. * - * @see https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses + * @see + * https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses */ def writeAddress(bytes: ByteVector): ByteVector = { if (bytes.size == 4) { - //this means we need to convert the IPv4 address to an IPv6 address - //first we have an 80 bit prefix of zeros + // this means we need to convert the IPv4 address to an IPv6 address + // first we have an 80 bit prefix of zeros val zeroBytes = ByteVector.fill(10)(0) - //the next 16 bits are ones + // the next 16 bits are ones val oneBytes = hex"ffff" val prefix: ByteVector = zeroBytes ++ oneBytes @@ -84,14 +89,15 @@ object NetworkIpAddress extends Factory[NetworkIpAddress] { time: UInt32, services: ServiceIdentifier, address: InetAddress, - port: Int) - extends NetworkIpAddress + port: Int + ) extends NetworkIpAddress def apply( time: UInt32, services: ServiceIdentifier, address: InetAddress, - port: Int): NetworkIpAddress = { + port: Int + ): NetworkIpAddress = { NetworkIpAddressImpl(time, services, address, port) } diff --git a/core/src/main/scala/org/bitcoins/core/p2p/NetworkMessage.scala b/core/src/main/scala/org/bitcoins/core/p2p/NetworkMessage.scala index f7482f903e..1b0d988015 100644 --- a/core/src/main/scala/org/bitcoins/core/p2p/NetworkMessage.scala +++ b/core/src/main/scala/org/bitcoins/core/p2p/NetworkMessage.scala @@ -24,15 +24,19 @@ object NetworkMessage extends Factory[NetworkMessage] { private case class NetworkMessageImpl( header: NetworkHeader, - payload: NetworkPayload) - extends NetworkMessage + payload: NetworkPayload + ) extends NetworkMessage def fromBytes(bytes: ByteVector): NetworkMessage = RawNetworkMessageSerializer.read(bytes) - /** Creates a network message from it's [[NetworkHeader]] and [[NetworkPayload]] - * @param header the [[NetworkHeader]] which is being sent across the network - * @param payload the [[NetworkPayload]] which contains the information being sent across the network + /** Creates a network message from it's [[NetworkHeader]] and + * [[NetworkPayload]] + * @param header + * the [[NetworkHeader]] which is being sent across the network + * @param payload + * the [[NetworkPayload]] which contains the information being sent across + * the network * @return */ def apply(header: NetworkHeader, payload: NetworkPayload): NetworkMessage = { @@ -40,13 +44,17 @@ object NetworkMessage extends Factory[NetworkMessage] { } /** Creates a [[NetworkMessage]] out of it's [[NetworkPayload]] - * @param network the [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] indicating the network which the message is going to be sent on - * @param payload the payload that needs to be sent across the network + * @param network + * the [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] + * indicating the network which the message is going to be sent on + * @param payload + * the payload that needs to be sent across the network * @return */ def apply( network: NetworkParameters, - payload: NetworkPayload): NetworkMessage = { + payload: NetworkPayload + ): NetworkMessage = { val header = NetworkHeader(network, payload) NetworkMessage(header, payload) } diff --git a/core/src/main/scala/org/bitcoins/core/p2p/NetworkPayload.scala b/core/src/main/scala/org/bitcoins/core/p2p/NetworkPayload.scala index 76a2dfce7a..20d7d0b75e 100644 --- a/core/src/main/scala/org/bitcoins/core/p2p/NetworkPayload.scala +++ b/core/src/main/scala/org/bitcoins/core/p2p/NetworkPayload.scala @@ -15,29 +15,33 @@ import org.bitcoins.crypto._ import scodec.bits.ByteVector /** Trait that represents a payload for a message on the Bitcoin p2p network - * @see [[https://bitcoin.org/en/developer-reference#p2p-network]] + * @see + * [[https://bitcoin.org/en/developer-reference#p2p-network]] */ sealed trait NetworkPayload extends NetworkElement { - /** ASCII string which identifies what message type is contained in the payload. - * Followed by nulls (0x00) to pad out byte count; for example: version\0\0\0\0\0. - * Command names need to be 12 bytes long - * This is generally used to build a [[org.bitcoins.core.p2p.NetworkHeader]] + /** ASCII string which identifies what message type is contained in the + * payload. Followed by nulls (0x00) to pad out byte count; for example: + * version\0\0\0\0\0. Command names need to be 12 bytes long This is + * generally used to build a [[org.bitcoins.core.p2p.NetworkHeader]] */ def commandName: String } /** Represents a data message inside of bitcoin core * - * @see [[https://bitcoin.org/en/developer-reference#data-messages]] + * @see + * [[https://bitcoin.org/en/developer-reference#data-messages]] */ sealed trait DataPayload extends NetworkPayload /** The block message transmits a single serialized block * - * @param block The block being transmitted inside of this message + * @param block + * The block being transmitted inside of this message * - * @see [[https://bitcoin.org/en/developer-reference#block]] + * @see + * [[https://bitcoin.org/en/developer-reference#block]] */ case class BlockMessage(block: Block) extends DataPayload { override val commandName = NetworkPayload.blockCommandName @@ -52,11 +56,12 @@ object BlockMessage extends Factory[BlockMessage] { } -/** The `getblocks` message requests an inv message that provides block header hashes - * starting from a particular point in the block chain. - * It allows a peer which has been disconnected or started for the first time to get the data - * it needs to request the blocks it hasn’t seen. - * @see [https://bitcoin.org/en/developer-reference#getblocks]] +/** The `getblocks` message requests an inv message that provides block header + * hashes starting from a particular point in the block chain. It allows a peer + * which has been disconnected or started for the first time to get the data it + * needs to request the blocks it hasn’t seen. + * @see + * [https://bitcoin.org/en/developer-reference#getblocks]] */ trait GetBlocksMessage extends DataPayload with ExpectsResponse { @@ -64,23 +69,24 @@ trait GetBlocksMessage extends DataPayload with ExpectsResponse { */ def protocolVersion: ProtocolVersion - /** The number of header hashes provided not including the stop hash. - * There is no limit except that the byte size of the entire message - * must be below the MAX_SIZE limit; typically from 1 to 200 hashes are sent. + /** The number of header hashes provided not including the stop hash. There is + * no limit except that the byte size of the entire message must be below the + * MAX_SIZE limit; typically from 1 to 200 hashes are sent. */ def hashCount: CompactSizeUInt /** One or more block header hashes (32 bytes each) in internal byte order. - * Hashes should be provided in reverse order of block height, - * so highest-height hashes are listed first and lowest-height hashes are listed last. + * Hashes should be provided in reverse order of block height, so + * highest-height hashes are listed first and lowest-height hashes are listed + * last. */ def blockHeaderHashes: Seq[DoubleSha256Digest] - /** The header hash of the last header hash being requested; - * set to all zeroes to request an inv message with all subsequent - * header hashes (a maximum of 500 will be sent as a reply to this message; - * if you need more than 500, you will need to send another getblocks message - * with a higher-height header hash as the first entry in block header hash field). + /** The header hash of the last header hash being requested; set to all zeroes + * to request an inv message with all subsequent header hashes (a maximum of + * 500 will be sent as a reply to this message; if you need more than 500, + * you will need to send another getblocks message with a higher-height + * header hash as the first entry in block header hash field). */ def stopHash: DoubleSha256Digest @@ -89,8 +95,10 @@ trait GetBlocksMessage extends DataPayload with ExpectsResponse { override def bytes: ByteVector = RawGetBlocksMessageSerializer.write(this) } -/** This is the companion object for the GetBlocks network message on the p2p network - * @see https://bitcoin.org/en/developer-reference#getblocks +/** This is the companion object for the GetBlocks network message on the p2p + * network + * @see + * https://bitcoin.org/en/developer-reference#getblocks */ object GetBlocksMessage extends Factory[GetBlocksMessage] { @@ -98,21 +106,23 @@ object GetBlocksMessage extends Factory[GetBlocksMessage] { protocolVersion: ProtocolVersion, hashCount: CompactSizeUInt, blockHeaderHashes: Seq[DoubleSha256Digest], - stopHash: DoubleSha256Digest) - extends GetBlocksMessage + stopHash: DoubleSha256Digest + ) extends GetBlocksMessage def apply( version: ProtocolVersion, hashCount: CompactSizeUInt, blockHeaderHashes: Seq[DoubleSha256Digest], - stopHash: DoubleSha256Digest): GetBlocksMessage = { + stopHash: DoubleSha256Digest + ): GetBlocksMessage = { GetBlocksMessageImpl(version, hashCount, blockHeaderHashes, stopHash) } def apply( version: ProtocolVersion, blockHeaderHashes: Seq[DoubleSha256Digest], - stopHash: DoubleSha256Digest): GetBlocksMessage = { + stopHash: DoubleSha256Digest + ): GetBlocksMessage = { val hashCount = CompactSizeUInt(UInt64(blockHeaderHashes.length)) GetBlocksMessage(version, hashCount, blockHeaderHashes, stopHash) } @@ -121,19 +131,22 @@ object GetBlocksMessage extends Factory[GetBlocksMessage] { RawGetBlocksMessageSerializer.read(bytes) } -/** The getdata message requests one or more data objects from another node. - * The objects are requested by an inventory, - * which the requesting node typically previously received by way of an inv message. +/** The getdata message requests one or more data objects from another node. The + * objects are requested by an inventory, which the requesting node typically + * previously received by way of an inv message. * - * @param inventoryCount The number of inventory enteries - * @param inventories One or more inventory entries up to a maximum of 50,000 entries. + * @param inventoryCount + * The number of inventory enteries + * @param inventories + * One or more inventory entries up to a maximum of 50,000 entries. * - * @see [[https://bitcoin.org/en/developer-reference#getdata]] + * @see + * [[https://bitcoin.org/en/developer-reference#getdata]] */ case class GetDataMessage( inventoryCount: CompactSizeUInt, - inventories: Seq[Inventory]) - extends DataPayload { + inventories: Seq[Inventory] +) extends DataPayload { override def commandName = NetworkPayload.getDataCommandName override def bytes: ByteVector = RawGetDataMessageSerializer.write(this) @@ -141,12 +154,10 @@ case class GetDataMessage( override def toString(): String = { val count = s"inventoryCount=${inventoryCount.toInt}" - val invs = s"inventories=${ - val base = inventories.toString + val invs = s"inventories=${val base = inventories.toString val cutoff = 100 if (base.length() > cutoff) base.take(cutoff) + "..." - else base - }" + else base}" s"GetDataMessage($count, $invs)" } } @@ -180,11 +191,12 @@ sealed trait ExpectsResponse { } } -/** The getheaders message requests a headers message that provides block headers starting - * from a particular point in the block chain. - * It allows a peer which has been disconnected or started for the first time to get the +/** The getheaders message requests a headers message that provides block + * headers starting from a particular point in the block chain. It allows a + * peer which has been disconnected or started for the first time to get the * headers it hasn’t seen yet. - * @see [[https://bitcoin.org/en/developer-reference#getheaders]] + * @see + * [[https://bitcoin.org/en/developer-reference#getheaders]] */ trait GetHeadersMessage extends DataPayload with ExpectsResponse { def version: ProtocolVersion @@ -214,8 +226,8 @@ object GetHeadersMessage extends Factory[GetHeadersMessage] { version: ProtocolVersion, hashCount: CompactSizeUInt, hashes: Seq[DoubleSha256Digest], - hashStop: DoubleSha256Digest) - extends GetHeadersMessage + hashStop: DoubleSha256Digest + ) extends GetHeadersMessage override def fromBytes(bytes: ByteVector): GetHeadersMessage = RawGetHeadersMessageSerializer.read(bytes) @@ -224,14 +236,16 @@ object GetHeadersMessage extends Factory[GetHeadersMessage] { version: ProtocolVersion, hashCount: CompactSizeUInt, hashes: Seq[DoubleSha256Digest], - hashStop: DoubleSha256Digest): GetHeadersMessage = { + hashStop: DoubleSha256Digest + ): GetHeadersMessage = { GetHeadersMessageImpl(version, hashCount, hashes, hashStop) } def apply( version: ProtocolVersion, hashes: Seq[DoubleSha256Digest], - hashStop: DoubleSha256Digest): GetHeadersMessage = { + hashStop: DoubleSha256Digest + ): GetHeadersMessage = { val hashCount = CompactSizeUInt(UInt64(hashes.length)) GetHeadersMessage(version, hashCount, hashes, hashStop) } @@ -239,18 +253,21 @@ object GetHeadersMessage extends Factory[GetHeadersMessage] { /** Creates a [[GetHeadersMessage]] with the default protocol version */ def apply( hashes: Seq[DoubleSha256Digest], - hashStop: DoubleSha256Digest): GetHeadersMessage = { + hashStop: DoubleSha256Digest + ): GetHeadersMessage = { GetHeadersMessage(ProtocolVersion.default, hashes, hashStop) } - /** Creates a [[GetHeadersMessage]] with no hash stop set, this requests all possible blocks - * if we need more than 2000 block headers, we will have to send another [[GetHeadersMessage]] + /** Creates a [[GetHeadersMessage]] with no hash stop set, this requests all + * possible blocks if we need more than 2000 block headers, we will have to + * send another [[GetHeadersMessage]] * - * @see [[https://bitcoin.org/en/developer-reference#getheaders]] + * @see + * [[https://bitcoin.org/en/developer-reference#getheaders]] */ def apply(hashes: Seq[DoubleSha256Digest]): GetHeadersMessage = { - //The header hash of the last header hash being requested; set to all zeroes to request an inv message with all - //subsequent header hashes (a maximum of 2000 will be sent as a reply to this message + // The header hash of the last header hash being requested; set to all zeroes to request an inv message with all + // subsequent header hashes (a maximum of 2000 will be sent as a reply to this message val hashStop = DoubleSha256Digest.empty GetHeadersMessage(hashes, hashStop) } @@ -260,18 +277,21 @@ object GetHeadersMessage extends Factory[GetHeadersMessage] { } } -/** The headers message sends one or more block headers to a node - * which previously requested certain headers with a getheaders message. - * @see [[https://bitcoin.org/en/developer-reference#headers]] +/** The headers message sends one or more block headers to a node which + * previously requested certain headers with a getheaders message. + * @see + * [[https://bitcoin.org/en/developer-reference#headers]] * - * @param count Number of block headers up to a maximum of 2,000. - * Note: headers-first sync assumes the sending node - * will send the maximum number of headers whenever possible. + * @param count + * Number of block headers up to a maximum of 2,000. Note: headers-first sync + * assumes the sending node will send the maximum number of headers whenever + * possible. * - * @param headers Block headers: each 80-byte block header is in the format described in the - * block headers section with an additional 0x00 suffixed. - * This 0x00 is called the transaction count, but because the headers message - * doesn’t include any transactions, the transaction count is always zero. + * @param headers + * Block headers: each 80-byte block header is in the format described in the + * block headers section with an additional 0x00 suffixed. This 0x00 is + * called the transaction count, but because the headers message doesn’t + * include any transactions, the transaction count is always zero. */ case class HeadersMessage(count: CompactSizeUInt, headers: Vector[BlockHeader]) extends DataPayload { @@ -294,8 +314,9 @@ object HeadersMessage extends Factory[HeadersMessage] { /** The maximum amount of headers sent in one `headers` message * - * @see [[https://bitcoin.org/en/developer-reference#getheaders bitcoin.org]] - * developer reference + * @see + * [[https://bitcoin.org/en/developer-reference#getheaders bitcoin.org]] + * developer reference */ val MaxHeadersCount: Int = 2000 @@ -309,10 +330,12 @@ object HeadersMessage extends Factory[HeadersMessage] { } } -/** The inv message (inventory message) transmits one or more inventories of objects known to the transmitting peer. - * It can be sent unsolicited to announce new transactions or blocks, - * or it can be sent in reply to a getblocks message or mempool message. - * @see [[https://bitcoin.org/en/developer-reference#inv]] +/** The inv message (inventory message) transmits one or more inventories of + * objects known to the transmitting peer. It can be sent unsolicited to + * announce new transactions or blocks, or it can be sent in reply to a + * getblocks message or mempool message. + * @see + * [[https://bitcoin.org/en/developer-reference#inv]] */ trait InventoryMessage extends DataPayload { @@ -348,26 +371,29 @@ trait InventoryMessage extends DataPayload { inventories.mkString } s"InventoryMessage($invCount inv(s)${if (invList.nonEmpty) ", " + invList - else ""})" + else ""})" } } -/** Creates an scala object that represents the inventory type on the p2p network - * @see https://bitcoin.org/en/developer-reference#inv +/** Creates an scala object that represents the inventory type on the p2p + * network + * @see + * https://bitcoin.org/en/developer-reference#inv */ object InventoryMessage extends Factory[InventoryMessage] { private case class InventoryMessageImpl( inventoryCount: CompactSizeUInt, - inventories: Seq[Inventory]) - extends InventoryMessage + inventories: Seq[Inventory] + ) extends InventoryMessage override def fromBytes(bytes: ByteVector): InventoryMessage = RawInventoryMessageSerializer.read(bytes) def apply( inventoryCount: CompactSizeUInt, - inventories: Seq[Inventory]): InventoryMessage = { + inventories: Seq[Inventory] + ): InventoryMessage = { InventoryMessageImpl(inventoryCount, inventories) } @@ -377,12 +403,14 @@ object InventoryMessage extends Factory[InventoryMessage] { } } -/** The mempool message requests the TXIDs of transactions that the receiving node has verified - * as valid but which have not yet appeared in a block. - * That is, transactions which are in the receiving node’s memory pool. - * The response to the mempool message is one or more inv messages containing the TXIDs in the usual inventory format. +/** The mempool message requests the TXIDs of transactions that the receiving + * node has verified as valid but which have not yet appeared in a block. That + * is, transactions which are in the receiving node’s memory pool. The response + * to the mempool message is one or more inv messages containing the TXIDs in + * the usual inventory format. * - * @see [[https://bitcoin.org/en/developer-reference#mempool]] + * @see + * [[https://bitcoin.org/en/developer-reference#mempool]] */ case object MemPoolMessage extends DataPayload { override val commandName = NetworkPayload.memPoolCommandName @@ -390,13 +418,17 @@ case object MemPoolMessage extends DataPayload { } /** The merkleblock message is a reply to a getdata message which requested a - * block using the inventory type MSG_MERKLEBLOCK. - * It is only part of the reply: if any matching transactions are found, - * they will be sent separately as tx messages. + * block using the inventory type MSG_MERKLEBLOCK. It is only part of the + * reply: if any matching transactions are found, they will be sent separately + * as tx messages. * - * @see [[https://bitcoin.org/en/developer-reference#merkleblock]] + * @see + * [[https://bitcoin.org/en/developer-reference#merkleblock]] * - * @param merkleBlock The actual [[org.bitcoins.core.protocol.blockchain.MerkleBlock MerkleBlock]] that this message represents + * @param merkleBlock + * The actual + * [[org.bitcoins.core.protocol.blockchain.MerkleBlock MerkleBlock]] that + * this message represents */ case class MerkleBlockMessage(merkleBlock: MerkleBlock) extends DataPayload { @@ -406,7 +438,8 @@ case class MerkleBlockMessage(merkleBlock: MerkleBlock) extends DataPayload { } -/** @see https://bitcoin.org/en/developer-reference#merkleblock +/** @see + * https://bitcoin.org/en/developer-reference#merkleblock */ object MerkleBlockMessage extends Factory[MerkleBlockMessage] { @@ -415,28 +448,32 @@ object MerkleBlockMessage extends Factory[MerkleBlockMessage] { } -/** The notfound message is a reply to a getdata message which requested an object the receiving - * node does not have available for relay. (Nodes are not expected to relay historic transactions - * which are no longer in the memory pool or relay set. - * Nodes may also have pruned spent transactions from older blocks, making them unable to send those blocks.) +/** The notfound message is a reply to a getdata message which requested an + * object the receiving node does not have available for relay. (Nodes are not + * expected to relay historic transactions which are no longer in the memory + * pool or relay set. Nodes may also have pruned spent transactions from older + * blocks, making them unable to send those blocks.) * - * @see [[https://bitcoin.org/en/developer-reference#notfound]] + * @see + * [[https://bitcoin.org/en/developer-reference#notfound]] */ trait NotFoundMessage extends DataPayload with InventoryMessage { override def commandName = NetworkPayload.notFoundCommandName override def bytes: ByteVector = RawNotFoundMessageSerializer.write(this) } -/** The companion object factory used to create NotFoundMessages on the p2p network +/** The companion object factory used to create NotFoundMessages on the p2p + * network * - * @see https://bitcoin.org/en/developer-reference#notfound + * @see + * https://bitcoin.org/en/developer-reference#notfound */ object NotFoundMessage extends Factory[NotFoundMessage] { private case class NotFoundMessageImpl( inventoryCount: CompactSizeUInt, - inventories: Seq[Inventory]) - extends NotFoundMessage + inventories: Seq[Inventory] + ) extends NotFoundMessage def fromBytes(bytes: ByteVector): NotFoundMessage = RawNotFoundMessageSerializer.read(bytes) @@ -448,15 +485,18 @@ object NotFoundMessage extends Factory[NotFoundMessage] { def apply( inventoryCount: CompactSizeUInt, - inventories: Seq[Inventory]): NotFoundMessage = { + inventories: Seq[Inventory] + ): NotFoundMessage = { NotFoundMessageImpl(inventoryCount, inventories) } } /** The tx message transmits a single transaction in the raw transaction format. * It can be sent in a variety of situations; - * @param transaction The transaction being sent over the wire - * @see [[https://bitcoin.org/en/developer-reference#tx]] + * @param transaction + * The transaction being sent over the wire + * @see + * [[https://bitcoin.org/en/developer-reference#tx]] */ case class TransactionMessage(transaction: Transaction) extends DataPayload { @@ -467,7 +507,8 @@ case class TransactionMessage(transaction: Transaction) extends DataPayload { } /** Companion factory object for the TransactionMessage on the p2p network - * @see https://bitcoin.org/en/developer-reference#tx + * @see + * https://bitcoin.org/en/developer-reference#tx */ object TransactionMessage extends Factory[TransactionMessage] { @@ -482,13 +523,15 @@ sealed trait ControlPayload extends NetworkPayload sealed trait GossipAddrMessage extends ControlPayload -/** The addr (IP address) message relays connection information for peers on the network. - * Each peer which wants to accept incoming connections creates an addr message providing its - * connection information and then sends that message to its peers unsolicited. - * Some of its peers send that information to their peers (also unsolicited), - * some of which further distribute it, allowing decentralized peer discovery for - * any program already on the network. - * @see [[https://bitcoin.org/en/developer-reference#addr]] +/** The addr (IP address) message relays connection information for peers on the + * network. Each peer which wants to accept incoming connections creates an + * addr message providing its connection information and then sends that + * message to its peers unsolicited. Some of its peers send that information to + * their peers (also unsolicited), some of which further distribute it, + * allowing decentralized peer discovery for any program already on the + * network. + * @see + * [[https://bitcoin.org/en/developer-reference#addr]] */ trait AddrMessage extends GossipAddrMessage { def ipCount: CompactSizeUInt @@ -498,14 +541,15 @@ trait AddrMessage extends GossipAddrMessage { } /** The companion object for an AddrMessage - * @see https://bitcoin.org/en/developer-reference#addr + * @see + * https://bitcoin.org/en/developer-reference#addr */ object AddrMessage extends Factory[AddrMessage] { private case class AddrMessageImpl( ipCount: CompactSizeUInt, - addresses: Seq[NetworkIpAddress]) - extends AddrMessage + addresses: Seq[NetworkIpAddress] + ) extends AddrMessage def fromBytes(bytes: ByteVector): AddrMessage = RawAddrMessageSerializer.read(bytes) @@ -517,15 +561,17 @@ object AddrMessage extends Factory[AddrMessage] { def apply( ipCount: CompactSizeUInt, - addresses: Seq[NetworkIpAddress]): AddrMessage = + addresses: Seq[NetworkIpAddress] + ): AddrMessage = AddrMessageImpl(ipCount, addresses) } -/** addrV2 relays information about a peer. It supports many different - * address types and networks. +/** addrV2 relays information about a peer. It supports many different address + * types and networks. * - * @see https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki */ sealed trait AddrV2Message extends GossipAddrMessage { def time: UInt32 @@ -538,7 +584,8 @@ sealed trait AddrV2Message extends GossipAddrMessage { override def bytes: ByteVector = time.bytes ++ services.bytes ++ ByteVector.fromByte( - networkId) ++ addrBytes ++ port.bytes + networkId + ) ++ addrBytes ++ port.bytes } /** addrv2 message that contains an IPv4 address */ @@ -546,14 +593,16 @@ case class IPv4AddrV2Message( time: UInt32, services: CompactSizeUInt, addr: InetAddress, - port: UInt16) - extends AddrV2Message { + port: UInt16 +) extends AddrV2Message { override val networkId: Byte = AddrV2Message.IPV4_NETWORK_BYTE override val addrBytes: ByteVector = addr.ipv4Bytes - require(addrBytes.size == AddrV2Message.IPV4_ADDR_LENGTH, - "Incorrect size of IPv4 message, consider using IPv6AddrV2Message") + require( + addrBytes.size == AddrV2Message.IPV4_ADDR_LENGTH, + "Incorrect size of IPv4 message, consider using IPv6AddrV2Message" + ) } /** addrv2 message that contains an IPv6 address */ @@ -561,14 +610,16 @@ case class IPv6AddrV2Message( time: UInt32, services: CompactSizeUInt, addr: InetAddress, - port: UInt16) - extends AddrV2Message { + port: UInt16 +) extends AddrV2Message { override val networkId: Byte = AddrV2Message.IPV6_NETWORK_BYTE override val addrBytes: ByteVector = ByteVector(addr.getAddress) - require(addrBytes.size == AddrV2Message.IPV6_ADDR_LENGTH, - "Incorrect size of IPv6 message, consider using IPv4AddrV2Message") + require( + addrBytes.size == AddrV2Message.IPV6_ADDR_LENGTH, + "Incorrect size of IPv6 message, consider using IPv4AddrV2Message" + ) } /** addrv2 message that contains a TorV2 address */ @@ -576,11 +627,12 @@ case class TorV2AddrV2Message( time: UInt32, services: CompactSizeUInt, addrBytes: ByteVector, - port: UInt16) - extends AddrV2Message { + port: UInt16 +) extends AddrV2Message { require( addrBytes.size == AddrV2Message.TOR_V2_ADDR_LENGTH, - s"TorV2 addresses are ${AddrV2Message.TOR_V2_ADDR_LENGTH} bytes, got ${addrBytes.size}") + s"TorV2 addresses are ${AddrV2Message.TOR_V2_ADDR_LENGTH} bytes, got ${addrBytes.size}" + ) override val networkId: Byte = AddrV2Message.TOR_V2_NETWORK_BYTE } @@ -589,11 +641,12 @@ case class TorV3AddrV2Message( time: UInt32, services: CompactSizeUInt, addrBytes: ByteVector, - port: UInt16) - extends AddrV2Message { + port: UInt16 +) extends AddrV2Message { require( addrBytes.size == AddrV2Message.TOR_V3_ADDR_LENGTH, - s"TorV3 addresses are ${AddrV2Message.TOR_V3_ADDR_LENGTH} bytes, got ${addrBytes.size}") + s"TorV3 addresses are ${AddrV2Message.TOR_V3_ADDR_LENGTH} bytes, got ${addrBytes.size}" + ) override val networkId: Byte = AddrV2Message.TOR_V3_NETWORK_BYTE } @@ -602,11 +655,12 @@ case class I2PAddrV2Message( time: UInt32, services: CompactSizeUInt, addrBytes: ByteVector, - port: UInt16) - extends AddrV2Message { + port: UInt16 +) extends AddrV2Message { require( addrBytes.size == AddrV2Message.I2P_ADDR_LENGTH, - s"I2P addresses are ${AddrV2Message.I2P_ADDR_LENGTH} bytes, got ${addrBytes.size}") + s"I2P addresses are ${AddrV2Message.I2P_ADDR_LENGTH} bytes, got ${addrBytes.size}" + ) override val networkId: Byte = AddrV2Message.I2P_NETWORK_BYTE } @@ -615,31 +669,39 @@ case class CJDNSAddrV2Message( time: UInt32, services: CompactSizeUInt, addrBytes: ByteVector, - port: UInt16) - extends AddrV2Message { - require(addrBytes.head == 0xfc.toByte, - s"CJDNS addresses start with 0xFC, got $addrBytes") + port: UInt16 +) extends AddrV2Message { + require( + addrBytes.head == 0xfc.toByte, + s"CJDNS addresses start with 0xFC, got $addrBytes" + ) require( addrBytes.size == AddrV2Message.CJDNS_ADDR_LENGTH, - s"CJDNS addresses are ${AddrV2Message.CJDNS_ADDR_LENGTH} bytes, got ${addrBytes.size}") + s"CJDNS addresses are ${AddrV2Message.CJDNS_ADDR_LENGTH} bytes, got ${addrBytes.size}" + ) override val networkId: Byte = AddrV2Message.CJDNS_NETWORK_BYTE } -/** addrv2 message that contains an address from a network we do not understand */ +/** addrv2 message that contains an address from a network we do not understand + */ case class UnknownNetworkAddrV2Message( time: UInt32, services: CompactSizeUInt, networkId: Byte, addrBytes: ByteVector, - port: UInt16) - extends AddrV2Message { - require(!AddrV2Message.knownNetworkBytes.contains(networkId), - s"$networkId is a known network byte") + port: UInt16 +) extends AddrV2Message { + require( + !AddrV2Message.knownNetworkBytes.contains(networkId), + s"$networkId is a known network byte" + ) } /** The companion object for an AddrV2Message - * @see https://developer.bitcoin.org/reference/p2p_networking.html#addrv2 - * @see https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki + * @see + * https://developer.bitcoin.org/reference/p2p_networking.html#addrv2 + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki */ object AddrV2Message extends Factory[AddrV2Message] { @@ -661,12 +723,14 @@ object AddrV2Message extends Factory[AddrV2Message] { final val CJDNS_NETWORK_BYTE: Byte = 0x06 final val CJDNS_ADDR_LENGTH: Int = 16 - val knownNetworkBytes: Vector[Byte] = Vector(IPV4_NETWORK_BYTE, - IPV6_NETWORK_BYTE, - TOR_V2_NETWORK_BYTE, - TOR_V3_NETWORK_BYTE, - I2P_NETWORK_BYTE, - CJDNS_NETWORK_BYTE) + val knownNetworkBytes: Vector[Byte] = Vector( + IPV4_NETWORK_BYTE, + IPV6_NETWORK_BYTE, + TOR_V2_NETWORK_BYTE, + TOR_V3_NETWORK_BYTE, + I2P_NETWORK_BYTE, + CJDNS_NETWORK_BYTE + ) override def fromBytes(bytes: ByteVector): AddrV2Message = { val timeBytes = bytes.take(4) @@ -716,32 +780,37 @@ object AddrV2Message extends Factory[AddrV2Message] { } } -/** Sending such a message indicates that a node can understand and - * prefers to receive addrv2 messages instead of addr messages. - * I.e. "Send me addrv2".sendaddrv2 SHOULD be sent after receiving the verack message from the peer. - * For older peers, that did not emit sendaddrv2, keep sending the legacy - * addr message, ignoring addresses with the newly introduced address types. - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki#signaling-support-and-compatibility]] +/** Sending such a message indicates that a node can understand and prefers to + * receive addrv2 messages instead of addr messages. I.e. "Send me + * addrv2".sendaddrv2 SHOULD be sent after receiving the verack message from + * the peer. For older peers, that did not emit sendaddrv2, keep sending the + * legacy addr message, ignoring addresses with the newly introduced address + * types. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki#signaling-support-and-compatibility]] */ case object SendAddrV2Message extends ControlPayload { override val commandName: String = NetworkPayload.sendAddrV2CommandName override val bytes: ByteVector = ByteVector.empty } -/** The feefilter message is a request to the receiving peer to not relay any transaction inv messages - * to the sending peer where the fee rate for the transaction is below the fee rate specified in the - * feefilter message. +/** The feefilter message is a request to the receiving peer to not relay any + * transaction inv messages to the sending peer where the fee rate for the + * transaction is below the fee rate specified in the feefilter message. * - * feefilter was introduced in Bitcoin Core 0.13.0 following the introduction of mempool limiting in - * Bitcoin Core 0.12.0. Mempool limiting provides protection against attacks and spam transactions - * that have low fee rates and are unlikely to be included in mined blocks. The feefilter messages - * allows a node to inform its peers that it will not accept transactions below a specified fee rate - * into its mempool, and therefore that the peers can skip relaying inv messages for transactions below - * that fee rate to that node. + * feefilter was introduced in Bitcoin Core 0.13.0 following the introduction + * of mempool limiting in Bitcoin Core 0.12.0. Mempool limiting provides + * protection against attacks and spam transactions that have low fee rates and + * are unlikely to be included in mined blocks. The feefilter messages allows a + * node to inform its peers that it will not accept transactions below a + * specified fee rate into its mempool, and therefore that the peers can skip + * relaying inv messages for transactions below that fee rate to that node. */ trait FeeFilterMessage extends ControlPayload { - /** The raw fee rate, in satoshis per kb. This is what is defined in the p2p message */ + /** The raw fee rate, in satoshis per kb. This is what is defined in the p2p + * message + */ def feeRate: SatoshisPerKiloByte def satPerByte: SatoshisPerByte = { @@ -774,10 +843,11 @@ object FeeFilterMessage extends Factory[FeeFilterMessage] { } /** The filteradd message tells the receiving peer to add a single element to a - * previously-set bloom filter, such as a new public key. - * The element is sent directly to the receiving peer; the peer then uses the parameters - * set in the filterload message to add the element to the bloom filter. - * @see [[https://bitcoin.org/en/developer-reference#filteradd]] + * previously-set bloom filter, such as a new public key. The element is sent + * directly to the receiving peer; the peer then uses the parameters set in the + * filterload message to add the element to the bloom filter. + * @see + * [[https://bitcoin.org/en/developer-reference#filteradd]] */ trait FilterAddMessage extends ControlPayload { @@ -785,11 +855,11 @@ trait FilterAddMessage extends ControlPayload { */ def elementSize: CompactSizeUInt - /** The element to add to the current filter. - * Maximum of 520 bytes, which is the maximum size of an element which can be pushed - * onto the stack in a pubkey or signature script. - * Elements must be sent in the byte order they would use when appearing in a raw transaction; - * for example, hashes should be sent in internal byte order. + /** The element to add to the current filter. Maximum of 520 bytes, which is + * the maximum size of an element which can be pushed onto the stack in a + * pubkey or signature script. Elements must be sent in the byte order they + * would use when appearing in a raw transaction; for example, hashes should + * be sent in internal byte order. */ def element: ByteVector @@ -798,21 +868,23 @@ trait FilterAddMessage extends ControlPayload { override def bytes: ByteVector = RawFilterAddMessageSerializer.write(this) } -/** @see [[https://bitcoin.org/en/developer-reference#filteradd]] +/** @see + * [[https://bitcoin.org/en/developer-reference#filteradd]] */ object FilterAddMessage extends Factory[FilterAddMessage] { private case class FilterAddMessageImpl( elementSize: CompactSizeUInt, - element: ByteVector) - extends FilterAddMessage + element: ByteVector + ) extends FilterAddMessage override def fromBytes(bytes: ByteVector): FilterAddMessage = RawFilterAddMessageSerializer.read(bytes) def apply( elementSize: CompactSizeUInt, - element: ByteVector): FilterAddMessage = { + element: ByteVector + ): FilterAddMessage = { FilterAddMessageImpl(elementSize, element) } @@ -823,21 +895,25 @@ object FilterAddMessage extends Factory[FilterAddMessage] { } -/** The filterclear message tells the receiving peer to remove a previously-set bloom filter. - * This also undoes the effect of setting the relay field in the version message to 0, - * allowing unfiltered access to inv messages announcing new transactions. - * @see [[https://bitcoin.org/en/developer-reference#filterclear]] +/** The filterclear message tells the receiving peer to remove a previously-set + * bloom filter. This also undoes the effect of setting the relay field in the + * version message to 0, allowing unfiltered access to inv messages announcing + * new transactions. + * @see + * [[https://bitcoin.org/en/developer-reference#filterclear]] */ case object FilterClearMessage extends ControlPayload { override val commandName = NetworkPayload.filterClearCommandName override val bytes: ByteVector = ByteVector.empty } -/** The filterload message tells the receiving peer to filter all relayed transactions and - * requested merkle blocks through the provided filter. - * This allows clients to receive transactions relevant to their wallet plus a configurable - * rate of false positive transactions which can provide plausible-deniability privacy. - * @see [[https://bitcoin.org/en/developer-reference#filterload]] +/** The filterload message tells the receiving peer to filter all relayed + * transactions and requested merkle blocks through the provided filter. This + * allows clients to receive transactions relevant to their wallet plus a + * configurable rate of false positive transactions which can provide + * plausible-deniability privacy. + * @see + * [[https://bitcoin.org/en/developer-reference#filterload]] */ trait FilterLoadMessage extends ControlPayload { @@ -849,7 +925,8 @@ trait FilterLoadMessage extends ControlPayload { override def bytes: ByteVector = RawFilterLoadMessageSerializer.write(this) } -/** @see [[https://bitcoin.org/en/developer-reference#filterload]] +/** @see + * [[https://bitcoin.org/en/developer-reference#filterload]] */ object FilterLoadMessage extends Factory[FilterLoadMessage] { @@ -857,10 +934,12 @@ object FilterLoadMessage extends Factory[FilterLoadMessage] { extends FilterLoadMessage { require( bloomFilter.filterSize.num.toLong <= BloomFilter.maxSize.toLong, - "Can only have a maximum of 36,000 bytes in our filter, got: " + bloomFilter.data.size) + "Can only have a maximum of 36,000 bytes in our filter, got: " + bloomFilter.data.size + ) require( bloomFilter.hashFuncs <= BloomFilter.maxHashFuncs, - "Can only have a maximum of 50 hashFuncs inside FilterLoadMessage, got: " + bloomFilter.hashFuncs) + "Can only have a maximum of 50 hashFuncs inside FilterLoadMessage, got: " + bloomFilter.hashFuncs + ) require( bloomFilter.filterSize.num.toLong == bloomFilter.data.size, "Filter Size compactSizeUInt and actual filter size were different, " + @@ -876,7 +955,8 @@ object FilterLoadMessage extends Factory[FilterLoadMessage] { filter: ByteVector, hashFuncs: UInt32, tweak: UInt32, - flags: BloomFlag): FilterLoadMessage = { + flags: BloomFlag + ): FilterLoadMessage = { val bloomFilter = BloomFilter(filterSize, filter, hashFuncs, tweak, flags) FilterLoadMessage(bloomFilter) } @@ -885,7 +965,8 @@ object FilterLoadMessage extends Factory[FilterLoadMessage] { filter: ByteVector, hashFuncs: UInt32, tweak: UInt32, - flags: BloomFlag): FilterLoadMessage = { + flags: BloomFlag + ): FilterLoadMessage = { val filterSize = CompactSizeUInt(UInt64(filter.length)) FilterLoadMessage(filterSize, filter, hashFuncs, tweak, flags) } @@ -896,10 +977,12 @@ object FilterLoadMessage extends Factory[FilterLoadMessage] { } /** The getaddr message requests an addr message from the receiving node, - * preferably one with lots of IP addresses of other receiving nodes. - * The transmitting node can use those IP addresses to quickly update its - * database of available nodes rather than waiting for unsolicited addr messages to arrive over time. - * @see [[https://bitcoin.org/en/developer-reference#getaddr]] + * preferably one with lots of IP addresses of other receiving nodes. The + * transmitting node can use those IP addresses to quickly update its database + * of available nodes rather than waiting for unsolicited addr messages to + * arrive over time. + * @see + * [[https://bitcoin.org/en/developer-reference#getaddr]] */ case object GetAddrMessage extends ControlPayload { override val commandName = NetworkPayload.getAddrCommandName @@ -907,16 +990,17 @@ case object GetAddrMessage extends ControlPayload { } /** The ping message helps confirm that the receiving peer is still connected. - * If a TCP/IP error is encountered when sending the ping message (such as a connection timeout), - * the transmitting node can assume that the receiving node is disconnected. - * The response to a ping message is the pong message. - * @see [[https://bitcoin.org/en/developer-reference#ping]] + * If a TCP/IP error is encountered when sending the ping message (such as a + * connection timeout), the transmitting node can assume that the receiving + * node is disconnected. The response to a ping message is the pong message. + * @see + * [[https://bitcoin.org/en/developer-reference#ping]] */ trait PingMessage extends ControlPayload { - /** Random nonce assigned to this ping message. - * The responding pong message will include this nonce - * to identify the ping message to which it is replying. + /** Random nonce assigned to this ping message. The responding pong message + * will include this nonce to identify the ping message to which it is + * replying. */ def nonce: UInt64 @@ -936,14 +1020,17 @@ object PingMessage extends Factory[PingMessage] { def apply(nonce: UInt64): PingMessage = PingMessageImpl(nonce) } -/** The pong message replies to a ping message, proving to the pinging node that the ponging node is still alive. - * Bitcoin Core will, by default, disconnect from any clients which have not responded - * to a ping message within 20 minutes. - * @see [[https://bitcoin.org/en/developer-reference#pong]] +/** The pong message replies to a ping message, proving to the pinging node that + * the ponging node is still alive. Bitcoin Core will, by default, disconnect + * from any clients which have not responded to a ping message within 20 + * minutes. + * @see + * [[https://bitcoin.org/en/developer-reference#pong]] */ trait PongMessage extends ControlPayload { - /** The nonce which is the nonce in the ping message the peer is responding too + /** The nonce which is the nonce in the ping message the peer is responding + * too */ def nonce: UInt64 @@ -966,8 +1053,10 @@ object PongMessage extends Factory[PongMessage] { def apply(nonce: UInt64): PongMessage = PongMessageImpl(nonce) } -/** The reject message informs the receiving node that one of its previous messages has been rejected. - * @see [[https://bitcoin.org/en/developer-reference#reject]] +/** The reject message informs the receiving node that one of its previous + * messages has been rejected. + * @see + * [[https://bitcoin.org/en/developer-reference#reject]] */ trait RejectMessage extends ControlPayload { @@ -975,8 +1064,8 @@ trait RejectMessage extends ControlPayload { */ def messageSize: CompactSizeUInt - /** The type of message rejected as ASCII text without null padding. - * For example: “tx”, “block”, or “version”. + /** The type of message rejected as ASCII text without null padding. For + * example: “tx”, “block”, or “version”. */ def message: String @@ -984,19 +1073,19 @@ trait RejectMessage extends ControlPayload { */ def code: Char - /** The number of bytes in the following reason field. - * May be 0x00 if a text reason isn’t provided. + /** The number of bytes in the following reason field. May be 0x00 if a text + * reason isn’t provided. */ def reasonSize: CompactSizeUInt - /** The reason for the rejection in ASCII text. - * This should not be displayed to the user; it is only for debugging purposes. + /** The reason for the rejection in ASCII text. This should not be displayed + * to the user; it is only for debugging purposes. */ def reason: String - /** Optional additional data provided with the rejection. - * For example, most rejections of tx messages or block messages include - * the hash of the rejected transaction or block header. See the code table below. + /** Optional additional data provided with the rejection. For example, most + * rejections of tx messages or block messages include the hash of the + * rejected transaction or block header. See the code table below. */ def extra: ByteVector @@ -1005,7 +1094,8 @@ trait RejectMessage extends ControlPayload { override def bytes: ByteVector = RawRejectMessageSerializer.write(this) } -/** @see [[https://bitcoin.org/en/developer-reference#reject]] +/** @see + * [[https://bitcoin.org/en/developer-reference#reject]] */ object RejectMessage extends Factory[RejectMessage] { @@ -1015,8 +1105,8 @@ object RejectMessage extends Factory[RejectMessage] { code: Char, reasonSize: CompactSizeUInt, reason: String, - extra: ByteVector) - extends RejectMessage + extra: ByteVector + ) extends RejectMessage def apply( messageSize: CompactSizeUInt, @@ -1024,7 +1114,8 @@ object RejectMessage extends Factory[RejectMessage] { code: Char, reasonSize: CompactSizeUInt, reason: String, - extra: ByteVector): RejectMessage = { + extra: ByteVector + ): RejectMessage = { RejectMessageImpl(messageSize, message, code, reasonSize, reason, extra) } @@ -1035,18 +1126,20 @@ object RejectMessage extends Factory[RejectMessage] { message: String, code: Char, reason: String, - extra: ByteVector): RejectMessage = { + extra: ByteVector + ): RejectMessage = { val messageSize: CompactSizeUInt = CompactSizeUInt(UInt64(message.size)) val reasonSize: CompactSizeUInt = CompactSizeUInt(UInt64(reason.size)) RejectMessage(messageSize, message, code, reasonSize, reason, extra) } } -/** The sendheaders message tells the receiving peer to send new block announcements - * using a headers message rather than an inv message. - * There is no payload in a sendheaders message. See the message header section for an example - * of a message without a payload. - * @see [[https://bitcoin.org/en/developer-reference#sendheaders]] +/** The sendheaders message tells the receiving peer to send new block + * announcements using a headers message rather than an inv message. There is + * no payload in a sendheaders message. See the message header section for an + * example of a message without a payload. + * @see + * [[https://bitcoin.org/en/developer-reference#sendheaders]] */ case object SendHeadersMessage extends ControlPayload { override def commandName = NetworkPayload.sendHeadersCommandName @@ -1054,23 +1147,25 @@ case object SendHeadersMessage extends ControlPayload { } /** The verack message acknowledges a previously-received version message, - * informing the connecting node that it can begin to send other messages. - * The verack message has no payload; for an example of a message with no payload, + * informing the connecting node that it can begin to send other messages. The + * verack message has no payload; for an example of a message with no payload, * see the message headers section. - * @see [[https://bitcoin.org/en/developer-reference#verack]] + * @see + * [[https://bitcoin.org/en/developer-reference#verack]] */ case object VerAckMessage extends ControlPayload { override val commandName = NetworkPayload.verAckCommandName override val bytes: ByteVector = ByteVector.empty } -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfilters BIP157]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfilters BIP157]] */ case class GetCompactFiltersMessage( filterType: FilterType, startHeight: UInt32, - stopHash: DoubleSha256Digest) - extends DataPayload + stopHash: DoubleSha256Digest +) extends DataPayload with ExpectsResponse { val commandName: String = NetworkPayload.getCompactFiltersCommandName @@ -1088,12 +1183,15 @@ object GetCompactFiltersMessage extends Factory[GetCompactFiltersMessage] { /** Constructs a message with the default basic filter type */ def apply(startHeight: Int, stopHash: DoubleSha256Digest) = - new GetCompactFiltersMessage(FilterType.Basic, - UInt32(startHeight), - stopHash) + new GetCompactFiltersMessage( + FilterType.Basic, + UInt32(startHeight), + stopHash + ) } -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfilter BIP157]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfilter BIP157]] */ case class CompactFilterMessage( filterType: FilterType, @@ -1105,7 +1203,8 @@ case class CompactFilterMessage( /** The number of filter bytes in this message */ val numFilterBytes: CompactSizeUInt = CompactSizeUInt( - UInt64(filterBytes.length)) + UInt64(filterBytes.length) + ) val commandName: String = NetworkPayload.compactFilterCommandName def bytes: ByteVector = RawCompactFilterMessageSerializer.write(this) @@ -1120,7 +1219,8 @@ object CompactFilterMessage extends Factory[CompactFilterMessage] { /** Constructs a message from the tiven blockhash and filter */ def apply( blockHash: DoubleSha256Digest, - filter: GolombFilter): CompactFilterMessage = { + filter: GolombFilter + ): CompactFilterMessage = { val filterBytes = filter.bytes new CompactFilterMessage(FilterType.Basic, blockHash, filterBytes) } @@ -1130,9 +1230,11 @@ object CompactFilterMessage extends Factory[CompactFilterMessage] { } -/** `getcfheaders` is used to request verifiable filter headers for a range of blocks +/** `getcfheaders` is used to request verifiable filter headers for a range of + * blocks * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfheaders BIP157]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfheaders BIP157]] */ case class GetCompactFilterHeadersMessage( filterType: FilterType, @@ -1153,39 +1255,43 @@ object GetCompactFilterHeadersMessage def apply( startHeight: Int, stopHash: DoubleSha256Digest, - filterType: FilterType = - FilterType.Basic): GetCompactFilterHeadersMessage = { - new GetCompactFilterHeadersMessage(filterType, - UInt32(startHeight), - stopHash) + filterType: FilterType = FilterType.Basic + ): GetCompactFilterHeadersMessage = { + new GetCompactFilterHeadersMessage( + filterType, + UInt32(startHeight), + stopHash + ) } def fromBytes(bytes: ByteVector): GetCompactFilterHeadersMessage = RawGetCompactFilterHeadersMessageSerializer.read(bytes) } -/** `cfheaders` is sent in response to `getcfheaders`. Instead of including - * the filter headers themselves, the response includes one filter header - * and a sequence of filter hashes, from which the headers can be derived. - * This has the benefit that the client can verify the binding links - * between the headers. +/** `cfheaders` is sent in response to `getcfheaders`. Instead of including the + * filter headers themselves, the response includes one filter header and a + * sequence of filter hashes, from which the headers can be derived. This has + * the benefit that the client can verify the binding links between the + * headers. * * TODO: doc on params * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfheaders BIP157]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfheaders BIP157]] */ case class CompactFilterHeadersMessage( filterType: FilterType, stopHash: DoubleSha256Digest, previousFilterHeader: DoubleSha256Digest, - filterHashes: Vector[DoubleSha256Digest]) - extends DataPayload { + filterHashes: Vector[DoubleSha256Digest] +) extends DataPayload { val stopHashBE: DoubleSha256DigestBE = stopHash.flip /** The number of hashes in this message */ val filterHashesLength: CompactSizeUInt = CompactSizeUInt( - UInt64(filterHashes.length)) + UInt64(filterHashes.length) + ) val commandName: String = NetworkPayload.compactFilterHeadersCommandName def bytes: ByteVector = RawCompactFilterHeadersMessageSerializer.write(this) @@ -1219,12 +1325,13 @@ object CompactFilterHeadersMessage RawCompactFilterHeadersMessageSerializer.read(bytes) } -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfcheckpt BIP157]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfcheckpt BIP157]] */ case class GetCompactFilterCheckPointMessage( filterType: FilterType, - stopHash: DoubleSha256Digest) - extends DataPayload { + stopHash: DoubleSha256Digest +) extends DataPayload { val commandName: String = NetworkPayload.getCompactFilterCheckpointCommandName def bytes: ByteVector = @@ -1242,17 +1349,19 @@ object GetCompactFilterCheckPointMessage RawGetCompactFilterCheckpointMessageSerializer.read(bytes) } -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfcheckpt BIP-157 ]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfcheckpt BIP-157]] */ case class CompactFilterCheckPointMessage( filterType: FilterType, stopHash: DoubleSha256Digest, - filterHeaders: Vector[DoubleSha256Digest]) - extends DataPayload { + filterHeaders: Vector[DoubleSha256Digest] +) extends DataPayload { /** The amount of filter headers in this message */ val filterHeadersLength: CompactSizeUInt = CompactSizeUInt( - UInt64(filterHeaders.length)) + UInt64(filterHeaders.length) + ) val commandName: String = NetworkPayload.compactFilterCheckpointCommandName @@ -1279,55 +1388,61 @@ object CompactFilterCheckPointMessage } /** The version message provides information about the transmitting node to the - * receiving node at the beginning of a connection. - * Until both peers have exchanged version messages, no other messages will be accepted. - * If a version message is accepted, the receiving node should send a verack message—but - * no node should send a verack message before initializing its half of the connection - * by first sending a version message. + * receiving node at the beginning of a connection. Until both peers have + * exchanged version messages, no other messages will be accepted. If a version + * message is accepted, the receiving node should send a verack message—but no + * node should send a verack message before initializing its half of the + * connection by first sending a version message. * [[https://bitcoin.org/en/developer-reference#version]] */ trait VersionMessage extends ControlPayload { - /** The highest protocol version understood by the transmitting node. See the protocol version section. + /** The highest protocol version understood by the transmitting node. See the + * protocol version section. */ def version: ProtocolVersion - /** The services supported by the transmitting node encoded as a bitfield. See the list of service codes below. + /** The services supported by the transmitting node encoded as a bitfield. See + * the list of service codes below. */ def services: ServiceIdentifier /** The current Unix epoch time according to the transmitting node’s clock. - * Because nodes will reject blocks with timestamps more than two hours in the future, - * this field can help other nodes to determine that their clock is wrong. + * Because nodes will reject blocks with timestamps more than two hours in + * the future, this field can help other nodes to determine that their clock + * is wrong. */ def timestamp: Int64 - /** The services supported by the receiving node as perceived by the transmitting node. - * Same format as the ‘services’ field above. - * Bitcoin Core will attempt to provide accurate information. BitcoinJ will, by default, always send 0. + /** The services supported by the receiving node as perceived by the + * transmitting node. Same format as the ‘services’ field above. Bitcoin Core + * will attempt to provide accurate information. BitcoinJ will, by default, + * always send 0. */ def addressReceiveServices: ServiceIdentifier - /** The IPv6 address of the receiving node as perceived by the transmitting node in big endian byte order. - * IPv4 addresses can be provided as IPv4-mapped IPv6 addresses. - * Bitcoin Core will attempt to provide accurate information - * BitcoinJ will, by default, always return ::ffff:127.0.0.1 - * This is the network address of the node receiving this message + /** The IPv6 address of the receiving node as perceived by the transmitting + * node in big endian byte order. IPv4 addresses can be provided as + * IPv4-mapped IPv6 addresses. Bitcoin Core will attempt to provide accurate + * information BitcoinJ will, by default, always return ::ffff:127.0.0.1 This + * is the network address of the node receiving this message */ def addressReceiveIpAddress: InetAddress - /** The port number of the receiving node as perceived by the transmitting node in big endian byte order. + /** The port number of the receiving node as perceived by the transmitting + * node in big endian byte order. */ def addressReceivePort: Int - /** The services supported by the transmitting node. Should be identical to the ‘services’ field above. + /** The services supported by the transmitting node. Should be identical to + * the ‘services’ field above. */ def addressTransServices: ServiceIdentifier - /** The IPv6 address of the transmitting node in big endian byte order. - * IPv4 addresses can be provided as IPv4-mapped IPv6 addresses. - * Set to ::ffff:127.0.0.1 if unknown. - * This is the network address of the node emitting this message + /** The IPv6 address of the transmitting node in big endian byte order. IPv4 + * addresses can be provided as IPv4-mapped IPv6 addresses. Set to + * ::ffff:127.0.0.1 if unknown. This is the network address of the node + * emitting this message */ def addressTransIpAddress: InetAddress @@ -1335,14 +1450,15 @@ trait VersionMessage extends ControlPayload { */ def addressTransPort: Int - /** A random nonce which can help a node detect a connection to itself. - * If the nonce is 0, the nonce field is ignored. - * If the nonce is anything else, a node should terminate the connection on receipt - * of a version message with a nonce it previously sent. + /** A random nonce which can help a node detect a connection to itself. If the + * nonce is 0, the nonce field is ignored. If the nonce is anything else, a + * node should terminate the connection on receipt of a version message with + * a nonce it previously sent. */ def nonce: UInt64 - /** Number of bytes in following user_agent field. If 0x00, no user agent field is sent. + /** Number of bytes in following user_agent field. If 0x00, no user agent + * field is sent. */ def userAgentSize: CompactSizeUInt @@ -1350,14 +1466,15 @@ trait VersionMessage extends ControlPayload { */ def userAgent: String - /** The height of the transmitting node’s best block chain or, - * in the case of an SPV client, best block header chain. + /** The height of the transmitting node’s best block chain or, in the case of + * an SPV client, best block header chain. */ def startHeight: Int32 - /** Transaction relay flag. If 0x00, no inv messages or tx messages announcing new transactions - * should be sent to this client until it sends a filterload message or filterclear message. - * If 0x01, this node wants inv messages and tx messages announcing new transactions. + /** Transaction relay flag. If 0x00, no inv messages or tx messages announcing + * new transactions should be sent to this client until it sends a filterload + * message or filterclear message. If 0x01, this node wants inv messages and + * tx messages announcing new transactions. */ def relay: Boolean @@ -1372,7 +1489,8 @@ trait VersionMessage extends ControlPayload { } -/** @see https://bitcoin.org/en/developer-reference#version +/** @see + * https://bitcoin.org/en/developer-reference#version */ object VersionMessage extends Factory[VersionMessage] { @@ -1390,8 +1508,8 @@ object VersionMessage extends Factory[VersionMessage] { userAgentSize: CompactSizeUInt, userAgent: String, startHeight: Int32, - relay: Boolean) - extends VersionMessage + relay: Boolean + ) extends VersionMessage override def fromBytes(bytes: ByteVector): VersionMessage = RawVersionMessageSerializer.read(bytes) @@ -1409,7 +1527,8 @@ object VersionMessage extends Factory[VersionMessage] { nonce: UInt64, userAgent: String, startHeight: Int32, - relay: Boolean): VersionMessage = { + relay: Boolean + ): VersionMessage = { val userAgentSize: CompactSizeUInt = CompactSizeUInt.calculateCompactSizeUInt(ByteVector(userAgent.getBytes)) VersionMessageImpl( @@ -1434,13 +1553,16 @@ object VersionMessage extends Factory[VersionMessage] { network: NetworkParameters, receivingIpAddress: InetAddress, transmittingIpAddress: InetAddress, - relay: Boolean): VersionMessage = { - VersionMessage(network, - ProtocolVersion.userAgent, - Int32.zero, - receivingIpAddress, - transmittingIpAddress, - relay) + relay: Boolean + ): VersionMessage = { + VersionMessage( + network, + ProtocolVersion.userAgent, + Int32.zero, + receivingIpAddress, + transmittingIpAddress, + relay + ) } def apply( @@ -1449,7 +1571,8 @@ object VersionMessage extends Factory[VersionMessage] { startHeight: Int32, receivingIpAddress: InetAddress, transmittingIpAddress: InetAddress, - relay: Boolean): VersionMessage = { + relay: Boolean + ): VersionMessage = { val nonce = UInt64.zero VersionMessage( version = ProtocolVersion.default, @@ -1502,11 +1625,12 @@ object NetworkPayload { private[core] val getCompactFilterCheckpointCommandName = "getcfcheckpt" private[core] val compactFilterCheckpointCommandName = "cfcheckpt" - /** Contains all the valid command names with their deserializer on the p2p protocol. - * These commands all have the null bytes appended to the end of the string as - * required by the network header specification. + /** Contains all the valid command names with their deserializer on the p2p + * protocol. These commands all have the null bytes appended to the end of + * the string as required by the network header specification. * - * @see [[https://bitcoin.org/en/developer-reference#message-headers]] + * @see + * [[https://bitcoin.org/en/developer-reference#message-headers]] */ val readers: Map[String, ByteVector => NetworkPayload] = Map( blockCommandName -> RawBlockMessageSerializer.read, @@ -1556,28 +1680,35 @@ object NetworkPayload { /** All command names for P2P messages */ val commandNames: Vector[String] = readers.keys.toVector - /** Parses a [[NetworkPayload]] from the given bytes using the [[NetworkHeader]] - * to determine what type of [[NetworkPayload]] this is - * @param networkHeader the header for the message on the p2p network - * @param payloadBytes the payload corresponding to the header on the p2p network + /** Parses a [[NetworkPayload]] from the given bytes using the + * [[NetworkHeader]] to determine what type of [[NetworkPayload]] this is + * @param networkHeader + * the header for the message on the p2p network + * @param payloadBytes + * the payload corresponding to the header on the p2p network */ def apply( networkHeader: NetworkHeader, - payloadBytes: ByteVector): NetworkPayload = { - //the commandName in the network header tells us what payload type this is + payloadBytes: ByteVector + ): NetworkPayload = { + // the commandName in the network header tells us what payload type this is val deserializer: ByteVector => NetworkPayload = readers( - networkHeader.commandName) + networkHeader.commandName + ) deserializer(payloadBytes) } /** Parses a [[NetworkPayload]] from the given hex using the [[NetworkHeader]] * to determine what type of [[NetworkPayload]] this is - * @param networkHeader the header for the message on the p2p network - * @param payloadHex the hexadecimal representation of the payload + * @param networkHeader + * the header for the message on the p2p network + * @param payloadHex + * the hexadecimal representation of the payload */ def apply( networkHeader: NetworkHeader, - payloadHex: String): NetworkPayload = { + payloadHex: String + ): NetworkPayload = { NetworkPayload(networkHeader, BytesUtil.decodeHex(payloadHex)) } } diff --git a/core/src/main/scala/org/bitcoins/core/p2p/ProtocolVersion.scala b/core/src/main/scala/org/bitcoins/core/p2p/ProtocolVersion.scala index e537e76b27..0841a9041b 100644 --- a/core/src/main/scala/org/bitcoins/core/p2p/ProtocolVersion.scala +++ b/core/src/main/scala/org/bitcoins/core/p2p/ProtocolVersion.scala @@ -3,9 +3,10 @@ package org.bitcoins.core.p2p import org.bitcoins.crypto.{Factory, NetworkElement} import scodec.bits._ -/** The peer to peer network has versions to allow for new operations - * Here are the currently protocol versions in the network - * @see [[https://bitcoin.org/en/developer-reference#protocol-versions]] +/** The peer to peer network has versions to allow for new operations Here are + * the currently protocol versions in the network + * @see + * [[https://bitcoin.org/en/developer-reference#protocol-versions]] */ sealed trait ProtocolVersion extends NetworkElement @@ -36,124 +37,110 @@ object ProtocolVersion extends Factory[ProtocolVersion] { ) def fromBytes(bytes: ByteVector): ProtocolVersion = { - //TODO: Should we default to the latest protocol version if the bytes don't match??? + // TODO: Should we default to the latest protocol version if the bytes don't match??? versions.find(v => v.bytes == bytes).getOrElse(versions.last) } } -/** Added receive IP address fields to version message. - * Bitcoin Core 0.1.6 (Oct 2009) +/** Added receive IP address fields to version message. Bitcoin Core 0.1.6 (Oct + * 2009) */ case object ProtocolVersion106 extends ProtocolVersion { override val bytes: ByteVector = hex"6a000000" } -/** Added checksum field to message headers. - * Bitcoin Core 0.2.9 (May 2010) +/** Added checksum field to message headers. Bitcoin Core 0.2.9 (May 2010) */ case object ProtocolVersion209 extends ProtocolVersion { override val bytes: ByteVector = hex"d1000000" } -/** Added alert message - * Bitcion Core 0.3.11 (Aug 2010) +/** Added alert message Bitcion Core 0.3.11 (Aug 2010) */ case object ProtocolVersion311 extends ProtocolVersion { override val bytes: ByteVector = hex"37010000" } -/** Added time field to addr message. - * Bitcoin Core 0.3.15 (Oct 2010) +/** Added time field to addr message. Bitcoin Core 0.3.15 (Oct 2010) */ case object ProtocolVersion31402 extends ProtocolVersion { override val bytes: ByteVector = hex"aa7a0000" } -/** Added getheaders message and headers message. - * Bitcoin Core 0.3.18 (Dec 2010) +/** Added getheaders message and headers message. Bitcoin Core 0.3.18 (Dec 2010) */ case object ProtocolVersion31800 extends ProtocolVersion { override val bytes: ByteVector = hex"387c0000" } -/** BIP14: Separated protocol version from Bitcoin Core version - * Bitcoin Core 0.6.0 (Mar 2012) +/** BIP14: Separated protocol version from Bitcoin Core version Bitcoin Core + * 0.6.0 (Mar 2012) */ case object ProtocolVersion60000 extends ProtocolVersion { override val bytes: ByteVector = hex"60ea0000" } -/** BIP31: Added nonce field to ping message, Added pong message - * Bitcoin Core 0.6.1 (May 2012) +/** BIP31: Added nonce field to ping message, Added pong message Bitcoin Core + * 0.6.1 (May 2012) */ case object ProtocolVersion60001 extends ProtocolVersion { override val bytes: ByteVector = hex"61ea0000" } -/** BIP35: Added mempool message. - * • Extended getdata message to allow download of memory pool transactions - * Bitcoin Core 0.7.0 (Sep 2012) +/** BIP35: Added mempool message. • Extended getdata message to allow download + * of memory pool transactions Bitcoin Core 0.7.0 (Sep 2012) */ case object ProtocolVersion60002 extends ProtocolVersion { override val bytes: ByteVector = hex"62ea0000" } -/** Added notfound message. - * BIP37: - * • Added filterload message. - * • Added filteradd message. - * • Added filterclear message. - * • Added merkleblock message. - * • Added relay field to version message - * • Added MSG_FILTERED_BLOCK inventory type to getdata message. - * Bitcoin Core 0.8.0 (Feb 2013) +/** Added notfound message. BIP37: • Added filterload message. • Added filteradd + * message. • Added filterclear message. • Added merkleblock message. • Added + * relay field to version message • Added MSG_FILTERED_BLOCK inventory type to + * getdata message. Bitcoin Core 0.8.0 (Feb 2013) */ case object ProtocolVersion70001 extends ProtocolVersion { override val bytes: ByteVector = hex"71110100" } /** Send multiple inv messages in response to a mempool message if necessary - * BIP61: Add reject message - * Bitcoin Core 0.9.0 (Mar 2014) + * BIP61: Add reject message Bitcoin Core 0.9.0 (Mar 2014) */ case object ProtocolVersion70002 extends ProtocolVersion { override val bytes: ByteVector = hex"72110100" } -/** BIP130: Add sendheaders message - * Bitcoin Core 0.12.0 +/** BIP130: Add sendheaders message Bitcoin Core 0.12.0 */ case object ProtocolVersion70012 extends ProtocolVersion { override val bytes: ByteVector = hex"7c110100" } -/** Added feefilter message. - * Removed alert message system. See Alert System Retirement - * Bitcoin Core 0.13.0 (August 2016) +/** Added feefilter message. Removed alert message system. See Alert System + * Retirement Bitcoin Core 0.13.0 (August 2016) */ case object ProtocolVersion70013 extends ProtocolVersion { override val bytes: ByteVector = hex"7d110100" } -/** BIP152 - * Added sendcmpct, cmpctblock, getblocktxn, blocktxn messages - * Added MSG_CMPCT_BLOCK inventory type to getdata message. - * Bitcoin Core 0.13.0 (August 2016) +/** BIP152 Added sendcmpct, cmpctblock, getblocktxn, blocktxn messages Added + * MSG_CMPCT_BLOCK inventory type to getdata message. Bitcoin Core 0.13.0 + * (August 2016) */ case object ProtocolVersion70014 extends ProtocolVersion { override val bytes: ByteVector = hex"7e110100" } -/** New banning behavior for invalid compact blocks #9026 in v0.14.0, Backported to v0.13.2 in #9048. - * Bitcoin Core 0.13.2 (January 2017) +/** New banning behavior for invalid compact blocks #9026 in v0.14.0, Backported + * to v0.13.2 in #9048. Bitcoin Core 0.13.2 (January 2017) */ case object ProtocolVersion70015 extends ProtocolVersion { override val bytes: ByteVector = hex"7f110100" } -/** Indicates that a node prefers to relay transactions via wtxid, rather than txid. - * Protocol version 70016 as described by BIP 339. - * Bitcoin Core 0.21.0 (December 2020) +/** Indicates that a node prefers to relay transactions via wtxid, rather than + * txid. Protocol version 70016 as described by BIP 339. Bitcoin Core 0.21.0 + * (December 2020) */ case object ProtocolVersion70016 extends ProtocolVersion { override val bytes: ByteVector = hex"80110100" diff --git a/core/src/main/scala/org/bitcoins/core/p2p/ServiceIdentifier.scala b/core/src/main/scala/org/bitcoins/core/p2p/ServiceIdentifier.scala index 560a8f793f..f666c33ef2 100644 --- a/core/src/main/scala/org/bitcoins/core/p2p/ServiceIdentifier.scala +++ b/core/src/main/scala/org/bitcoins/core/p2p/ServiceIdentifier.scala @@ -7,9 +7,11 @@ import scodec.bits.ByteVector /** Indicates the services that are provided by a node on the P2P network * - * @see [[https://bitcoin.org/en/developer-reference#version]] - * @see [[https://github.com/bitcoin/bitcoin/blob/master/src/protocol.h#L247 protocol.h]] - * in Bitcoin Core + * @see + * [[https://bitcoin.org/en/developer-reference#version]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/master/src/protocol.h#L247 protocol.h]] + * in Bitcoin Core */ sealed abstract class ServiceIdentifier extends NetworkElement { @@ -19,65 +21,68 @@ sealed abstract class ServiceIdentifier extends NetworkElement { override def bytes: ByteVector = RawServiceIdentifierSerializer.write(this) - /** This node is not a full node. - * It may not be able to provide any data except for the transactions it originates. + /** This node is not a full node. It may not be able to provide any data + * except for the transactions it originates. */ lazy val nodeNone: Boolean = num == UInt64.zero - /** This is a full node and can be asked for full blocks. - * It should implement all protocol features available in - * its self-reported protocol version. + /** This is a full node and can be asked for full blocks. It should implement + * all protocol features available in its self-reported protocol version. */ lazy val nodeNetwork: Boolean = reversedBits(0) // 1 << 0 - /** This is a full node capable of responding to the - * `getutxo` protocol request. This is not supported - * by any currently-maintained Bitcoin node. + /** This is a full node capable of responding to the `getutxo` protocol + * request. This is not supported by any currently-maintained Bitcoin node. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0064.mediawiki BIP64]] - * for details on how this is implemented. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0064.mediawiki BIP64]] + * for details on how this is implemented. */ lazy val nodeGetUtxo: Boolean = reversedBits(1) // 1 << 1 - /** This is a full node capable and willing to handle - * bloom-filtered connections. + /** This is a full node capable and willing to handle bloom-filtered + * connections. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki BIP111]] - * for details + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki BIP111]] + * for details */ lazy val nodeBloom: Boolean = reversedBits(2) // 1 << 2 - /** This is a full node that can be asked for blocks - * and transactions including witness data. + /** This is a full node that can be asked for blocks and transactions + * including witness data. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki BIP144]]] - * for details. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki BIP144]]] + * for details. */ lazy val nodeWitness: Boolean = reversedBits(3) // 1 << 3 - /** This is a full node that supports Xtreme Thinblocks. - * This is not supported by any currently-maintained - * Bitcoin node. + /** This is a full node that supports Xtreme Thinblocks. This is not supported + * by any currently-maintained Bitcoin node. */ lazy val nodeXthin: Boolean = reversedBits(4) // 1 << 4 - /** NODE_COMPACT_FILTERS means the node will service basic - * block filter requests. + /** NODE_COMPACT_FILTERS means the node will service basic block filter + * requests. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0157 BIP157]] and - * [https://github.com/bitcoin/bips/blob/master/bip-0158 BIP158] - * for details on how this is implemented. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157 BIP157]] and + * [https://github.com/bitcoin/bips/blob/master/bip-0158 BIP158] for + * details on how this is implemented. * - * @note This is not yet supported by any Core release. Currently - * (aug. 1 2019) is a open PR by jimpo: https://github.com/bitcoin/bitcoin/pull/16442 + * @note + * This is not yet supported by any Core release. Currently (aug. 1 2019) + * is a open PR by jimpo: https://github.com/bitcoin/bitcoin/pull/16442 */ lazy val nodeCompactFilters: Boolean = reversedBits(6) // 1 << 6 - /** this means the same as `nodeNetwork` with the limitation of only - * serving the last 288 (2 days) blocks + /** this means the same as `nodeNetwork` with the limitation of only serving + * the last 288 (2 days) blocks * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki BIP159]] - * for details on how this is implemented. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki BIP159]] + * for details on how this is implemented. */ lazy val nodeNetworkLimited: Boolean = reversedBits(10) // 1 << 10 @@ -89,7 +94,9 @@ sealed abstract class ServiceIdentifier extends NetworkElement { s"ServiceIdentifier($innerText)" } - /** returns true if this service identifier has at least all services specified in services */ + /** returns true if this service identifier has at least all services + * specified in services + */ def hasServicesOf(services: ServiceIdentifier): Boolean = { (num & services.num) == services.num } @@ -105,54 +112,56 @@ object ServiceIdentifier extends Factory[ServiceIdentifier] with StringFactory[ServiceIdentifier] { - /** This node is not a full node. - * It may not be able to provide any data except for the transactions it originates. + /** This node is not a full node. It may not be able to provide any data + * except for the transactions it originates. */ val NODE_NONE = ServiceIdentifier(UInt64.zero) - /** This is a full node and can be asked for full blocks. - * It should implement all protocol features available in its self-reported protocol version. + /** This is a full node and can be asked for full blocks. It should implement + * all protocol features available in its self-reported protocol version. */ val NODE_NETWORK: ServiceIdentifier = ServiceIdentifier(1 << 0) - /** This is a full node capable of responding to the - * `getutxo` protocol request. This is not supported - * by any currently-maintained Bitcoin node. + /** This is a full node capable of responding to the `getutxo` protocol + * request. This is not supported by any currently-maintained Bitcoin node. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0064.mediawiki BIP64]] - * for details on how this is implemented. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0064.mediawiki BIP64]] + * for details on how this is implemented. */ val NODE_GET_UTXO: ServiceIdentifier = ServiceIdentifier(1 << 1) - /** This is a full node capable and willing to handle - * bloom-filtered connections. + /** This is a full node capable and willing to handle bloom-filtered + * connections. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki BIP111]] - * for details + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki BIP111]] + * for details */ val NODE_BLOOM: ServiceIdentifier = ServiceIdentifier(1 << 2) - /** This is a full node that can be asked for blocks - * and transactions including witness data. + /** This is a full node that can be asked for blocks and transactions + * including witness data. * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki BIP144]]] - * for details. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki BIP144]]] + * for details. */ val NODE_WITNESS: ServiceIdentifier = ServiceIdentifier(1 << 3) - /** This is a full node that supports Xtreme Thinblocks. - * This is not supported by any currently-maintained - * Bitcoin node. + /** This is a full node that supports Xtreme Thinblocks. This is not supported + * by any currently-maintained Bitcoin node. */ val NODE_XTHIN: ServiceIdentifier = ServiceIdentifier(1 << 4) val NODE_COMPACT_FILTERS = ServiceIdentifier(1 << 6) - /** This means the same as `NODE_NETWORK` with the limitation of only - * serving the last 288 (2 days) blocks + /** This means the same as `NODE_NETWORK` with the limitation of only serving + * the last 288 (2 days) blocks * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki BIP159]] - * for details on how this is implemented. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0159.mediawiki BIP159]] + * for details on how this is implemented. */ val NODE_NETWORK_LIMITED: ServiceIdentifier = ServiceIdentifier(1 << 10) @@ -173,7 +182,8 @@ object ServiceIdentifier case "XTHIN" => NODE_XTHIN case _: String => throw new IllegalArgumentException( - s""""$string" does not represent a ServiceIdentifier""") + s""""$string" does not represent a ServiceIdentifier""" + ) } def apply(num: BigInt): ServiceIdentifier = ServiceIdentifier(UInt64(num)) diff --git a/core/src/main/scala/org/bitcoins/core/p2p/TypeIdentifier.scala b/core/src/main/scala/org/bitcoins/core/p2p/TypeIdentifier.scala index fe796e150d..8fc1d2f59c 100644 --- a/core/src/main/scala/org/bitcoins/core/p2p/TypeIdentifier.scala +++ b/core/src/main/scala/org/bitcoins/core/p2p/TypeIdentifier.scala @@ -7,7 +7,8 @@ import scodec.bits.ByteVector /** This indicates the type of the object that has been hashed for an inventory * - * @see https://bitcoin.org/en/developer-reference#data-messages + * @see + * https://bitcoin.org/en/developer-reference#data-messages */ sealed trait TypeIdentifier extends NetworkElement { def num: UInt32 @@ -30,17 +31,17 @@ object TypeIdentifier extends Factory[TypeIdentifier] { override val num = UInt32(3) } - /** The hash is of a block header; identical to `MsgBlock`. When used in - * a `getdata` message, this indicates the response should be a `cmpctblock` + /** The hash is of a block header; identical to `MsgBlock`. When used in a + * `getdata` message, this indicates the response should be a `cmpctblock` * message. Only for use in `getdata` messages. */ final case object MsgCompactBlock extends TypeIdentifier { val num: UInt32 = UInt32(4) } - /** The hash is a TXID. When used in a `getdata` message, this indicates - * the response should be a transaction message, if the witness structure - * is nonempty, the witness serialization will be used. Only for use in + /** The hash is a TXID. When used in a `getdata` message, this indicates the + * response should be a transaction message, if the witness structure is + * nonempty, the witness serialization will be used. Only for use in * `getdata` messages. */ final case object MsgWitnessTx extends TypeIdentifier { @@ -48,10 +49,10 @@ object TypeIdentifier extends Factory[TypeIdentifier] { val num: UInt32 = MsgTx.num | MsgWitnessFlag } - /** The hash is of a block header; identical to `MsgBlock`. When - * used in a `getdata` message, this indicates the response should - * be a block message with transactions that have a witness using - * witness serialization. Only for use in `getdata` messages. + /** The hash is of a block header; identical to `MsgBlock`. When used in a + * `getdata` message, this indicates the response should be a block message + * with transactions that have a witness using witness serialization. Only + * for use in `getdata` messages. */ final case object MsgWitnessBlock extends TypeIdentifier { val num: UInt32 = MsgBlock.num | MsgWitnessFlag @@ -63,18 +64,20 @@ object TypeIdentifier extends Factory[TypeIdentifier] { val num: UInt32 = MsgFilteredBlock.num | MsgWitnessFlag } - private lazy val assigned = Vector(MsgTx, - MsgBlock, - MsgFilteredBlock, - MsgCompactBlock, - MsgWitnessTx, - MsgWitnessBlock, - MsgFilteredWitnessBlock) + private lazy val assigned = Vector( + MsgTx, + MsgBlock, + MsgFilteredBlock, + MsgCompactBlock, + MsgWitnessTx, + MsgWitnessBlock, + MsgFilteredWitnessBlock + ) /** from the docs at https://bitcoin.org/en/developer-reference#data-messages * These (witness block and tx) are the same as their respective type - * identifier but with their 30th bit set to indicate witness. - * For example MSG_WITNESS_TX = 0x01000040. + * identifier but with their 30th bit set to indicate witness. For example + * MSG_WITNESS_TX = 0x01000040. */ private val MsgWitnessFlag = UInt32(1 << 30) diff --git a/core/src/main/scala/org/bitcoins/core/package.scala b/core/src/main/scala/org/bitcoins/core/package.scala index 8815401f3a..89c499101a 100644 --- a/core/src/main/scala/org/bitcoins/core/package.scala +++ b/core/src/main/scala/org/bitcoins/core/package.scala @@ -59,7 +59,8 @@ package object core { override def compare( x: SatoshisPerKiloByte, - y: SatoshisPerKiloByte): Int = x.toLong compare y.toLong + y: SatoshisPerKiloByte + ): Int = x.toLong compare y.toLong } implicit val byteVectorOrdering: Ordering[ByteVector] = @@ -88,7 +89,8 @@ package object core { new Ordering[SchnorrDigitalSignature] { override def compare( x: SchnorrDigitalSignature, - y: SchnorrDigitalSignature): Int = { + y: SchnorrDigitalSignature + ): Int = { nonceOrdering.compare(x.rx, y.rx) } } @@ -106,7 +108,8 @@ package object core { new Ordering[OutcomePayoutPoint] { override def compare( x: OutcomePayoutPoint, - y: OutcomePayoutPoint): Int = { + y: OutcomePayoutPoint + ): Int = { x.outcome.compare(y.outcome) } } @@ -116,7 +119,8 @@ package object core { new Ordering[DLCPayoutCurvePiece] { override def compare( x: DLCPayoutCurvePiece, - y: DLCPayoutCurvePiece): Int = { + y: DLCPayoutCurvePiece + ): Int = { outcomePayoutPointOrdering.compare(x.leftEndpoint, y.leftEndpoint) } } diff --git a/core/src/main/scala/org/bitcoins/core/policy/Policy.scala b/core/src/main/scala/org/bitcoins/core/policy/Policy.scala index 5315249d5d..7a3eae2564 100644 --- a/core/src/main/scala/org/bitcoins/core/policy/Policy.scala +++ b/core/src/main/scala/org/bitcoins/core/policy/Policy.scala @@ -5,24 +5,23 @@ import org.bitcoins.core.number.UInt32 import org.bitcoins.core.script.flag._ import org.bitcoins.core.wallet.fee.{FeeUnit, SatoshisPerVirtualByte} -/** Created by chris on 4/6/16. - * Mimics the policy files found in +/** Created by chris on 4/6/16. Mimics the policy files found in * [[https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.h Bitcoin Core]] */ sealed abstract class Policy { - /** Mandatory script verification flags that all new blocks must comply with for - * them to be valid. (but old blocks may not comply with) Currently just P2SH, - * but in the future other flags may be added, such as a soft-fork to enforce - * strict DER encoding. + /** Mandatory script verification flags that all new blocks must comply with + * for them to be valid. (but old blocks may not comply with) Currently just + * P2SH, but in the future other flags may be added, such as a soft-fork to + * enforce strict DER encoding. * * Failing one of these tests may trigger a DoS ban - see CheckInputs() for * details. */ def mandatoryScriptVerifyFlags: Seq[ScriptFlag] = Seq(ScriptVerifyP2SH) - /** The default script verify flags used to validate the blockchain - * and bitcoin transactions + /** The default script verify flags used to validate the blockchain and + * bitcoin transactions */ def standardScriptVerifyFlags: Seq[ScriptFlag] = mandatoryScriptVerifyFlags ++ Seq( @@ -52,8 +51,7 @@ sealed abstract class Policy { def confirmations: Long = 6 /** Minimum amount of [[org.bitcoins.core.currency.CurrencyUnit CurrencyUnit]] - * lock in a Channel - * Currently set to 1 mBTC + * lock in a Channel Currently set to 1 mBTC * * TODO: Remove this? */ diff --git a/core/src/main/scala/org/bitcoins/core/protocol/Address.scala b/core/src/main/scala/org/bitcoins/core/protocol/Address.scala index e8e23b2718..b4963ccd19 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/Address.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/Address.scala @@ -30,7 +30,9 @@ sealed abstract class Address { */ def hash: HashDigest - /** The [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] the address represents */ + /** The [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] the + * address represents + */ def scriptPubKey: ScriptPubKey override def toString: String = value @@ -40,7 +42,8 @@ sealed abstract class Address { /** Checks if the address currently follows the standardness rules of bitcoin * and will be relayed by network. * - * Currently this just means verifying the address is not of a [[UnassignedWitnessScriptPubKey]] + * Currently this just means verifying the address is not of a + * [[UnassignedWitnessScriptPubKey]] */ def isStandard: Boolean } @@ -127,8 +130,8 @@ object Bech32Address extends AddressFactory[Bech32Address] { private case class Bech32AddressImpl( networkParameters: NetworkParameters, - data: Vector[UInt5]) - extends Bech32Address { + data: Vector[UInt5] + ) extends Bech32Address { require(verifyChecksum, s"checksum did not pass $checksum") } @@ -137,8 +140,9 @@ object Bech32Address extends AddressFactory[Bech32Address] { def apply( witSPK: WitnessScriptPubKey, - networkParameters: NetworkParameters): Bech32Address = { - //we don't encode the wit version or pushop for program into base5 + networkParameters: NetworkParameters + ): Bech32Address = { + // we don't encode the wit version or pushop for program into base5 val prog = UInt8.toUInt8s(witSPK.asmBytes.tail.tail) val encoded = Bech32.from8bitTo5bit(prog) val witVersion = witSPK.witnessVersion.version.toInt.toByte @@ -147,14 +151,16 @@ object Bech32Address extends AddressFactory[Bech32Address] { def apply( networkParameters: NetworkParameters, - data: Vector[UInt5]): Bech32Address = { + data: Vector[UInt5] + ): Bech32Address = { Bech32AddressImpl(networkParameters, data) } /** Returns a base 5 checksum as specified by BIP173 */ def createChecksum( hrp: BtcHumanReadablePart, - bytes: Vector[UInt5]): Vector[UInt5] = { + bytes: Vector[UInt5] + ): Vector[UInt5] = { val values = hrp.expand ++ bytes Bech32.createChecksum(values, Bech32Encoding.Bech32) } @@ -175,23 +181,32 @@ object Bech32Address extends AddressFactory[Bech32Address] { case Some(v) => val witSPK = Try( WitnessScriptPubKeyV0( - List(v.version) ++ pushOp ++ List(ScriptConstant(progBytes)))) + List(v.version) ++ pushOp ++ List(ScriptConstant(progBytes)) + ) + ) witSPK match { case Success(spk) => Success(spk) case Failure(err) => Failure( new IllegalArgumentException( - "Failed to decode bech32 into a witSPK: " + err.getMessage)) + "Failed to decode bech32 into a witSPK: " + err.getMessage + ) + ) } case None => Failure( new IllegalArgumentException( - "Witness version was not valid, got: " + v)) + "Witness version was not valid, got: " + v + ) + ) } } } - /** Decodes bech32 string to the [[org.bitcoins.core.protocol.BtcHumanReadablePart HumanReadablePart]] & data part */ + /** Decodes bech32 string to the + * [[org.bitcoins.core.protocol.BtcHumanReadablePart HumanReadablePart]] & + * data part + */ override def fromString(bech32: String): Bech32Address = { val bech32T = for { (hrp, data) <- Bech32.splitToHrpAndData(bech32, Bech32Encoding.Bech32) @@ -206,7 +221,8 @@ object Bech32Address extends AddressFactory[Bech32Address] { override def fromScriptPubKeyT( spk: ScriptPubKey, - np: NetworkParameters): Try[Bech32Address] = + np: NetworkParameters + ): Try[Bech32Address] = spk match { case witSPK: WitnessScriptPubKeyV0 => Success(Bech32Address(witSPK, np)) @@ -218,7 +234,9 @@ object Bech32Address extends AddressFactory[Bech32Address] { _: UnassignedWitnessScriptPubKey | EmptyScriptPubKey) => Failure( new IllegalArgumentException( - "Cannot create a address for the scriptPubKey: " + x)) + "Cannot create a address for the scriptPubKey: " + x + ) + ) } } @@ -242,8 +260,10 @@ sealed abstract class Bech32mAddress extends BitcoinAddress { override def scriptPubKey: WitnessScriptPubKey = { val spk = Bech32mAddress.fromStringToWitSPK(value).get - require(spk.witnessVersion != WitnessVersion0, - "Use bech32 addresses for segwit v0") + require( + spk.witnessVersion != WitnessVersion0, + "Use bech32 addresses for segwit v0" + ) spk } @@ -272,8 +292,8 @@ object Bech32mAddress extends AddressFactory[Bech32mAddress] { private case class Bech32mAddressImpl( networkParameters: NetworkParameters, - data: Vector[UInt5]) - extends Bech32mAddress { + data: Vector[UInt5] + ) extends Bech32mAddress { require(verifyChecksum, "checksum did not pass") require(Try(scriptPubKey).isSuccess, "invalid witness script pub key") } @@ -283,8 +303,9 @@ object Bech32mAddress extends AddressFactory[Bech32mAddress] { def apply( witSPK: WitnessScriptPubKey, - networkParameters: NetworkParameters): Bech32mAddress = { - //we don't encode the wit version or pushop for program into base5 + networkParameters: NetworkParameters + ): Bech32mAddress = { + // we don't encode the wit version or pushop for program into base5 val prog = UInt8.toUInt8s(witSPK.asmBytes.tail.tail) val encoded = Bech32.from8bitTo5bit(prog) val witVersion = witSPK.witnessVersion.version.toInt.toByte @@ -293,14 +314,16 @@ object Bech32mAddress extends AddressFactory[Bech32mAddress] { def apply( networkParameters: NetworkParameters, - data: Vector[UInt5]): Bech32mAddress = { + data: Vector[UInt5] + ): Bech32mAddress = { Bech32mAddressImpl(networkParameters, data) } /** Returns a base 5 checksum as specified by BIP173 */ def createChecksum( hrp: BtcHumanReadablePart, - bytes: Vector[UInt5]): Vector[UInt5] = { + bytes: Vector[UInt5] + ): Vector[UInt5] = { val values = hrp.expand ++ bytes Bech32.createChecksum(values, Bech32Encoding.Bech32m) } @@ -320,23 +343,32 @@ object Bech32mAddress extends AddressFactory[Bech32mAddress] { case Some(v) => val witSPK = Try( WitnessScriptPubKey( - List(v.version) ++ pushOp ++ List(ScriptConstant(progBytes)))) + List(v.version) ++ pushOp ++ List(ScriptConstant(progBytes)) + ) + ) witSPK match { case Success(spk) => Success(spk) case Failure(err) => Failure( new IllegalArgumentException( - "Failed to decode bech32 into a witSPK: " + err.getMessage)) + "Failed to decode bech32 into a witSPK: " + err.getMessage + ) + ) } case None => Failure( new IllegalArgumentException( - "Witness version was not valid, got: " + v)) + "Witness version was not valid, got: " + v + ) + ) } } } - /** Decodes bech32 string to the [[org.bitcoins.core.protocol.BtcHumanReadablePart HumanReadablePart]] & data part */ + /** Decodes bech32 string to the + * [[org.bitcoins.core.protocol.BtcHumanReadablePart HumanReadablePart]] & + * data part + */ override def fromString(bech32m: String): Bech32mAddress = { val bech32T = for { (hrp, data) <- Bech32.splitToHrpAndData(bech32m, Bech32Encoding.Bech32m) @@ -351,7 +383,8 @@ object Bech32mAddress extends AddressFactory[Bech32mAddress] { override def fromScriptPubKeyT( spk: ScriptPubKey, - np: NetworkParameters): Try[Bech32mAddress] = + np: NetworkParameters + ): Try[Bech32mAddress] = spk match { case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey | _: P2PKWithTimeoutScriptPubKey | _: MultiSignatureScriptPubKey | @@ -361,7 +394,9 @@ object Bech32mAddress extends AddressFactory[Bech32mAddress] { EmptyScriptPubKey) => Failure( new IllegalArgumentException( - "Cannot create a address for the scriptPubKey: " + x)) + "Cannot create a address for the scriptPubKey: " + x + ) + ) case witSPK: WitnessScriptPubKey => Success(Bech32mAddress(witSPK, np)) } @@ -371,30 +406,34 @@ object P2PKHAddress extends AddressFactory[P2PKHAddress] { private case class P2PKHAddressImpl( hash: Sha256Hash160Digest, - networkParameters: NetworkParameters) - extends P2PKHAddress + networkParameters: NetworkParameters + ) extends P2PKHAddress def apply( hash: Sha256Hash160Digest, - network: NetworkParameters): P2PKHAddress = + network: NetworkParameters + ): P2PKHAddress = P2PKHAddressImpl(hash, network) def apply( pubKey: ECPublicKey, - networkParameters: NetworkParameters): P2PKHAddress = { + networkParameters: NetworkParameters + ): P2PKHAddress = { val hash = CryptoUtil.sha256Hash160(pubKey.bytes) P2PKHAddress(hash, networkParameters) } def apply( spk: P2PKHScriptPubKey, - networkParameters: NetworkParameters): P2PKHAddress = { + networkParameters: NetworkParameters + ): P2PKHAddress = { P2PKHAddress(spk.pubKeyHash, networkParameters) } def fromDecompressedPubKey( pubKey: ECPublicKey, - networkParameters: NetworkParameters): P2PKHAddress = { + networkParameters: NetworkParameters + ): P2PKHAddress = { val hash = CryptoUtil.sha256Hash160(pubKey.decompressedBytes) P2PKHAddressImpl(hash, networkParameters) } @@ -413,7 +452,8 @@ object P2PKHAddress extends AddressFactory[P2PKHAddress] { val payloadSize = bytes.size - p2pkhNetworkBytes.size require( payloadSize == 20, - s"Payload of a P2PKH address must be 20 bytes in size, got $payloadSize") + s"Payload of a P2PKH address must be 20 bytes in size, got $payloadSize" + ) val payload = bytes.slice(p2pkhNetworkBytes.size, bytes.size) P2PKHAddress(Sha256Hash160Digest(payload), network) } @@ -422,7 +462,9 @@ object P2PKHAddress extends AddressFactory[P2PKHAddress] { case None => Failure( new IllegalArgumentException( - s"Given address was not a valid P2PKH address, got: $address")) + s"Given address was not a valid P2PKH address, got: $address" + ) + ) } } @@ -434,7 +476,8 @@ object P2PKHAddress extends AddressFactory[P2PKHAddress] { override def fromScriptPubKeyT( spk: ScriptPubKey, - np: NetworkParameters): Try[P2PKHAddress] = + np: NetworkParameters + ): Try[P2PKHAddress] = spk match { case p2pkh: P2PKHScriptPubKey => Success(P2PKHAddress(p2pkh, np)) case x @ (_: P2PKScriptPubKey | _: P2PKWithTimeoutScriptPubKey | @@ -445,7 +488,9 @@ object P2PKHAddress extends AddressFactory[P2PKHAddress] { EmptyScriptPubKey) => Failure( new IllegalArgumentException( - "Cannot create a address for the scriptPubKey: " + x)) + "Cannot create a address for the scriptPubKey: " + x + ) + ) } } @@ -453,28 +498,34 @@ object P2SHAddress extends AddressFactory[P2SHAddress] { private case class P2SHAddressImpl( hash: Sha256Hash160Digest, - networkParameters: NetworkParameters) - extends P2SHAddress + networkParameters: NetworkParameters + ) extends P2SHAddress - /** Creates a [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] from the given - * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]], - * then creates an address from that [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] + /** Creates a + * [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] + * from the given + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]], then + * creates an address from that + * [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] */ def apply( scriptPubKey: ScriptPubKey, - network: NetworkParameters): P2SHAddress = { + network: NetworkParameters + ): P2SHAddress = { val p2shScriptPubKey = P2SHScriptPubKey(scriptPubKey) P2SHAddress(p2shScriptPubKey, network) } def apply( p2shScriptPubKey: P2SHScriptPubKey, - network: NetworkParameters): P2SHAddress = + network: NetworkParameters + ): P2SHAddress = P2SHAddress(p2shScriptPubKey.scriptHash, network) def apply( hash: Sha256Hash160Digest, - network: NetworkParameters): P2SHAddress = + network: NetworkParameters + ): P2SHAddress = P2SHAddressImpl(hash, network) override def fromString(address: String): P2SHAddress = { @@ -491,7 +542,8 @@ object P2SHAddress extends AddressFactory[P2SHAddress] { val payloadSize = bytes.size - p2shNetworkBytes.size require( payloadSize == 20, - s"Payload of a P2PKH address must be 20 bytes in size, got $payloadSize") + s"Payload of a P2PKH address must be 20 bytes in size, got $payloadSize" + ) val payload = bytes.slice(p2shNetworkBytes.size, bytes.size) P2SHAddress(Sha256Hash160Digest(payload), network) } @@ -500,7 +552,9 @@ object P2SHAddress extends AddressFactory[P2SHAddress] { case None => Failure( new IllegalArgumentException( - s"Given address was not a valid P2PKH address, got: $address")) + s"Given address was not a valid P2PKH address, got: $address" + ) + ) } } @@ -512,7 +566,8 @@ object P2SHAddress extends AddressFactory[P2SHAddress] { override def fromScriptPubKeyT( spk: ScriptPubKey, - np: NetworkParameters): Try[P2SHAddress] = + np: NetworkParameters + ): Try[P2SHAddress] = spk match { case p2sh: P2SHScriptPubKey => Success(P2SHAddress(p2sh, np)) case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey | @@ -523,13 +578,17 @@ object P2SHAddress extends AddressFactory[P2SHAddress] { EmptyScriptPubKey) => Failure( new IllegalArgumentException( - "Cannot create a address for the scriptPubKey: " + x)) + "Cannot create a address for the scriptPubKey: " + x + ) + ) } } object BitcoinAddress extends AddressFactory[BitcoinAddress] { - /** Creates a [[org.bitcoins.core.protocol.BitcoinAddress BitcoinAddress]] from the given string value */ + /** Creates a [[org.bitcoins.core.protocol.BitcoinAddress BitcoinAddress]] + * from the given string value + */ def apply(value: String): BitcoinAddress = fromString(value) override def fromString(value: String): BitcoinAddress = { @@ -543,13 +602,15 @@ object BitcoinAddress extends AddressFactory[BitcoinAddress] { case Success(addr) => addr case Failure(_) => throw new IllegalArgumentException( - s"Could not decode the given value to a BitcoinAddress, got: $value") + s"Could not decode the given value to a BitcoinAddress, got: $value" + ) } } override def fromScriptPubKeyT( spk: ScriptPubKey, - np: NetworkParameters): Try[BitcoinAddress] = + np: NetworkParameters + ): Try[BitcoinAddress] = spk match { case p2pkh: P2PKHScriptPubKey => Success(P2PKHAddress(p2pkh, np)) case p2sh: P2SHScriptPubKey => Success(P2SHAddress(p2sh, np)) @@ -564,7 +625,9 @@ object BitcoinAddress extends AddressFactory[BitcoinAddress] { _: WitnessCommitment | EmptyScriptPubKey) => Failure( new IllegalArgumentException( - "Cannot create a address for the scriptPubKey: " + x)) + "Cannot create a address for the scriptPubKey: " + x + ) + ) } } @@ -588,14 +651,16 @@ object Address extends AddressFactory[Address] { override def fromScriptPubKeyT( spk: ScriptPubKey, - network: NetworkParameters): Try[Address] = + network: NetworkParameters + ): Try[Address] = network match { case _: BitcoinNetwork => BitcoinAddress.fromScriptPubKeyT(spk, network) } def apply( spk: ScriptPubKey, - networkParameters: NetworkParameters): Try[Address] = { + networkParameters: NetworkParameters + ): Try[Address] = { fromScriptPubKeyT(spk, networkParameters) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/AddressFactory.scala b/core/src/main/scala/org/bitcoins/core/protocol/AddressFactory.scala index daea35265b..b1474fc25f 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/AddressFactory.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/AddressFactory.scala @@ -19,14 +19,16 @@ abstract class AddressFactory[T <: Address] extends StringFactory[T] { } } - /** Attempts to create a address from the given [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] - * and [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] + /** Attempts to create a address from the given + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] and + * [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] */ def fromScriptPubKeyT(spk: ScriptPubKey, np: NetworkParameters): Try[T] def fromScriptPubKeyOpt( spk: ScriptPubKey, - np: NetworkParameters): Option[T] = { + np: NetworkParameters + ): Option[T] = { fromScriptPubKeyT(spk, np).toOption } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/BigSizeUInt.scala b/core/src/main/scala/org/bitcoins/core/protocol/BigSizeUInt.scala index cc8fb8a585..8d18f52fc4 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/BigSizeUInt.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/BigSizeUInt.scala @@ -22,8 +22,10 @@ case class BigSizeUInt(num: UInt64) extends NetworkElement { def toInt: Int = { val l = toLong - require(Int.MinValue <= l && l <= Int.MaxValue, - "Cannot convert BigSizeUInt toInt, got: " + this) + require( + Int.MinValue <= l && l <= Int.MaxValue, + "Cannot convert BigSizeUInt toInt, got: " + this + ) l.toInt } @@ -69,7 +71,8 @@ object BigSizeUInt extends Factory[BigSizeUInt] { require( bigSizeUInt.byteSize == expectedSize, - s"Length prefix $prefixNum did not match bytes ${bigSizeUInt.bytes.tail}") + s"Length prefix $prefixNum did not match bytes ${bigSizeUInt.bytes.tail}" + ) bigSizeUInt } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/BlockStamp.scala b/core/src/main/scala/org/bitcoins/core/protocol/BlockStamp.scala index b99dba44e0..2016c98963 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/BlockStamp.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/BlockStamp.scala @@ -11,12 +11,16 @@ import org.bitcoins.crypto.{DoubleSha256DigestBE, StringFactory} import scala.util.{Failure, Success, Try} -/** This trait represents a point on blockchain, and is used to specify block ranges */ +/** This trait represents a point on blockchain, and is used to specify block + * ranges + */ sealed trait BlockStamp { def mkString: String } -/** This trait represents a point in time on the blockchain, including future times */ +/** This trait represents a point in time on the blockchain, including future + * times + */ sealed trait BlockTimeStamp extends BlockStamp { def toUInt32: UInt32 def toScriptNumber: ScriptNumber @@ -78,7 +82,9 @@ object BlockStamp extends StringFactory[BlockStamp] { def apply(timeLockNumber: Int): BlockTimeStamp = fromUInt32(UInt32(timeLockNumber)) - /** @see [[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki#detailed-specification]] */ + /** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki#detailed-specification]] + */ def fromUInt32(uInt32: UInt32): BlockTimeStamp = { if (uInt32 < TransactionConstants.locktimeThreshold) { BlockHeight(uInt32.toInt) @@ -121,7 +127,9 @@ object BlockTimeStamp extends StringFactory[BlockTimeStamp] { def apply(timeLockNumber: Int): BlockTimeStamp = fromUInt32(UInt32(timeLockNumber)) - /** @see [[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki#detailed-specification]] */ + /** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki#detailed-specification]] + */ def fromUInt32(uInt32: UInt32): BlockTimeStamp = { if (uInt32 < TransactionConstants.locktimeThreshold) { BlockStamp.BlockHeight(uInt32.toInt) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/BtcHumanReadablePart.scala b/core/src/main/scala/org/bitcoins/core/protocol/BtcHumanReadablePart.scala index 2d5911674e..c843ddf942 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/BtcHumanReadablePart.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/BtcHumanReadablePart.scala @@ -27,9 +27,10 @@ object BtcHumanReadablePart extends StringFactory[BtcHumanReadablePart] { /** Represents the HumanReadablePart for a bitcoin regtest bech32 address * - * @see Regtest is not covered in the BIP. See - * [[https://github.com/bitcoin/bitcoin/issues/12314 this issue]] - * for more context. + * @see + * Regtest is not covered in the BIP. See + * [[https://github.com/bitcoin/bitcoin/issues/12314 this issue]] for more + * context. */ case object bcrt extends BtcHumanReadablePart { override def network: RegTest.type = RegTest @@ -43,7 +44,8 @@ object BtcHumanReadablePart extends StringFactory[BtcHumanReadablePart] { case "bcrt" => bcrt // Bitcoin Core specific case _ => throw new IllegalArgumentException( - s"Could not construct BTC HRP from $str") + s"Could not construct BTC HRP from $str" + ) } def apply(network: NetworkParameters): BtcHumanReadablePart = diff --git a/core/src/main/scala/org/bitcoins/core/protocol/CompactSizeUInt.scala b/core/src/main/scala/org/bitcoins/core/protocol/CompactSizeUInt.scala index f4ac4ddd44..0c97e7759b 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/CompactSizeUInt.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/CompactSizeUInt.scala @@ -8,7 +8,8 @@ import scodec.bits.ByteVector /** Compact sized unsigned integer, a Bitcoin-native data structure * - * @see https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers + * @see + * https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers */ sealed abstract class CompactSizeUInt extends NetworkElement { @@ -28,8 +29,10 @@ sealed abstract class CompactSizeUInt extends NetworkElement { def toInt: Int = { val l = toLong - require(Int.MinValue <= l && l <= Int.MaxValue, - "Cannot convert CompactSizeUInt toInt, got: " + this) + require( + Int.MinValue <= l && l <= Int.MaxValue, + "Cannot convert CompactSizeUInt toInt, got: " + this + ) l.toInt } @@ -40,8 +43,8 @@ object CompactSizeUInt extends Factory[CompactSizeUInt] { private case class CompactSizeUIntImpl( num: UInt64, - override val byteSize: Long) - extends CompactSizeUInt + override val byteSize: Long + ) extends CompactSizeUInt val zero: CompactSizeUInt = CompactSizeUInt(UInt64.zero) @@ -64,21 +67,21 @@ object CompactSizeUInt extends Factory[CompactSizeUInt] { if (num.toBigInt <= 252) 1 // can be represented with two bytes else if (num.toBigInt <= 65535) 3 - //can be represented with 4 bytes + // can be represented with 4 bytes else if (num.toBigInt <= UInt32.max.toBigInt) 5 else 9 } - /** This function is responsible for calculating what the compact size unsigned integer is for a - * sequence of bytes + /** This function is responsible for calculating what the compact size + * unsigned integer is for a sequence of bytes * https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers. */ def calculateCompactSizeUInt(bytes: ByteVector): CompactSizeUInt = { - //means we can represent the number with a single byte + // means we can represent the number with a single byte if (bytes.size <= 252) CompactSizeUInt(UInt64(bytes.size), 1) // can be represented with two bytes else if (bytes.size <= 65535) CompactSizeUInt(UInt64(bytes.size), 3) - //can be represented with 4 bytes + // can be represented with 4 bytes else if (bytes.size <= UInt32.max.toBigInt) CompactSizeUInt(UInt64(bytes.size), 5) else CompactSizeUInt(UInt64(bytes.size), 9) @@ -87,7 +90,8 @@ object CompactSizeUInt extends Factory[CompactSizeUInt] { def calc(bytes: ByteVector): CompactSizeUInt = calculateCompactSizeUInt(bytes) /** Responsible for calculating what the - * [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] is for this hex string. + * [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] is for this + * hex string. */ def calculateCompactSizeUInt(hex: String): CompactSizeUInt = calculateCompactSizeUInt(BytesUtil.decodeHex(hex)) @@ -98,22 +102,23 @@ object CompactSizeUInt extends Factory[CompactSizeUInt] { def parseCompactSizeUInt(hex: String): CompactSizeUInt = parseCompactSizeUInt(BytesUtil.decodeHex(hex)) - /** Parses a [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] from a sequence of bytes + /** Parses a [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] + * from a sequence of bytes * [[https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers]] */ def parseCompactSizeUInt(bytes: ByteVector): CompactSizeUInt = { require(bytes.nonEmpty, "Cannot parse a VarInt if the byte array is size 0") val firstByte = UInt64(ByteVector(bytes.head)) - //8 bit number + // 8 bit number if (firstByte.toInt < 253) CompactSizeUInt(firstByte, 1) - //16 bit number + // 16 bit number else if (firstByte.toInt == 253) CompactSizeUInt(UInt64(bytes.slice(1, 3).reverse), 3) - //32 bit number + // 32 bit number else if (firstByte.toInt == 254) CompactSizeUInt(UInt64(bytes.slice(1, 5).reverse), 5) - //64 bit number + // 64 bit number else CompactSizeUInt(UInt64(bytes.slice(1, 9).reverse), 9) } @@ -123,17 +128,18 @@ object CompactSizeUInt extends Factory[CompactSizeUInt] { * https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer. */ def parseCompactSizeUIntSize(byte: Byte): Long = { - //8 bit number + // 8 bit number if (parseLong(byte) < 253) 1 - //16 bit number + // 16 bit number else if (parseLong(byte) == 253) 3 - //32 bit number + // 32 bit number else if (parseLong(byte) == 254) 5 - //64 bit number + // 64 bit number else 9 } - /** Parses the [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] from a + /** Parses the [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] + * from a * [[org.bitcoins.core.protocol.script.ScriptSignature ScriptSignature]]. * https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers. */ diff --git a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/Block.scala b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/Block.scala index 5dbcad07c1..b7559115ca 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/Block.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/Block.scala @@ -7,9 +7,8 @@ import org.bitcoins.core.serializers.blockchain.RawBlockSerializer import org.bitcoins.crypto.{Factory, NetworkElement} import scodec.bits.ByteVector -/** Created by chris on 5/19/16. - * Represents a block in our blockchain - * Bitcoin Core implementation: +/** Created by chris on 5/19/16. Represents a block in our blockchain Bitcoin + * Core implementation: * [[https://github.com/bitcoin/bitcoin/blob/master/src/primitives/block.h#L73]] * Bitcoin Developer Reference link: * [[https://bitcoin.org/en/developer-reference#serialized-blocks]] @@ -19,8 +18,8 @@ sealed abstract class Block extends NetworkElement { /** The block header for this block */ def blockHeader: BlockHeader - /** The total number of transactions in this block, - * including the coinbase transaction. + /** The total number of transactions in this block, including the coinbase + * transaction. */ def txCount: CompactSizeUInt @@ -29,13 +28,16 @@ sealed abstract class Block extends NetworkElement { override def bytes = RawBlockSerializer.write(this) - /** This is the new computation to determine the maximum size of a block as per BIP141 + /** This is the new computation to determine the maximum size of a block as + * per BIP141 * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#block-size]] * The weight of a block is determined as follows: * - * Base size is the block size in bytes with the original transaction serialization without any witness-related data + * Base size is the block size in bytes with the original transaction + * serialization without any witness-related data * - * Total size is the block size in bytes with transactions serialized as described in BIP144, including base data and witness data. + * Total size is the block size in bytes with transactions serialized as + * described in BIP144, including base data and witness data. * * Block weight is defined as Base size * 3 + Total size * [[https://github.com/bitcoin/bitcoin/blob/7490ae8b699d2955b665cf849d86ff5bb5245c28/src/primitives/block.cpp#L35]] @@ -50,8 +52,8 @@ object Block extends Factory[Block] { private case class BlockImpl( blockHeader: BlockHeader, txCount: CompactSizeUInt, - transactions: Seq[Transaction]) - extends Block { + transactions: Seq[Transaction] + ) extends Block { override def toString: String = { s"Block(blockHeader=${blockHeader}, txCount=${txCount.toLong})" @@ -61,7 +63,8 @@ object Block extends Factory[Block] { def apply( blockHeader: BlockHeader, txCount: CompactSizeUInt, - transactions: Seq[Transaction]): Block = { + transactions: Seq[Transaction] + ): Block = { BlockImpl(blockHeader, txCount, transactions) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/BlockHeader.scala b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/BlockHeader.scala index cac90740ef..e67e847ff9 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/BlockHeader.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/BlockHeader.scala @@ -6,104 +6,123 @@ import org.bitcoins.core.util.NumberUtil import org.bitcoins.crypto._ import scodec.bits.ByteVector -/** Nodes collect new transactions into a block, hash them into a hash tree, - * and scan through nonce values to make the block's hash satisfy proof-of-work - * requirements. When they solve the proof-of-work, they broadcast the block - * to everyone and the block is added to the block chain. The first transaction - * in the block is a special one that creates a new coin owned by the creator - * of the block. - * @see Bitcoin Developer reference: - * https://bitcoin.org/en/developer-reference#block-headers +/** Nodes collect new transactions into a block, hash them into a hash tree, and + * scan through nonce values to make the block's hash satisfy proof-of-work + * requirements. When they solve the proof-of-work, they broadcast the block to + * everyone and the block is added to the block chain. The first transaction in + * the block is a special one that creates a new coin owned by the creator of + * the block. + * @see + * Bitcoin Developer reference: + * https://bitcoin.org/en/developer-reference#block-headers * - * @see Bitcoin Core implementation: - * https://github.com/bitcoin/bitcoin/blob/master/src/primitives/block.h#L20 + * @see + * Bitcoin Core implementation: + * https://github.com/bitcoin/bitcoin/blob/master/src/primitives/block.h#L20 */ sealed trait BlockHeader extends NetworkElement { - /** The block version number indicates which set of block validation rules to follow. - * See the list of block versions below. + /** The block version number indicates which set of block validation rules to + * follow. See the list of block versions below. * - * @see BIP9 for more information on what version number signify - * https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki + * @see + * BIP9 for more information on what version number signify + * https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki * - * @return the version number for this block + * @return + * the version number for this block */ def version: Int32 - /** A SHA256(SHA256()) hash in internal byte order of the previous block’s header. - * This ensures no previous block can be changed without also changing this block’s header. + /** A SHA256(SHA256()) hash in internal byte order of the previous block’s + * header. This ensures no previous block can be changed without also + * changing this block’s header. * - * @return the previous block's hash + * @return + * the previous block's hash */ def previousBlockHash: DoubleSha256Digest - /** Returns the big endian encoding of the previous block hash - * This is useful for using rpc and block exporers, but is NOT used in the protocol itself + /** Returns the big endian encoding of the previous block hash This is useful + * for using rpc and block exporers, but is NOT used in the protocol itself * - * @see see this Stack Exchange question for more: - * [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]] + * @see + * see this Stack Exchange question for more: + * [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]] */ def previousBlockHashBE: DoubleSha256DigestBE = previousBlockHash.flip - /** A `SHA256(SHA256())` hash in internal byte order. - * The merkle root is derived from the hashes of all transactions included in this block, - * ensuring that none of those transactions can be modified without modifying the header. + /** A `SHA256(SHA256())` hash in internal byte order. The merkle root is + * derived from the hashes of all transactions included in this block, + * ensuring that none of those transactions can be modified without modifying + * the header. * - * @see https://bitcoin.org/en/developer-reference#merkle-trees + * @see + * https://bitcoin.org/en/developer-reference#merkle-trees * - * @return the merkle root of the merkle tree + * @return + * the merkle root of the merkle tree */ def merkleRootHash: DoubleSha256Digest - /** Returns the merkle root hash in BIG ENDIAN format. This is not compatible with the bitcoin - * protocol but it is useful for rpc clients and block explorers + /** Returns the merkle root hash in BIG ENDIAN format. This is not compatible + * with the bitcoin protocol but it is useful for rpc clients and block + * explorers * - * @see this link for more info - * [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]] + * @see + * this link for more info + * [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]] */ def merkleRootHashBE: DoubleSha256DigestBE = merkleRootHash.flip - /** The block time is a Unix epoch time when the miner started hashing the header (according to the miner). - * Must be greater than or equal to the median time of the previous 11 blocks. - * Full nodes will not accept blocks with headers more than two hours in the future according to their clock. + /** The block time is a Unix epoch time when the miner started hashing the + * header (according to the miner). Must be greater than or equal to the + * median time of the previous 11 blocks. Full nodes will not accept blocks + * with headers more than two hours in the future according to their clock. * - * @return the time when the miner started solving the block + * @return + * the time when the miner started solving the block */ def time: UInt32 - /** An encoded version of the target threshold this block’s header hash must be less than or equal to. + /** An encoded version of the target threshold this block’s header hash must + * be less than or equal to. * - * @see See the nBits format described below. - * https://bitcoin.org/en/developer-reference#target-nbits + * @see + * See the nBits format described below. + * https://bitcoin.org/en/developer-reference#target-nbits */ def nBits: UInt32 - /** This is the decoded version of [[nBits]]. nBits is used to compactly represent the difficulty - * target for the bitcoin network. This field is the expanded version that is the _actual_ - * requirement needed for the network. This is a 256 bit unsigned integer - * See the bitcoin developer reference for more information on how this is constructed + /** This is the decoded version of [[nBits]]. nBits is used to compactly + * represent the difficulty target for the bitcoin network. This field is the + * expanded version that is the _actual_ requirement needed for the network. + * This is a 256 bit unsigned integer See the bitcoin developer reference for + * more information on how this is constructed * [[https://bitcoin.org/en/developer-reference#target-nbits documentation]] * - * The hash of this block needs to be _less than_ this difficulty - * to be considered a valid block on the network + * The hash of this block needs to be _less than_ this difficulty to be + * considered a valid block on the network */ def difficulty: BigInt = { NumberUtil.targetExpansion(nBits = nBits).difficulty } - /** An arbitrary number miners change to modify the header hash in order to produce a hash below the target threshold. - * If all 32-bit values are tested, the time can be updated or the coinbase - * transaction can be changed and the merkle root updated. + /** An arbitrary number miners change to modify the header hash in order to + * produce a hash below the target threshold. If all 32-bit values are + * tested, the time can be updated or the coinbase transaction can be changed + * and the merkle root updated. * - * @return the nonce used to try and solve a block + * @return + * the nonce used to try and solve a block */ def nonce: UInt32 /** Returns the block's hash in the protocol level little endian encoding */ lazy val hash: DoubleSha256Digest = CryptoUtil.doubleSHA256(bytes) - /** Returns the block hash in big endian format, this is useful for rpc - * and block explorer debugging. This is *not* used in the core protocol itself. + /** Returns the block hash in big endian format, this is useful for rpc and + * block explorer debugging. This is *not* used in the core protocol itself. * See this link for more info * [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]] * @return @@ -130,8 +149,8 @@ object BlockHeader extends Factory[BlockHeader] { merkleRootHash: DoubleSha256Digest, time: UInt32, nBits: UInt32, - nonce: UInt32) - extends BlockHeader + nonce: UInt32 + ) extends BlockHeader def apply( version: Int32, @@ -139,22 +158,26 @@ object BlockHeader extends Factory[BlockHeader] { merkleRootHash: DoubleSha256Digest, time: UInt32, nBits: UInt32, - nonce: UInt32): BlockHeader = { - BlockHeaderImpl(version, - previousBlockHash, - merkleRootHash, - time, - nBits, - nonce) + nonce: UInt32 + ): BlockHeader = { + BlockHeaderImpl( + version, + previousBlockHash, + merkleRootHash, + time, + nBits, + nonce + ) } def fromBytes(bytes: ByteVector): BlockHeader = RawBlockHeaderSerializer.read(bytes) - /** Return type used to carry around extra information - * about the difficulty required to mine a block. Unfortunately - * there is weird corner cases like it being an overflow or negative - * which is returned by [[https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.cpp#L206 arith_uint256#SetCompact()]] in bitcoin core + /** Return type used to carry around extra information about the difficulty + * required to mine a block. Unfortunately there is weird corner cases like + * it being an overflow or negative which is returned by + * [[https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.cpp#L206 arith_uint256#SetCompact()]] + * in bitcoin core * @param difficulty * @param isNegative * @param isOverflow @@ -162,7 +185,8 @@ object BlockHeader extends Factory[BlockHeader] { case class TargetDifficultyHelper( difficulty: BigInt, isNegative: Boolean, - isOverflow: Boolean) + isOverflow: Boolean + ) def getBlockProof(header: BlockHeader): BigInt = { val target = NumberUtil.targetExpansion(header.nBits) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala index 3a6389caaf..a2c7d59a43 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/ChainParams.scala @@ -21,96 +21,129 @@ import scodec.bits.{ByteVector, _} import scala.concurrent.duration.{Duration, DurationInt} -/** Created by chris on 5/22/16. - * `ChainParams` defines various tweakable parameters of a given instance of the - * Bitcoin system. There are three: the main network on which people trade goods - * and services, the public test network which gets reset from time to time and - * a regression test mode which is intended for private networks only. It has - * minimal difficulty to ensure that blocks can be found instantly. - * @see Mimics - * [[https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.h#L42 this C++ interface]] - * in Bitcoin Core +/** Created by chris on 5/22/16. `ChainParams` defines various tweakable + * parameters of a given instance of the Bitcoin system. There are three: the + * main network on which people trade goods and services, the public test + * network which gets reset from time to time and a regression test mode which + * is intended for private networks only. It has minimal difficulty to ensure + * that blocks can be found instantly. + * @see + * Mimics + * [[https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.h#L42 this C++ interface]] + * in Bitcoin Core */ sealed abstract class ChainParams { /** Return the BIP70 network string ( * [[org.bitcoins.core.protocol.blockchain.MainNetChainParams MainNetChainParams]], - * [[org.bitcoins.core.protocol.blockchain.MainNetChainParams TestNetChainParams]] or - * [[org.bitcoins.core.protocol.blockchain.MainNetChainParams RegTestNetChainParams]].) + * [[org.bitcoins.core.protocol.blockchain.MainNetChainParams TestNetChainParams]] + * or + * [[org.bitcoins.core.protocol.blockchain.MainNetChainParams RegTestNetChainParams]].) * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki BIP70]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki BIP70]] */ def networkId: String - /** The Genesis [[org.bitcoins.core.protocol.blockchain.Block Block]] in the blockchain. */ + /** The Genesis [[org.bitcoins.core.protocol.blockchain.Block Block]] in the + * blockchain. + */ def genesisBlock: Block def genesisHash: DoubleSha256Digest = genesisBlock.blockHeader.hash def genesisHashBE: DoubleSha256DigestBE = genesisHash.flip - /** Filter transactions that do not match well-defined patterns - * inside of [[org.bitcoins.core.policy.Policy Policy]]. + /** Filter transactions that do not match well-defined patterns inside of + * [[org.bitcoins.core.policy.Policy Policy]]. */ def requireStandardTransaction: Boolean = true - /** Takes in a [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] and returns its base58 prefix. */ + /** Takes in a [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] + * and returns its base58 prefix. + */ def base58Prefix(base58: Base58Type): ByteVector = base58Prefixes(base58) - /** The mapping from a [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]]to a String. - * Base58 prefixes for various keys/hashes on the network. + /** The mapping from a + * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]]to a + * String. Base58 prefixes for various keys/hashes on the network. * - * @see Bitcoin wiki - * [[https://en.bitcoin.it/wiki/List_of_address_prefixes article]] - * on address prefixes + * @see + * Bitcoin wiki + * [[https://en.bitcoin.it/wiki/List_of_address_prefixes article]] on + * address prefixes */ def base58Prefixes: Map[Base58Type, ByteVector] - /** Creates the Genesis [[org.bitcoins.core.protocol.blockchain.Block Block]] for this blockchain. + /** Creates the Genesis [[org.bitcoins.core.protocol.blockchain.Block Block]] + * for this blockchain. * - * @see Mimics - * [[https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.cpp#L51 this function]] - * in Bitcoin Core + * @see + * Mimics + * [[https://github.com/bitcoin/bitcoin/blob/master/src/chainparams.cpp#L51 this function]] + * in Bitcoin Core * - * @param time the time when the miner started hashing the block header - * @param nonce the nonce to mine the block - * @param nBits An encoded version of the target threshold this block’s header hash must be less than or equal to. - * @param version the block version - * @param amount the block reward for the genesis block (50 BTC in Bitcoin) - * @return the newly minted genesis block + * @param time + * the time when the miner started hashing the block header + * @param nonce + * the nonce to mine the block + * @param nBits + * An encoded version of the target threshold this block’s header hash must + * be less than or equal to. + * @param version + * the block version + * @param amount + * the block reward for the genesis block (50 BTC in Bitcoin) + * @return + * the newly minted genesis block */ def createGenesisBlock( time: UInt32, nonce: UInt32, nBits: UInt32, version: Int32, - amount: CurrencyUnit): Block = { + amount: CurrencyUnit + ): Block = { val timestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks" val asm = Seq( BytesToPushOntoStack(65), ScriptConstant( - "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"), + "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f" + ), OP_CHECKSIG ) val genesisOutputScript = ScriptPubKey.fromAsm(asm) - createGenesisBlock(timestamp, - genesisOutputScript, - time, - nonce, - nBits, - version, - amount) + createGenesisBlock( + timestamp, + genesisOutputScript, + time, + nonce, + nBits, + version, + amount + ) } - /** @param timestamp a piece of data to signify when this block was first created - satoshi used an article headline - * @param scriptPubKey the scriptPubKey that needs to be satisfied in able to spend the genesis block reward - * @param time the time when the miner started hashing the block header - * @param nonce the nonce used to mine the block - * @param nBits An encoded version of the target threshold this block's header hash must be less than or equal to - * @param version the block version - * @param amount the block reward for the genesis block (50 BTC in Bitcoin) - * @return the newly minted genesis block + /** @param timestamp + * a piece of data to signify when this block was first created - satoshi + * used an article headline + * @param scriptPubKey + * the scriptPubKey that needs to be satisfied in able to spend the genesis + * block reward + * @param time + * the time when the miner started hashing the block header + * @param nonce + * the nonce used to mine the block + * @param nBits + * An encoded version of the target threshold this block's header hash must + * be less than or equal to + * @param version + * the block version + * @param amount + * the block reward for the genesis block (50 BTC in Bitcoin) + * @return + * the newly minted genesis block */ def createGenesisBlock( timestamp: String, @@ -119,17 +152,20 @@ sealed abstract class ChainParams { nonce: UInt32, nBits: UInt32, version: Int32, - amount: CurrencyUnit): Block = { + amount: CurrencyUnit + ): Block = { val timestampBytes = ByteVector(timestamp.getBytes(StandardCharsets.UTF_8)) - //see https://bitcoin.stackexchange.com/questions/13122/scriptsig-coinbase-structure-of-the-genesis-block - //for a full breakdown of the genesis block & its script signature + // see https://bitcoin.stackexchange.com/questions/13122/scriptsig-coinbase-structure-of-the-genesis-block + // for a full breakdown of the genesis block & its script signature val const = ScriptConstant(timestampBytes) val asm = { - List(BytesToPushOntoStack(4), - ScriptConstant("ffff001d"), - BytesToPushOntoStack(1), - ScriptConstant("04")) ++ + List( + BytesToPushOntoStack(4), + ScriptConstant("ffff001d"), + BytesToPushOntoStack(1), + ScriptConstant("04") + ) ++ BitcoinScriptUtil.calculatePushOp(const) ++ List(const) } @@ -138,12 +174,15 @@ sealed abstract class ChainParams { val input = CoinbaseInput(scriptSignature, TransactionConstants.sequence) val output = TransactionOutput(amount, scriptPubKey) - val tx = BaseTransaction(TransactionConstants.version, - Seq(input), - Seq(output), - TransactionConstants.lockTime) + val tx = BaseTransaction( + TransactionConstants.version, + Seq(input), + Seq(output), + TransactionConstants.lockTime + ) val prevBlockHash = DoubleSha256Digest( - "0000000000000000000000000000000000000000000000000000000000000000") + "0000000000000000000000000000000000000000000000000000000000000000" + ) val merkleRootHash = Merkle.computeMerkleRoot(Seq(tx)) val genesisBlockHeader = BlockHeader(version, prevBlockHash, merkleRootHash, time, nBits, nonce) @@ -157,14 +196,17 @@ sealed abstract class ChainParams { */ def powLimit: BigInteger - /** The minimum proof of required for a block as specified by [[org.bitcoins.core.protocol.blockchain.ChainParams.powLimit powLimit]], compressed to a UInt32 */ + /** The minimum proof of required for a block as specified by + * [[org.bitcoins.core.protocol.blockchain.ChainParams.powLimit powLimit]], + * compressed to a UInt32 + */ lazy val compressedPowLimit: UInt32 = { NumberUtil.targetCompression(bigInteger = powLimit, isNegative = false) } - /** The targetted timespan between difficulty adjustments - * As of this implementation, all of these are the same in bitcoin core + /** The targetted timespan between difficulty adjustments As of this + * implementation, all of these are the same in bitcoin core * * [[https://github.com/bitcoin/bitcoin/blob/a083f75ba79d465f15fddba7b00ca02e31bb3d40/src/chainparams.cpp#L73 mainnet]] * [[https://github.com/bitcoin/bitcoin/blob/a083f75ba79d465f15fddba7b00ca02e31bb3d40/src/chainparams.cpp#L190 testnet]] @@ -180,23 +222,24 @@ sealed abstract class ChainParams { */ def powTargetSpacing: Duration - /** In bitcoin [[MainNetChainParams mainnet]], the network recalculates the difficulty for the network every 2016 blocks + /** In bitcoin [[MainNetChainParams mainnet]], the network recalculates the + * difficulty for the network every 2016 blocks * [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/consensus/params.h#L75 bitcoin core implementation]] */ def difficultyChangeInterval: Int = { (powTargetTimeSpan.toSeconds / powTargetSpacing.toSeconds).toInt } - /** Whether we should allow minimum difficulty blocks or not - * As an example you can trivially mine blocks on [[RegTestNetChainParams]] and [[TestNetChainParams]] - * but not the [[MainNetChainParams]] + /** Whether we should allow minimum difficulty blocks or not As an example you + * can trivially mine blocks on [[RegTestNetChainParams]] and + * [[TestNetChainParams]] but not the [[MainNetChainParams]] * @return */ def allowMinDifficultyBlocks: Boolean - /** Whether this chain supports - * proof of work retargeting or not - * @see [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/consensus/params.h#L72 link]] + /** Whether this chain supports proof of work retargeting or not + * @see + * [[https://github.com/bitcoin/bitcoin/blob/eb7daf4d600eeb631427c018a984a77a34aca66e/src/consensus/params.h#L72 link]] * @return */ def noRetargeting: Boolean @@ -204,10 +247,14 @@ sealed abstract class ChainParams { /** Uses signet blocks that require checking the signet challenge */ def signetBlocks: Boolean - /** Blocks must satisfy the given script to be considered valid (only for signet networks) */ + /** Blocks must satisfy the given script to be considered valid (only for + * signet networks) + */ def signetChallenge: ScriptPubKey - /** The [[org.bitcoins.core.config.BitcoinNetwork network]] that corresponds to this chain param */ + /** The [[org.bitcoins.core.config.BitcoinNetwork network]] that corresponds + * to this chain param + */ def network: NetworkParameters } @@ -222,7 +269,7 @@ sealed abstract class BitcoinChainParams extends ChainParams { /** @inheritdoc */ override lazy val powTargetSpacing: Duration = { - val time = 10 * 60 //10 minutes * 60 seconds + val time = 10 * 60 // 10 minutes * 60 seconds time.seconds } @@ -240,11 +287,13 @@ object MainNetChainParams extends BitcoinChainParams { override lazy val networkId = "main" override lazy val genesisBlock: Block = - createGenesisBlock(UInt32(1231006505), - UInt32(2083236893), - UInt32(0x1d00ffff), - Int32.one, - Satoshis(5000000000L)) + createGenesisBlock( + UInt32(1231006505), + UInt32(2083236893), + UInt32(0x1d00ffff), + Int32.one, + Satoshis(5000000000L) + ) override lazy val base58Prefixes: Map[Base58Type, ByteVector] = Map( @@ -302,11 +351,13 @@ object TestNetChainParams extends BitcoinChainParams { override lazy val networkId = "test" override lazy val genesisBlock: Block = - createGenesisBlock(UInt32(1296688602), - UInt32(414098458), - UInt32(0x1d00ffff), - Int32.one, - Satoshis(5000000000L)) + createGenesisBlock( + UInt32(1296688602), + UInt32(414098458), + UInt32(0x1d00ffff), + Int32.one, + Satoshis(5000000000L) + ) override lazy val base58Prefixes: Map[Base58Type, ByteVector] = Map( @@ -356,11 +407,13 @@ object RegTestNetChainParams extends BitcoinChainParams { override lazy val networkId = "regtest" override lazy val genesisBlock: Block = - createGenesisBlock(time = UInt32(1296688602), - nonce = UInt32(2), - nBits = UInt32(0x207fffff), - version = Int32.one, - amount = Satoshis(5000000000L)) + createGenesisBlock( + time = UInt32(1296688602), + nonce = UInt32(2), + nBits = UInt32(0x207fffff), + version = Int32.one, + amount = Satoshis(5000000000L) + ) override lazy val base58Prefixes: Map[Base58Type, ByteVector] = TestNetChainParams.base58Prefixes @@ -399,30 +452,39 @@ object RegTestNetChainParams extends BitcoinChainParams { /** Uses signet blocks that require checking the signet challenge */ override def signetBlocks: Boolean = false - /** Blocks must satisfy the given script to be considered valid (only for signet networks) */ + /** Blocks must satisfy the given script to be considered valid (only for + * signet networks) + */ override def signetChallenge: ScriptPubKey = EmptyScriptPubKey } case class SigNetChainParams( signetChallenge: ScriptPubKey = ScriptPubKey.fromAsmHex( - "512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae")) - extends BitcoinChainParams { + "512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae" + ) +) extends BitcoinChainParams { override lazy val networkId = "signet" override lazy val genesisBlock: Block = - createGenesisBlock(UInt32(1598918400), - UInt32(52613770), - UInt32(0x1e0377ae), - Int32.one, - Bitcoins(50)) + createGenesisBlock( + UInt32(1598918400), + UInt32(52613770), + UInt32(0x1e0377ae), + Int32.one, + Bitcoins(50) + ) require( genesisBlock.blockHeader.hashBE == DoubleSha256DigestBE( - "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6")) + "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6" + ) + ) require( genesisBlock.blockHeader.merkleRootHashBE == DoubleSha256DigestBE( - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")) + "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" + ) + ) override lazy val base58Prefixes: Map[Base58Type, ByteVector] = Map( diff --git a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/MerkleBlock.scala b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/MerkleBlock.scala index eab3c4ea6d..e2bc210f59 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/MerkleBlock.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/MerkleBlock.scala @@ -23,10 +23,15 @@ sealed abstract class MerkleBlock extends NetworkElement { /** The amount of hashes inside of the merkle block */ def hashCount: CompactSizeUInt = CompactSizeUInt(UInt64(hashes.size)) - /** One or more hashes of both transactions and merkle nodes used to build the partial merkle tree */ + /** One or more hashes of both transactions and merkle nodes used to build the + * partial merkle tree + */ def hashes: Seq[DoubleSha256Digest] = partialMerkleTree.hashes - /** The [[org.bitcoins.core.protocol.blockchain.PartialMerkleTree PartialMerkleTree]] for this merkle block */ + /** The + * [[org.bitcoins.core.protocol.blockchain.PartialMerkleTree PartialMerkleTree]] + * for this merkle block + */ def partialMerkleTree: PartialMerkleTree def bytes = RawMerkleBlockSerializer.write(this) @@ -37,26 +42,32 @@ object MerkleBlock extends Factory[MerkleBlock] { private case class MerkleBlockImpl( blockHeader: BlockHeader, transactionCount: UInt32, - partialMerkleTree: PartialMerkleTree) - extends MerkleBlock + partialMerkleTree: PartialMerkleTree + ) extends MerkleBlock - /** Creates a [[org.bitcoins.core.protocol.blockchain.MerkleBlock MerkleBlock]] from the given - * [[org.bitcoins.core.protocol.blockchain.Block Block]] and [[org.bitcoins.core.bloom.BloomFilter BloomFilter]] - * This function iterates through each transaction inside our block checking if it is relevant to the given bloom filter - * If it is relevant, it will set a flag to indicate we should include it inside of our + /** Creates a + * [[org.bitcoins.core.protocol.blockchain.MerkleBlock MerkleBlock]] from the + * given [[org.bitcoins.core.protocol.blockchain.Block Block]] and + * [[org.bitcoins.core.bloom.BloomFilter BloomFilter]] This function iterates + * through each transaction inside our block checking if it is relevant to + * the given bloom filter If it is relevant, it will set a flag to indicate + * we should include it inside of our * [[org.bitcoins.core.protocol.blockchain.PartialMerkleTree PartialMerkleTree]]. - * @param block the block that we searching for transactions that match the bloom filter - * @param filter the filter we are comparing transactions in the block against - * @return the merkle block and the bloom filter loaded with information from the relevant txs in the block + * @param block + * the block that we searching for transactions that match the bloom filter + * @param filter + * the filter we are comparing transactions in the block against + * @return + * the merkle block and the bloom filter loaded with information from the + * relevant txs in the block */ def apply(block: Block, filter: BloomFilter): (MerkleBlock, BloomFilter) = { @tailrec def loop( remainingTxs: Seq[Transaction], accumFilter: BloomFilter, - txMatches: Seq[(Boolean, DoubleSha256Digest)]): ( - Seq[(Boolean, DoubleSha256Digest)], - BloomFilter) = { + txMatches: Seq[(Boolean, DoubleSha256Digest)] + ): (Seq[(Boolean, DoubleSha256Digest)], BloomFilter) = { if (remainingTxs.isEmpty) (txMatches.reverse, accumFilter) else { val tx = remainingTxs.head @@ -71,15 +82,17 @@ object MerkleBlock extends Factory[MerkleBlock] { (MerkleBlock(block.blockHeader, txCount, partialMerkleTree), newFilter) } - /** Creates a merkle block that matches the given txids if they appear inside the given block */ + /** Creates a merkle block that matches the given txids if they appear inside + * the given block + */ def apply(block: Block, txIds: Seq[DoubleSha256Digest]): MerkleBlock = { - //follows this function inside of bitcoin core - //https://github.com/bitcoin/bitcoin/blob/master/src/merkleblock.cpp#L40 + // follows this function inside of bitcoin core + // https://github.com/bitcoin/bitcoin/blob/master/src/merkleblock.cpp#L40 @tailrec def loop( remainingTxs: Seq[Transaction], - txMatches: Seq[(Boolean, DoubleSha256Digest)]): ( - Seq[(Boolean, DoubleSha256Digest)]) = { + txMatches: Seq[(Boolean, DoubleSha256Digest)] + ): (Seq[(Boolean, DoubleSha256Digest)]) = { if (remainingTxs.isEmpty) txMatches.reverse else { val tx = remainingTxs.head @@ -98,7 +111,8 @@ object MerkleBlock extends Factory[MerkleBlock] { def apply( blockHeader: BlockHeader, txCount: UInt32, - partialMerkleTree: PartialMerkleTree): MerkleBlock = { + partialMerkleTree: PartialMerkleTree + ): MerkleBlock = { MerkleBlockImpl(blockHeader, txCount, partialMerkleTree) } @@ -106,7 +120,8 @@ object MerkleBlock extends Factory[MerkleBlock] { blockHeader: BlockHeader, txCount: UInt32, hashes: Seq[DoubleSha256Digest], - bits: BitVector): MerkleBlock = { + bits: BitVector + ): MerkleBlock = { val partialMerkleTree = PartialMerkleTree(txCount, hashes, bits) MerkleBlock(blockHeader, txCount, partialMerkleTree) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/PartialMerkleTree.scala b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/PartialMerkleTree.scala index f67c026f78..6c5ef6e87f 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/blockchain/PartialMerkleTree.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/blockchain/PartialMerkleTree.scala @@ -8,11 +8,10 @@ import scodec.bits.BitVector import scala.annotation.tailrec import scala.math._ -/** Created by chris on 8/7/16. - * Represents a subset of known txids inside of a [[org.bitcoins.core.protocol.blockchain.Block Block]] - * in a way that allows recovery of the txids & merkle root - * without having to store them all explicitly. - * See +/** Created by chris on 8/7/16. Represents a subset of known txids inside of a + * [[org.bitcoins.core.protocol.blockchain.Block Block]] in a way that allows + * recovery of the txids & merkle root without having to store them all + * explicitly. See * [[https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#partial-merkle-branch-format BIP37]] * for more details * @@ -20,11 +19,11 @@ import scala.math._ * [[https://bitcoin.org/en/developer-reference#creating-a-merkleblock-message "Bitcoin.org: creating a merkleblock message"]] * [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L78 "Bitcoin Core: merkleblock.cpp"]] * Traverse the tree in depth first order, storing a bit for each traversal. - * This bit signifies if the node is a parent of at least one - * matched leaf txid (or a matched leaf txid) itself. - * In case we are the leaf level, or this bit is 0, it's merkle - * node hash is stored and it's children are not explored any further. - * Otherwise no hash is stored, but we recurse all of this node's child branches. + * This bit signifies if the node is a parent of at least one matched leaf txid + * (or a matched leaf txid) itself. In case we are the leaf level, or this bit + * is 0, it's merkle node hash is stored and it's children are not explored any + * further. Otherwise no hash is stored, but we recurse all of this node's + * child branches. * * Decoding procedure: * [[https://bitcoin.org/en/developer-reference#parsing-a-merkleblock-message "Bitcoin.org: parsing a merkleblock message"]] @@ -46,58 +45,67 @@ sealed trait PartialMerkleTree { /** The actual tree used to represent this partial merkle tree */ def tree: BinaryTree[DoubleSha256Digest] - /** A sequence representing if this node is the parent of another node that matched a txid */ + /** A sequence representing if this node is the parent of another node that + * matched a txid + */ def bits: BitVector /** The hashes used to create the binary tree */ def hashes: Seq[DoubleSha256Digest] - /** Extracts the txids that were matched inside of the bloom filter used to create this partial merkle tree */ + /** Extracts the txids that were matched inside of the bloom filter used to + * create this partial merkle tree + */ def extractMatches: Seq[DoubleSha256Digest] = { - //TODO: This is some really ugly that isn't tail recursive, try to clean this up eventually + // TODO: This is some really ugly that isn't tail recursive, try to clean this up eventually def loop( subTree: BinaryTree[DoubleSha256Digest], remainingBits: BitVector, height: Int, pos: Int, - accumMatches: Seq[DoubleSha256Digest]): ( - Seq[DoubleSha256Digest], - BitVector) = { + accumMatches: Seq[DoubleSha256Digest] + ): (Seq[DoubleSha256Digest], BitVector) = { if (height == maxHeight) extractLeafMatch(accumMatches, remainingBits, subTree) else { - //means we have a nontxid node + // means we have a nontxid node if (remainingBits.head) { - //means we have a match underneath this node + // means we have a match underneath this node subTree match { case n: Node[DoubleSha256Digest] => - //since we are just trying to extract bloom filter matches, recurse into the two subtrees + // since we are just trying to extract bloom filter matches, recurse into the two subtrees val (leftTreeMatches, leftRemainingBits) = loop( n.l, remainingBits.tail, height + 1, (2 * pos), - accumMatches) - //check to see if we have a right subtree + accumMatches + ) + // check to see if we have a right subtree if ( - PartialMerkleTree.existsRightSubTree(pos, - numTransactions, - maxHeight, - height) + PartialMerkleTree.existsRightSubTree( + pos, + numTransactions, + maxHeight, + height + ) ) { val (rightTreeMatches, rightRemainingBits) = - loop(n.r, - leftRemainingBits, - height + 1, - (2 * pos) + 1, - leftTreeMatches) + loop( + n.r, + leftRemainingBits, + height + 1, + (2 * pos) + 1, + leftTreeMatches + ) (rightTreeMatches, rightRemainingBits) } else (leftTreeMatches, leftRemainingBits) case _: Leaf[DoubleSha256Digest] => (accumMatches, remainingBits.tail) case Empty => throw new IllegalArgumentException( - "We cannot have an empty node when we supposedly have a match underneath this node since it has no children") + "We cannot have an empty node when we supposedly have a match underneath this node since it has no children" + ) } } else (accumMatches, remainingBits.tail) } @@ -111,25 +119,28 @@ sealed trait PartialMerkleTree { matches.reverse } - /** Handles a leaf match when we are extracting matches from the partial merkle tree */ + /** Handles a leaf match when we are extracting matches from the partial + * merkle tree + */ private def extractLeafMatch( accumMatches: Seq[DoubleSha256Digest], remainingBits: BitVector, - subTree: BinaryTree[DoubleSha256Digest]): ( - Seq[DoubleSha256Digest], - BitVector) = { + subTree: BinaryTree[DoubleSha256Digest] + ): (Seq[DoubleSha256Digest], BitVector) = { if (remainingBits.head) { - //means we have a txid node that matched the filter + // means we have a txid node that matched the filter subTree match { case l: Leaf[DoubleSha256Digest] => val newAccumMatches = l.v +: accumMatches (newAccumMatches, remainingBits.tail) case x @ (_: Node[DoubleSha256Digest] | Empty) => - throw new IllegalArgumentException("We cannot have a " + - "Node or Empty node when we supposedly have a txid node -- txid nodes should always be leaves, got: " + x) + throw new IllegalArgumentException( + "We cannot have a " + + "Node or Empty node when we supposedly have a txid node -- txid nodes should always be leaves, got: " + x + ) } } else { - //means we have a txid node, but it did not match the filter + // means we have a txid node, but it did not match the filter (accumMatches, remainingBits.tail) } } @@ -141,80 +152,99 @@ object PartialMerkleTree { tree: BinaryTree[DoubleSha256Digest], transactionCount: UInt32, bits: BitVector, - hashes: Seq[DoubleSha256Digest]) - extends PartialMerkleTree { - require(bits.size % 8 == 0, - "As per BIP37, bits must be padded to the nearest byte") + hashes: Seq[DoubleSha256Digest] + ) extends PartialMerkleTree { + require( + bits.size % 8 == 0, + "As per BIP37, bits must be padded to the nearest byte" + ) } def apply( - txMatches: Seq[(Boolean, DoubleSha256Digest)]): PartialMerkleTree = { + txMatches: Seq[(Boolean, DoubleSha256Digest)] + ): PartialMerkleTree = { val txIds = txMatches.map(_._2) val (bits, hashes) = build(txMatches) val tree = reconstruct(txIds.size, hashes, bits) PartialMerkleTree(tree, UInt32(txIds.size), bits, hashes) } - /** @param txMatches indicates whether the given txid matches the bloom filter, the full merkle branch needs - * to be included inside of the - * [[org.bitcoins.core.protocol.blockchain.PartialMerkleTree PartialMerkleTree]] - * @return the binary tree that represents the partial merkle tree, the bits needed to reconstruct this partial - * merkle tree, and the hashes needed to be inserted - * according to the flags inside of bits + /** @param txMatches + * indicates whether the given txid matches the bloom filter, the full + * merkle branch needs to be included inside of the + * [[org.bitcoins.core.protocol.blockchain.PartialMerkleTree PartialMerkleTree]] + * @return + * the binary tree that represents the partial merkle tree, the bits needed + * to reconstruct this partial merkle tree, and the hashes needed to be + * inserted according to the flags inside of bits */ - private def build(txMatches: Seq[(Boolean, DoubleSha256Digest)]): ( - BitVector, - Seq[DoubleSha256Digest]) = { + private def build( + txMatches: Seq[(Boolean, DoubleSha256Digest)] + ): (BitVector, Seq[DoubleSha256Digest]) = { val maxHeight = calcMaxHeight(txMatches.size) - /** This loops through our merkle tree building `bits` so we can instruct another node how to create the partial merkle tree - * @see [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L78]] - * @param bits the accumulator for bits indicating how to reconsctruct the partial merkle tree - * @param hashes the relevant hashes used with bits to reconstruct the merkle tree - * @param height the transaction index we are currently looking at -- if it was matched in our bloom filter we need the entire merkle branch - * @param pos the position in the loop represented as an int - * @return the binary tree that represents the partial merkle tree, the bits needed to reconstruct this partial merkle tree, and the hashes needed to be inserted - * according to the flags inside of bits + /** This loops through our merkle tree building `bits` so we can instruct + * another node how to create the partial merkle tree + * @see + * [[https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L78]] + * @param bits + * the accumulator for bits indicating how to reconsctruct the partial + * merkle tree + * @param hashes + * the relevant hashes used with bits to reconstruct the merkle tree + * @param height + * the transaction index we are currently looking at -- if it was matched + * in our bloom filter we need the entire merkle branch + * @param pos + * the position in the loop represented as an int + * @return + * the binary tree that represents the partial merkle tree, the bits + * needed to reconstruct this partial merkle tree, and the hashes needed + * to be inserted according to the flags inside of bits */ def loop( bits: BitVector, hashes: Seq[DoubleSha256Digest], height: Int, - pos: Int): (BitVector, Seq[DoubleSha256Digest]) = { + pos: Int + ): (BitVector, Seq[DoubleSha256Digest]) = { val parentOfMatch = matchesTx(maxHeight, maxHeight - height, pos, txMatches) val newBits = parentOfMatch +: bits if (height == 0 || !parentOfMatch) { - //means that we are either at the root of the merkle tree or there is nothing interesting below - //this node in our binary tree + // means that we are either at the root of the merkle tree or there is nothing interesting below + // this node in our binary tree val nodeHash = calcHash(height, pos, txMatches.map(_._2)) val newHashes = nodeHash +: hashes (newBits, newHashes) } else { - //process the left node + // process the left node val (leftBits, leftHashes) = loop(newBits, hashes, height - 1, pos * 2) if (existsRightSubTree(pos, txMatches.size, height)) { - //process the right node if the tree's width is larger than the position we are looking at + // process the right node if the tree's width is larger than the position we are looking at loop(leftBits, leftHashes, height - 1, (pos * 2) + 1) } else (leftBits, leftHashes) } } val (bits, hashes) = loop(BitVector.empty, Nil, maxHeight, 0) - //pad the bit array to the nearest byte as required by BIP37 + // pad the bit array to the nearest byte as required by BIP37 val bitsNeeded = if (bits.size % 8 == 0) 0 else (8 - (bits.size % 8)) + bits.size val paddedBits = if (bitsNeeded == 0) bits else bits.padLeft(bitsNeeded) (paddedBits.reverse, hashes.reverse) } - /** Checks if a node at given the given height and position matches a transaction in the sequence */ + /** Checks if a node at given the given height and position matches a + * transaction in the sequence + */ def matchesTx( maxHeight: Int, height: Int, pos: Int, - matchedTx: Seq[(Boolean, DoubleSha256Digest)]): Boolean = { - //mimics this functionality inside of bitcoin core - //https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L78 + matchedTx: Seq[(Boolean, DoubleSha256Digest)] + ): Boolean = { + // mimics this functionality inside of bitcoin core + // https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L78 val inverseHeight = maxHeight - height @tailrec def loop(p: Int): Boolean = { @@ -235,10 +265,11 @@ object PartialMerkleTree { private def calcHash( height: Int, pos: Int, - txIds: Seq[DoubleSha256Digest]): DoubleSha256Digest = { - //TODO: Optimize this to tailrec function - //follows this function inside of bitcoin core - //https://github.com/bitcoin/bitcoin/blob/master/src/merkleblock.cpp#L63 + txIds: Seq[DoubleSha256Digest] + ): DoubleSha256Digest = { + // TODO: Optimize this to tailrec function + // follows this function inside of bitcoin core + // https://github.com/bitcoin/bitcoin/blob/master/src/merkleblock.cpp#L63 if (height == 0) txIds(pos) else { val leftHash = calcHash(height - 1, pos * 2, txIds) @@ -250,32 +281,42 @@ object PartialMerkleTree { } /** Function to reconstruct a partial merkle tree - * @param transactionCount the number of transactions inside of the partial merkle tree - * @param hashes the hashes used to reconstruct the partial merkle tree - * @param bits the bits used indicate the structure of the partial merkle tree + * @param transactionCount + * the number of transactions inside of the partial merkle tree + * @param hashes + * the hashes used to reconstruct the partial merkle tree + * @param bits + * the bits used indicate the structure of the partial merkle tree * @return */ def apply( transactionCount: UInt32, hashes: Seq[DoubleSha256Digest], - bits: BitVector): PartialMerkleTree = { + bits: BitVector + ): PartialMerkleTree = { val tree = reconstruct(transactionCount.toInt, hashes, bits) PartialMerkleTree(tree, transactionCount, bits, hashes) } - /** This constructor creates a partial from this given [[org.bitcoins.core.util.BinaryTree BinaryTree]] - * You probably don't want to use this constructor, unless you manually constructed `bits` and the `tree` - * by hand - * @param tree the partial merkle tree -- note this is NOT the full merkle tree - * @param transactionCount the number of transactions there initially was in the full merkle tree - * @param bits the path to the matches in the partial merkle tree - * @param hashes the hashes used to reconstruct the binary tree according to `bits` + /** This constructor creates a partial from this given + * [[org.bitcoins.core.util.BinaryTree BinaryTree]] You probably don't want + * to use this constructor, unless you manually constructed `bits` and the + * `tree` by hand + * @param tree + * the partial merkle tree -- note this is NOT the full merkle tree + * @param transactionCount + * the number of transactions there initially was in the full merkle tree + * @param bits + * the path to the matches in the partial merkle tree + * @param hashes + * the hashes used to reconstruct the binary tree according to `bits` */ def apply( tree: BinaryTree[DoubleSha256Digest], transactionCount: UInt32, bits: BitVector, - hashes: Seq[DoubleSha256Digest]): PartialMerkleTree = { + hashes: Seq[DoubleSha256Digest] + ): PartialMerkleTree = { PartialMerkleTreeImpl(tree, transactionCount, bits, hashes) } @@ -286,24 +327,25 @@ object PartialMerkleTree { private def reconstruct( numTransaction: Int, hashes: Seq[DoubleSha256Digest], - bits: BitVector): BinaryTree[DoubleSha256Digest] = { + bits: BitVector + ): BinaryTree[DoubleSha256Digest] = { val maxHeight = calcMaxHeight(numTransaction) - //TODO: Optimize to tailrec function + // TODO: Optimize to tailrec function def loop( remainingHashes: Seq[DoubleSha256Digest], remainingMatches: BitVector, height: Int, - pos: Int): ( - BinaryTree[DoubleSha256Digest], - Seq[DoubleSha256Digest], - BitVector) = { + pos: Int + ): (BinaryTree[DoubleSha256Digest], Seq[DoubleSha256Digest], BitVector) = { if (height == maxHeight) { - //means we have a txid node - (Leaf(remainingHashes.head), - remainingHashes.tail, - remainingMatches.tail) + // means we have a txid node + ( + Leaf(remainingHashes.head), + remainingHashes.tail, + remainingMatches.tail + ) } else { - //means we have a non txid node + // means we have a non txid node if (remainingMatches.head) { val nextHeight = height + 1 val leftNodePos = pos * 2 @@ -312,17 +354,20 @@ object PartialMerkleTree { remainingHashes, remainingMatches.tail, nextHeight, - leftNodePos) + leftNodePos + ) val (rightNode, rightRemainingHashes, rightRemainingBits) = { if (existsRightSubTree(pos, numTransaction, maxHeight, height)) { val (rightNode, rightRemainingHashes, rightRemainingBits) = - loop(leftRemainingHashes, - leftRemainingBits, - nextHeight, - rightNodePos) - //https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L121-L125 + loop( + leftRemainingHashes, + leftRemainingBits, + nextHeight, + rightNodePos + ) + // https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L121-L125 if (nextHeight != maxHeight) { - //we cannot the same two hashes as child nodes UNLESS we are the max height in the binary tree + // we cannot the same two hashes as child nodes UNLESS we are the max height in the binary tree require( leftNode.value.get != rightNode.value.get, "Cannot have the same hashes in two child nodes, got: " + leftNode + @@ -334,27 +379,31 @@ object PartialMerkleTree { } else (leftNode, leftRemainingHashes, leftRemainingBits) } val nodeHash = CryptoUtil.doubleSHA256( - leftNode.value.get.bytes ++ rightNode.value.get.bytes) + leftNode.value.get.bytes ++ rightNode.value.get.bytes + ) val node = Node(nodeHash, leftNode, rightNode) (node, rightRemainingHashes, rightRemainingBits) } else { - (Leaf(remainingHashes.head), - remainingHashes.tail, - remainingMatches.tail) + ( + Leaf(remainingHashes.head), + remainingHashes.tail, + remainingMatches.tail + ) } } } val (tree, remainingHashes, remainingBits) = loop(hashes, bits, 0, 0) - //require(remainingBits.isEmpty, s"Remainging bits should be empty, got ${remainingBits}") - //we must have used all the hashes provided to us to reconstruct the partial merkle tree as per BIP37 + // require(remainingBits.isEmpty, s"Remainging bits should be empty, got ${remainingBits}") + // we must have used all the hashes provided to us to reconstruct the partial merkle tree as per BIP37 require( remainingHashes.isEmpty, - "We should not have any left over hashes after building our partial merkle tree, got: " + remainingHashes) - //we must not have any matches remaining, unless the remaining bits were use to pad our byte vector to 8 bits - //for instance, we could have had 5 bits to indicate how to build the merkle tree, but we need to pad it with 3 bits - //to give us a full byte to serialize and send over the network - //https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L174-L175 + "We should not have any left over hashes after building our partial merkle tree, got: " + remainingHashes + ) + // we must not have any matches remaining, unless the remaining bits were use to pad our byte vector to 8 bits + // for instance, we could have had 5 bits to indicate how to build the merkle tree, but we need to pad it with 3 bits + // to give us a full byte to serialize and send over the network + // https://github.com/bitcoin/bitcoin/blob/b7b48c8bbdf7a90861610b035d8b0a247ef78c45/src/merkleblock.cpp#L174-L175 require( usedAllBits(bits, remainingBits), "We should not have any remaining matches except for those that pad our byte after building our partial merkle tree, got: " + remainingBits @@ -362,28 +411,35 @@ object PartialMerkleTree { tree } - /** Calculates the maximum height for a binary tree with the number of transactions specified */ + /** Calculates the maximum height for a binary tree with the number of + * transactions specified + */ def calcMaxHeight(numTransactions: Int): Int = Math.ceil((log(numTransactions) / log(2))).toInt - /** Determines if the right sub tree can exists inside of the partial merkle tree - * This function should only be used to determine if a right sub tree exists when we - * are building a partial merkle tree from bottom up, NOT TOP DOWN. If we are building a - * tree from top down use it's counterpart that does NOT take a maxHeight parameter + /** Determines if the right sub tree can exists inside of the partial merkle + * tree This function should only be used to determine if a right sub tree + * exists when we are building a partial merkle tree from bottom up, NOT TOP + * DOWN. If we are building a tree from top down use it's counterpart that + * does NOT take a maxHeight parameter */ private def existsRightSubTree( pos: Int, numTransaction: Int, maxHeight: Int, - height: Int): Boolean = { + height: Int + ): Boolean = { (pos * 2) + 1 < calcTreeWidth(numTransaction, maxHeight - height - 1) } - /** Determines if the right sub tree can exist inside of the partial merkle tree */ + /** Determines if the right sub tree can exist inside of the partial merkle + * tree + */ private def existsRightSubTree( pos: Int, numTransaction: Int, - height: Int): Boolean = { + height: Int + ): Boolean = { (pos * 2) + 1 < calcTreeWidth(numTransaction, height - 1) } @@ -393,7 +449,8 @@ object PartialMerkleTree { */ private def usedAllBits( bits: BitVector, - remainingBits: BitVector): Boolean = { + remainingBits: BitVector + ): Boolean = { val bitsUsed = bits.size - remainingBits.size ((bitsUsed + 7) / 8) == ((bits.size + 7) / 8) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/build/DLCCETBuilder.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/build/DLCCETBuilder.scala index b779ee69ca..513e5aa85a 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/build/DLCCETBuilder.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/build/DLCCETBuilder.scala @@ -22,8 +22,7 @@ import org.bitcoins.core.wallet.utxo.{ } import org.bitcoins.crypto.ECPublicKey -/** Responsible for constructing unsigned - * Contract Execution Transactions (CETs) +/** Responsible for constructing unsigned Contract Execution Transactions (CETs) */ case class DLCCETBuilder( contractInfo: ContractInfo, @@ -34,14 +33,16 @@ case class DLCCETBuilder( acceptFinalSPK: ScriptPubKey, acceptSerialId: UInt64, timeouts: DLCTimeouts, - fundingOutputRef: OutputReference) { + fundingOutputRef: OutputReference +) { private val fundingOutPoint = fundingOutputRef.outPoint private val fundingInput = TransactionInput( fundingOutPoint, EmptyScriptSignature, - TransactionConstants.disableRBFSequence) + TransactionConstants.disableRBFSequence + ) private val fundingKeys = Vector(offerFundingKey, acceptFundingKey).sortBy(_.hex) @@ -64,22 +65,25 @@ case class DLCCETBuilder( TransactionOutput(acceptValue, acceptFinalSPK) } - /** Constructs a Contract Execution Transaction (CET) - * for a given outcome + /** Constructs a Contract Execution Transaction (CET) for a given outcome */ def buildCET(outcome: OracleOutcome): WitnessTransaction = { val (offerPayout, acceptPayout) = contractInfo.getPayouts(outcome) val outputsWithSerialId = - Vector((cetOfferOutput(offerPayout), offerSerialId), - (cetAcceptOutput(acceptPayout), acceptSerialId)) + Vector( + (cetOfferOutput(offerPayout), offerSerialId), + (cetAcceptOutput(acceptPayout), acceptSerialId) + ) val outputs = sortAndFilterOutputs(outputsWithSerialId) - WitnessTransaction(TransactionConstants.validLockVersion, - Vector(fundingInput), - outputs, - timeouts.contractMaturity.toUInt32, - witness) + WitnessTransaction( + TransactionConstants.validLockVersion, + Vector(fundingInput), + outputs, + timeouts.contractMaturity.toUInt32, + witness + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/build/DLCTxBuilder.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/build/DLCTxBuilder.scala index 457f8264df..97b9787ce7 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/build/DLCTxBuilder.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/build/DLCTxBuilder.scala @@ -27,34 +27,44 @@ import scodec.bits.ByteVector case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs) { - val DLCOffer(_, - _, - DLCPublicKeys(offerFundingKey: ECPublicKey, - offerFinalAddress: BitcoinAddress), - offerTotalCollateral: Satoshis, - offerFundingInputs: Vector[DLCFundingInput], - offerChangeAddress: BitcoinAddress, - offerPayoutSerialId: UInt64, - offerChangeSerialId: UInt64, - fundOutputSerialId: UInt64, - feeRate: SatoshisPerVirtualByte, - DLCTimeouts(contractMaturity: BlockTimeStamp, - contractTimeout: BlockTimeStamp), - _) = offer + val DLCOffer( + _, + _, + DLCPublicKeys( + offerFundingKey: ECPublicKey, + offerFinalAddress: BitcoinAddress + ), + offerTotalCollateral: Satoshis, + offerFundingInputs: Vector[DLCFundingInput], + offerChangeAddress: BitcoinAddress, + offerPayoutSerialId: UInt64, + offerChangeSerialId: UInt64, + fundOutputSerialId: UInt64, + feeRate: SatoshisPerVirtualByte, + DLCTimeouts( + contractMaturity: BlockTimeStamp, + contractTimeout: BlockTimeStamp + ), + _ + ) = offer val network: BitcoinNetwork = offerFinalAddress.networkParameters match { case network: BitcoinNetwork => network } - val DLCAcceptWithoutSigs(acceptTotalCollateral: Satoshis, - DLCPublicKeys(acceptFundingKey: ECPublicKey, - acceptFinalAddress: BitcoinAddress), - acceptFundingInputs: Vector[DLCFundingInput], - acceptChangeAddress: BitcoinAddress, - acceptPayoutSerialId: UInt64, - acceptChangeSerialId: UInt64, - acceptNegotiationFields: DLCAccept.NegotiationFields, - tempContractId: Sha256Digest) = accept + val DLCAcceptWithoutSigs( + acceptTotalCollateral: Satoshis, + DLCPublicKeys( + acceptFundingKey: ECPublicKey, + acceptFinalAddress: BitcoinAddress + ), + acceptFundingInputs: Vector[DLCFundingInput], + acceptChangeAddress: BitcoinAddress, + acceptPayoutSerialId: UInt64, + acceptChangeSerialId: UInt64, + acceptNegotiationFields: DLCAccept.NegotiationFields, + tempContractId: Sha256Digest + ) = accept val totalInput: CurrencyUnit = offerTotalCollateral + acceptTotalCollateral @@ -68,12 +78,15 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs) { require( offerPayoutSerialId != acceptPayoutSerialId, - s"offerPayoutSerialId ($offerPayoutSerialId) cannot equal acceptPayoutSerialId ($acceptPayoutSerialId)") + s"offerPayoutSerialId ($offerPayoutSerialId) cannot equal acceptPayoutSerialId ($acceptPayoutSerialId)" + ) require( - Vector(offerChangeSerialId, - acceptChangeSerialId, - fundOutputSerialId).distinct.size == 3, + Vector( + offerChangeSerialId, + acceptChangeSerialId, + fundOutputSerialId + ).distinct.size == 3, s"offerChangeSerialId, acceptChangeSerialId, and fundOutputSerialId must be unique got ${Vector(offerChangeSerialId, acceptChangeSerialId, fundOutputSerialId)}, respectively" ) @@ -84,8 +97,10 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs) { offer.contractInfo val contractInfo: ContractInfo = - contractInfoBeforeAccept.updateOnAccept(totalInput.satoshis, - acceptNegotiationFields) + contractInfoBeforeAccept.updateOnAccept( + totalInput.satoshis, + acceptNegotiationFields + ) val offerTotalFunding: CurrencyUnit = offerFundingInputs.map(_.output.value).sum @@ -97,37 +112,48 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs) { offer.tempContractId == tempContractId, s"Offer and accept (without sigs) must refer to same event, offer.tempContractId=${offer.tempContractId.hex} tempContractId=${tempContractId.hex}" ) - require(acceptFinalAddress.networkParameters == network, - "Offer and accept (without sigs) must be on the same network") - require(offerChangeAddress.networkParameters == network, - "Offer change address must have same network as final address") - require(acceptChangeAddress.networkParameters == network, - "Accept change address must have same network as final address") + require( + acceptFinalAddress.networkParameters == network, + "Offer and accept (without sigs) must be on the same network" + ) + require( + offerChangeAddress.networkParameters == network, + "Offer change address must have same network as final address" + ) + require( + acceptChangeAddress.networkParameters == network, + "Accept change address must have same network as final address" + ) require( totalInput >= contractInfo.totalCollateral, s"Total collateral must add up to max winnings, totalInput=${totalInput} contractInfo.totalCollateral=${contractInfo.totalCollateral}" ) require( offerTotalFunding >= offerTotalCollateral, - "Offer funding inputs must add up to at least offer's total collateral") + "Offer funding inputs must add up to at least offer's total collateral" + ) require( acceptTotalFunding >= acceptTotalCollateral, - "Accept funding inputs must add up to at least accept's total collateral") + "Accept funding inputs must add up to at least accept's total collateral" + ) /** Returns the payouts for the signature as (toOffer, toAccept) */ def getPayouts( - oracleSigs: Vector[OracleSignatures]): (CurrencyUnit, CurrencyUnit) = { + oracleSigs: Vector[OracleSignatures] + ): (CurrencyUnit, CurrencyUnit) = { contractInfo.getPayouts(oracleSigs) } val fundingKeys: Vector[ECPublicKey] = Vector(offerFundingKey, acceptFundingKey).sortBy(_.hex) - /** The 2-of-2 MultiSignatureScriptPubKey to be wrapped in P2WSH and used as the funding output, - * and the funding output's P2WSH(MultiSig) ScriptPubKey + /** The 2-of-2 MultiSignatureScriptPubKey to be wrapped in P2WSH and used as + * the funding output, and the funding output's P2WSH(MultiSig) ScriptPubKey */ - val (fundingMultiSig: MultiSignatureScriptPubKey, - fundingSPK: P2WSHWitnessSPKV0) = + val ( + fundingMultiSig: MultiSignatureScriptPubKey, + fundingSPK: P2WSHWitnessSPKV0 + ) = DLCTxBuilder.buildFundingSPKs(fundingKeys) lazy val fundingTxFinalizer: DualFundingTxFinalizer = { @@ -175,13 +201,15 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs) { } lazy val calcContractId: ByteVector = { - DLCUtil.computeContractId(fundingTx = fundingTx, - outputIdx = fundOutputIndex, - tempContractId = accept.tempContractId) + DLCUtil.computeContractId( + fundingTx = fundingTx, + outputIdx = fundOutputIndex, + tempContractId = accept.tempContractId + ) } - /** Constructs the unsigned Contract Execution Transaction (CET) - * for a given outcome hash + /** Constructs the unsigned Contract Execution Transaction (CET) for a given + * outcome hash */ def buildCET(adaptorPoint: Indexed[ECPublicKey]): WitnessTransaction = { buildCETs(Vector(adaptorPoint)).head @@ -191,8 +219,9 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs) { buildCET(Indexed(adaptorPoint, index)) } - def buildCETsMap(adaptorPoints: Vector[Indexed[ECPublicKey]]): Vector[ - AdaptorPointCETPair] = { + def buildCETsMap( + adaptorPoints: Vector[Indexed[ECPublicKey]] + ): Vector[AdaptorPointCETPair] = { DLCTxBuilder .buildCETs( adaptorPoints, @@ -209,8 +238,9 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs) { ) } - def buildCETs(adaptorPoints: Vector[Indexed[ECPublicKey]]): Vector[ - WitnessTransaction] = { + def buildCETs( + adaptorPoints: Vector[Indexed[ECPublicKey]] + ): Vector[WitnessTransaction] = { buildCETsMap(adaptorPoints).map(_.wtx) } @@ -234,11 +264,13 @@ case class DLCTxBuilder(offer: DLCOffer, accept: DLCAcceptWithoutSigs) { object DLCTxBuilder { - def buildFundingSPKs(fundingPubKeys: Vector[ECPublicKey]): ( - MultiSignatureScriptPubKey, - P2WSHWitnessSPKV0) = { - require(fundingPubKeys.length == 2, - s"There must be exactly 2 funding keys, got $fundingPubKeys") + def buildFundingSPKs( + fundingPubKeys: Vector[ECPublicKey] + ): (MultiSignatureScriptPubKey, P2WSHWitnessSPKV0) = { + require( + fundingPubKeys.length == 2, + s"There must be exactly 2 funding keys, got $fundingPubKeys" + ) val multiSigSPK = MultiSignatureScriptPubKey(2, fundingPubKeys.sortBy(_.hex)) val p2wshSPK = P2WSHWitnessSPKV0(multiSigSPK) @@ -254,7 +286,8 @@ object DLCTxBuilder { offerPayoutSPK: ScriptPubKey, acceptPayoutSPK: ScriptPubKey, feeRate: SatoshisPerVirtualByte, - fundingSPK: P2WSHWitnessSPKV0): DualFundingTxFinalizer = { + fundingSPK: P2WSHWitnessSPKV0 + ): DualFundingTxFinalizer = { DualFundingTxFinalizer( offerInputs = offerFundingInputs.map(_.toDualFundingInput), offerPayoutSPK = offerPayoutSPK, @@ -268,7 +301,8 @@ object DLCTxBuilder { } /** Builds the funding transaction for a DLC - * @return the transaction and the output index of the funding output + * @return + * the transaction and the output index of the funding output */ def buildFundingTransaction( offerInput: CurrencyUnit, @@ -281,7 +315,8 @@ object DLCTxBuilder { acceptChangeSerialId: UInt64, fundingSPK: P2WSHWitnessSPKV0, fundOutputSerialId: UInt64, - finalizer: DualFundingTxFinalizer): (Transaction, Int) = { + finalizer: DualFundingTxFinalizer + ): (Transaction, Int) = { // The total collateral of both parties combined val totalInput: CurrencyUnit = offerInput + acceptInput @@ -334,20 +369,26 @@ object DLCTxBuilder { val outputs = sortAndFilterOutputs(outputsWithSerialId) - val btx = BaseTransaction(TransactionConstants.validLockVersion, - inputs, - outputs, - UInt32.zero) - val changeSPKs = Vector(offererChangeOutput.scriptPubKey, - acceptorChangeOutput.scriptPubKey) + val btx = BaseTransaction( + TransactionConstants.validLockVersion, + inputs, + outputs, + UInt32.zero + ) + val changeSPKs = Vector( + offererChangeOutput.scriptPubKey, + acceptorChangeOutput.scriptPubKey + ) val outputIdx = btx.outputs.zipWithIndex .filterNot { case (output, _) => changeSPKs.contains(output.scriptPubKey) } .map(_._2) - require(outputIdx.length == 1, - s"Can only have one funding output idx, got=$outputIdx") + require( + outputIdx.length == 1, + s"Can only have one funding output idx, got=$outputIdx" + ) (btx, outputIdx.head) } @@ -361,7 +402,8 @@ object DLCTxBuilder { acceptFinalSPK: ScriptPubKey, acceptSerialId: UInt64, timeouts: DLCTimeouts, - fundingOutputRef: OutputReference): WitnessTransaction = { + fundingOutputRef: OutputReference + ): WitnessTransaction = { val cets = buildCETs( Vector(adaptorPoint), contractInfo, @@ -374,8 +416,10 @@ object DLCTxBuilder { timeouts, fundingOutputRef ) - require(cets.length == 1, - s"Cannot have more than 1 CET for buildCET, got=${cets.length}") + require( + cets.length == 1, + s"Cannot have more than 1 CET for buildCET, got=${cets.length}" + ) cets.head.wtx } @@ -389,17 +433,20 @@ object DLCTxBuilder { acceptFinalSPK: ScriptPubKey, acceptSerialId: UInt64, timeouts: DLCTimeouts, - fundingOutputRef: OutputReference): Vector[AdaptorPointCETPair] = { + fundingOutputRef: OutputReference + ): Vector[AdaptorPointCETPair] = { val builder = - DLCCETBuilder(contractInfo, - offerFundingKey, - offerFinalSPK, - offerSerialId, - acceptFundingKey, - acceptFinalSPK, - acceptSerialId, - timeouts, - fundingOutputRef) + DLCCETBuilder( + contractInfo, + offerFundingKey, + offerFinalSPK, + offerSerialId, + acceptFundingKey, + acceptFinalSPK, + acceptSerialId, + timeouts, + fundingOutputRef + ) val outcomes = adaptorPoints.map { case Indexed(_, index) => contractInfo.allOutcomes(index) @@ -421,22 +468,25 @@ object DLCTxBuilder { acceptSerialId: UInt64, timeouts: DLCTimeouts, fundingTx: Transaction, - fundOutputIndex: Int): Vector[AdaptorPointCETPair] = { + fundOutputIndex: Int + ): Vector[AdaptorPointCETPair] = { val fundingOutPoint = TransactionOutPoint(fundingTx.txId, UInt32(fundOutputIndex)) val fundingOutputRef = OutputReference(fundingOutPoint, fundingTx.outputs(fundOutputIndex)) - buildCETs(adaptorPoints, - contractInfo, - offerFundingKey, - offerFinalSPK, - offerSerialId, - acceptFundingKey, - acceptFinalSPK, - acceptSerialId, - timeouts, - fundingOutputRef) + buildCETs( + adaptorPoints, + contractInfo, + offerFundingKey, + offerFinalSPK, + offerSerialId, + acceptFundingKey, + acceptFinalSPK, + acceptSerialId, + timeouts, + fundingOutputRef + ) } def buildRefundTx( @@ -449,7 +499,8 @@ object DLCTxBuilder { acceptFinalSPK: ScriptPubKey, acceptSerialId: UInt64, fundingOutputRef: OutputReference, - timeouts: DLCTimeouts): WitnessTransaction = { + timeouts: DLCTimeouts + ): WitnessTransaction = { val OutputReference(fundingOutPoint, fundingOutput) = fundingOutputRef val fundingKeys = Vector(offerFundingKey, acceptFundingKey).sortBy(_.hex) val fundingInfo = P2WSHV0InputInfo( @@ -460,13 +511,17 @@ object DLCTxBuilder { conditionalPath = ConditionalPath.NoCondition ) - val fundingInput = TransactionInput(fundingOutPoint, - EmptyScriptSignature, - TransactionConstants.disableRBFSequence) + val fundingInput = TransactionInput( + fundingOutPoint, + EmptyScriptSignature, + TransactionConstants.disableRBFSequence + ) val outputsWithSerialId = - Vector((TransactionOutput(offerInput, offerFinalSPK), offerSerialId), - (TransactionOutput(acceptInput, acceptFinalSPK), acceptSerialId)) + Vector( + (TransactionOutput(offerInput, offerFinalSPK), offerSerialId), + (TransactionOutput(acceptInput, acceptFinalSPK), acceptSerialId) + ) val outputs = sortAndFilterOutputs(outputsWithSerialId) @@ -494,27 +549,30 @@ object DLCTxBuilder { acceptSerialId: UInt64, fundingTx: Transaction, fundOutputIndex: Int, - timeouts: DLCTimeouts): WitnessTransaction = { + timeouts: DLCTimeouts + ): WitnessTransaction = { val fundingOutPoint = TransactionOutPoint(fundingTx.txId, UInt32(fundOutputIndex)) val fundingOutputRef = OutputReference(fundingOutPoint, fundingTx.outputs(fundOutputIndex)) - buildRefundTx(offerInput, - offerFundingKey, - offerFinalSPK, - offerSerialId, - acceptInput, - acceptFundingKey, - acceptFinalSPK, - acceptSerialId, - fundingOutputRef, - timeouts) + buildRefundTx( + offerInput, + offerFundingKey, + offerFinalSPK, + offerSerialId, + acceptInput, + acceptFundingKey, + acceptFinalSPK, + acceptSerialId, + fundingOutputRef, + timeouts + ) } def sortAndFilterOutputs( - outputsWithSerialId: Vector[(TransactionOutput, UInt64)]): Vector[ - TransactionOutput] = { + outputsWithSerialId: Vector[(TransactionOutput, UInt64)] + ): Vector[TransactionOutput] = { outputsWithSerialId .sortBy(_._2) .map(_._1) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/CETCalculator.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/CETCalculator.scala index 0f6d6bbe33..bc9c50b094 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/CETCalculator.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/CETCalculator.scala @@ -18,12 +18,10 @@ object CETCalculator { /** A Vector of digits in a given base. * - * For example if we are using base 2 (binary) - * This could look like + * For example if we are using base 2 (binary) This could look like * Vector(0,1,0,1,0,1,1,1,0) * - * or if we are using base 16 (hex) - * Vector(9,8,10,11,2,3,2,4,1,15) + * or if we are using base 16 (hex) Vector(9,8,10,11,2,3,2,4,1,15) */ type Digits = Vector[Int] @@ -33,15 +31,16 @@ object CETCalculator { /** A Vector of digits and the payout corresponding to this result */ case class CETOutcome(digits: Digits, payout: Satoshis) - /** A Vector of MultiOracleDigits and the payout corresponding to this result */ + /** A Vector of MultiOracleDigits and the payout corresponding to this result + */ case class MultiOracleOutcome( multiOracleDigits: MultiOracleDigits, - payout: Satoshis) + payout: Satoshis + ) - /** Given a range and a payout function with which to build CETs, - * the first step is to split the range into sub-ranges which - * can be compressed or cannot be compressed, represented here - * as CETRanges. + /** Given a range and a payout function with which to build CETs, the first + * step is to split the range into sub-ranges which can be compressed or + * cannot be compressed, represented here as CETRanges. * * These ranges are inclusive in both indices. */ @@ -50,12 +49,15 @@ object CETCalculator { def indexTo: Long } - /** This range contains payouts that all vary at every step and cannot be compressed */ + /** This range contains payouts that all vary at every step and cannot be + * compressed + */ case class VariablePayoutRange(indexFrom: Long, indexTo: Long) extends CETRange - /** This range contains some constant payout between 0 and totalCollateral (exclusive). - * To be clear, indexFrom and indexTo are still inclusive values. + /** This range contains some constant payout between 0 and totalCollateral + * (exclusive). To be clear, indexFrom and indexTo are still inclusive + * values. */ case class ConstantPayoutRange(indexFrom: Long, indexTo: Long) extends CETRange @@ -74,7 +76,8 @@ object CETCalculator { to: Long, totalCollateral: Satoshis, function: DLCPayoutCurve, - rounding: RoundingIntervals): Vector[CETRange] = { + rounding: RoundingIntervals + ): Vector[CETRange] = { require(from <= to, s"from ($from) cannot be greater than to ($to).") val Indexed(firstFunc, firstFuncIndex) = function.componentFor(from) @@ -102,18 +105,21 @@ object CETCalculator { ) } - /** Helper case class to return information from processConstantsForSplitIntoRangesLoop */ + /** Helper case class to return information from + * processConstantsForSplitIntoRangesLoop + */ private case class SplitIntoRangesLoopResult( nextCETRangesSoFar: Vector[CETRange], nextCETRange: CETRange, nextFunc: DLCPayoutCurvePiece, - nextFuncIndex: Int) + nextFuncIndex: Int + ) /** Processes the constant range [currentOutcome, constantTo]. * - * Sadly the redundant call to splitIntoRangesLoop must be repeated - * in all places that call this function otherwise scala cannot tell - * that it is tail recursive. + * Sadly the redundant call to splitIntoRangesLoop must be repeated in all + * places that call this function otherwise scala cannot tell that it is tail + * recursive. */ private def processConstantsForSplitIntoRangesLoop( constantTo: Long, @@ -125,7 +131,8 @@ object CETCalculator { function: DLCPayoutCurve, currentFunc: DLCPayoutCurvePiece, to: Long, - currentFuncIndex: Int): SplitIntoRangesLoopResult = { + currentFuncIndex: Int + ): SplitIntoRangesLoopResult = { val (nextCETRangesSoFar, nextCETRange) = if (value == prevValue) { currentCETRange match { @@ -167,10 +174,12 @@ object CETCalculator { (currentFunc, currentFuncIndex) } - SplitIntoRangesLoopResult(nextCETRangesSoFar, - nextCETRange, - nextFunc, - nextFuncIndex) + SplitIntoRangesLoopResult( + nextCETRangesSoFar, + nextCETRange, + nextFunc, + nextFuncIndex + ) } @tailrec @@ -184,23 +193,26 @@ object CETCalculator { currentCETRange: CETRange, prevValue: Satoshis, currentFunc: DLCPayoutCurvePiece, - currentFuncIndex: Int): Vector[CETRange] = { + currentFuncIndex: Int + ): Vector[CETRange] = { if (currentOutcome > to) { cetRangesSoFar.:+(currentCETRange) } else { val value = currentFunc(currentOutcome, rounding, totalCollateral) def processConstants(constantTo: Long): SplitIntoRangesLoopResult = { - processConstantsForSplitIntoRangesLoop(constantTo, - value, - prevValue, - currentCETRange, - cetRangesSoFar, - currentOutcome, - function, - currentFunc, - to, - currentFuncIndex) + processConstantsForSplitIntoRangesLoop( + constantTo, + value, + prevValue, + currentCETRange, + cetRangesSoFar, + currentOutcome, + function, + currentFunc, + to, + currentFuncIndex + ) } currentFunc match { @@ -212,10 +224,12 @@ object CETCalculator { math.min(rightEndpoint - 1, to) } - val SplitIntoRangesLoopResult(nextCETRangesSoFar, - nextCETRange, - nextFunc, - nextFuncIndex) = + val SplitIntoRangesLoopResult( + nextCETRangesSoFar, + nextCETRange, + nextFunc, + nextFuncIndex + ) = processConstants(constantTo = componentEnd) splitIntoRangesLoop( @@ -231,10 +245,12 @@ object CETCalculator { currentFuncIndex = nextFuncIndex ) case _: DLCPayoutCurvePiece => - val SplitIntoRangesLoopResult(nextCETRangesSoFar, - nextCETRange, - nextFunc, - nextFuncIndex) = + val SplitIntoRangesLoopResult( + nextCETRangesSoFar, + nextCETRange, + nextFunc, + nextFuncIndex + ) = processConstants(constantTo = currentOutcome) splitIntoRangesLoop( @@ -255,9 +271,11 @@ object CETCalculator { /** Searches for an outcome which contains a prefix of digits */ def searchForPrefix[Outcome](digits: Digits, outcomes: Vector[Outcome])( - outcomeToPrefix: Outcome => Digits): Option[Outcome] = { + outcomeToPrefix: Outcome => Digits + ): Option[Outcome] = { val indexOrOverByOne = NumberUtil.search(outcomes, digits, outcomeToPrefix)( - NumberUtil.lexicographicalOrdering[Int]) + NumberUtil.lexicographicalOrdering[Int] + ) if (indexOrOverByOne == outcomes.length) { if (digits.startsWith(outcomeToPrefix(outcomes.last))) { @@ -276,26 +294,30 @@ object CETCalculator { } } - /** Searches for an UnsignedNumericOutcome corresponding to (prefixing) digits. - * Assumes outcomes is ordered. + /** Searches for an UnsignedNumericOutcome corresponding to (prefixing) + * digits. Assumes outcomes is ordered. */ def searchForNumericOutcome( digits: Digits, - outcomes: Vector[DLCOutcomeType]): Option[UnsignedNumericOutcome] = { + outcomes: Vector[DLCOutcomeType] + ): Option[UnsignedNumericOutcome] = { searchForPrefix(digits, outcomes) { case outcome @ (_: EnumOutcome | _: SignedNumericOutcome) => throw new IllegalArgumentException( - s"Expected Numeric Outcome, got $outcome") + s"Expected Numeric Outcome, got $outcome" + ) case UnsignedNumericOutcome(digits) => digits }.asInstanceOf[Option[UnsignedNumericOutcome]] } - /** Computes the front groupings in the CETCompression - * (with endpoint optimization but without total optimization). - * This means the resulting outcomes cover [start, (prefix, digits[0], base-1, ..., base-1)]. + /** Computes the front groupings in the CETCompression (with endpoint + * optimization but without total optimization). This means the resulting + * outcomes cover [start, (prefix, digits[0], base-1, ..., base-1)]. * - * @param digits The unique digits of the range's start - * @param base The base the digits are represented in + * @param digits + * The unique digits of the range's start + * @param base + * The base the digits are represented in */ def frontGroupings(digits: Digits, base: Int): Vector[Digits] = { val nonZeroDigits = @@ -316,12 +338,14 @@ object CETCalculator { } } - /** Computes the back groupings in the CETCompression - * (with endpoint optimization but without total optimization). - * This means the resulting outcomes cover [(prefix, digits[0], 0, ..., 0), end]. + /** Computes the back groupings in the CETCompression (with endpoint + * optimization but without total optimization). This means the resulting + * outcomes cover [(prefix, digits[0], 0, ..., 0), end]. * - * @param digits The unique digits of the range's end - * @param base The base the digits are represented in + * @param digits + * The unique digits of the range's end + * @param base + * The base the digits are represented in */ def backGroupings(digits: Digits, base: Int): Vector[Digits] = { val nonMaxDigits = @@ -348,28 +372,35 @@ object CETCalculator { } } - /** Computes the middle groupings in the CETCompression (without total optimization). - * This means the resulting outcomes cover - * [(prefix, firstDigitStart + 1, 0, ..., 0), (prefix, firstDigitEnd-1, base-1, ..., base-1)]. + /** Computes the middle groupings in the CETCompression (without total + * optimization). This means the resulting outcomes cover [(prefix, + * firstDigitStart + 1, 0, ..., 0), (prefix, firstDigitEnd-1, base-1, ..., + * base-1)]. * - * @param firstDigitStart The first unique digit of the range's start - * @param firstDigitEnd The first unique digit of the range's end + * @param firstDigitStart + * The first unique digit of the range's start + * @param firstDigitEnd + * The first unique digit of the range's end */ def middleGrouping( firstDigitStart: Int, - firstDigitEnd: Int): Vector[Digits] = { + firstDigitEnd: Int + ): Vector[Digits] = { (firstDigitStart + 1).until(firstDigitEnd).toVector.map { firstDigit => Vector(firstDigit) } } - /** Splits off the shared prefix of start and end represented in the given base - * and returns the shared prefix and the unique digits of start and of end. + /** Splits off the shared prefix of start and end represented in the given + * base and returns the shared prefix and the unique digits of start and of + * end. */ - def separatePrefix(start: Long, end: Long, base: Int, numDigits: Int): ( - Digits, - Digits, - Digits) = { + def separatePrefix( + start: Long, + end: Long, + base: Int, + numDigits: Int + ): (Digits, Digits, Digits) = { val startDigits = NumberUtil.decompose(start, base, numDigits) val endDigits = NumberUtil.decompose(end, base, numDigits) @@ -378,19 +409,22 @@ object CETCalculator { .takeWhile { case (startDigit, endDigit) => startDigit == endDigit } .map(_._1) - (prefixDigits, - startDigits.drop(prefixDigits.length), - endDigits.drop(prefixDigits.length)) + ( + prefixDigits, + startDigits.drop(prefixDigits.length), + endDigits.drop(prefixDigits.length) + ) } - /** Runs the compression algorithm with all optimizations on the interval [start, end] - * represented in the given base. + /** Runs the compression algorithm with all optimizations on the interval + * [start, end] represented in the given base. */ def groupByIgnoringDigits( start: Long, end: Long, base: Int, - numDigits: Int): Vector[Digits] = { + numDigits: Int + ): Vector[Digits] = { val (prefixDigits, startDigits, endDigits) = separatePrefix(start, end, base, numDigits) @@ -415,9 +449,10 @@ object CETCalculator { } } - /** Computes the compressed set of outcomes and their corresponding payouts given - * a base, the number of digits to be signed, the payout function, totalCollateral - * and the range of outcomes to construct CETs for, [min, max]. + /** Computes the compressed set of outcomes and their corresponding payouts + * given a base, the number of digits to be signed, the payout function, + * totalCollateral and the range of outcomes to construct CETs for, [min, + * max]. */ def computeCETs( base: Int, @@ -426,7 +461,8 @@ object CETCalculator { totalCollateral: Satoshis, rounding: RoundingIntervals, min: Long, - max: Long): Vector[CETOutcome] = { + max: Long + ): Vector[CETOutcome] = { val ranges = splitIntoRanges(min, max, totalCollateral, function, rounding) ranges.flatMap { range => @@ -434,34 +470,42 @@ object CETCalculator { case ConstantPayoutRange(indexFrom, indexTo) => groupByIgnoringDigits(indexFrom, indexTo, base, numDigits).map { decomp => - CETOutcome(decomp, - payout = - function(indexFrom, rounding, totalCollateral)) + CETOutcome( + decomp, + payout = function(indexFrom, rounding, totalCollateral) + ) } case VariablePayoutRange(indexFrom, indexTo) => indexFrom.to(indexTo).map { num => val decomp = NumberUtil.decompose(num, base, numDigits) - CETOutcome(decomp, - payout = function(num, rounding, totalCollateral)) + CETOutcome( + decomp, + payout = function(num, rounding, totalCollateral) + ) } case SingletonPayoutRange(index) => val decomp = NumberUtil.decompose(index, base, numDigits) Vector( - CETOutcome(decomp, - payout = function(index, rounding, totalCollateral))) + CETOutcome( + decomp, + payout = function(index, rounding, totalCollateral) + ) + ) } } } - /** Computes the compressed set of outcomes and their corresponding payouts given - * a base, the number of digits to be signed, the payout function, and totalCollateral. + /** Computes the compressed set of outcomes and their corresponding payouts + * given a base, the number of digits to be signed, the payout function, and + * totalCollateral. */ def computeCETs( base: Int, numDigits: Int, function: DLCPayoutCurve, totalCollateral: Satoshis, - rounding: RoundingIntervals): Vector[CETOutcome] = { + rounding: RoundingIntervals + ): Vector[CETOutcome] = { val min = 0 val max = Math.pow(base, numDigits).toLong - 1 @@ -471,7 +515,8 @@ object CETCalculator { def payoutSample( func: Long => Long, numDigits: Int, - numPoints: Long): Vector[PiecewisePolynomialEndpoint] = { + numPoints: Long + ): Vector[PiecewisePolynomialEndpoint] = { val maxVal = (1L << numDigits) - 1 0L.until(maxVal, maxVal / numPoints) .toVector @@ -485,7 +530,8 @@ object CETCalculator { def payoutSampleByInterval( func: Long => Long, numDigits: Int, - interval: Int): Vector[PiecewisePolynomialEndpoint] = { + interval: Int + ): Vector[PiecewisePolynomialEndpoint] = { val maxVal = (1L << numDigits) - 1 payoutSample(func, numDigits, maxVal / interval) } @@ -493,10 +539,12 @@ object CETCalculator { def lineApprox( func: Long => Long, numDigits: Int, - interval: Int): DLCPayoutCurve = { + interval: Int + ): DLCPayoutCurve = { DLCPayoutCurve.polynomialInterpolate( payoutSampleByInterval(func, numDigits, interval), - serializationVersion = DLCSerializationVersion.Beta) + serializationVersion = DLCSerializationVersion.Beta + ) } /** Computes all combinations of threshold oracles, preserving order. */ @@ -511,7 +559,9 @@ object CETCalculator { } } - /** Given binary digits corresponding to a CET, returns the CET's support bounds */ + /** Given binary digits corresponding to a CET, returns the CET's support + * bounds + */ def computeCETIntervalBinary(cet: Digits, numDigits: Int): (Long, Long) = { val left = NumberUtil.fromDigits(cet, base = 2, numDigits) val right = left + (1L << (numDigits - cet.length)) - 1 @@ -541,7 +591,8 @@ object CETCalculator { start: Long, end: Long, minFail: Long, - numDigits: Int): Digits = { + numDigits: Int + ): Digits = { val leftBound = start - minFail val leftBoundDigits = NumberUtil.decompose(leftBound, base = 2, numDigits) val rightBound = end + minFail @@ -564,7 +615,8 @@ object CETCalculator { end: Long, maxErrorExp: Int, minFail: Long, - numDigits: Int): Digits = { + numDigits: Int + ): Digits = { val rightBound = end + minFail val rightBoundDigits = NumberUtil.decompose(rightBound, base = 2, numDigits) val (prefix, halvingDigits) = @@ -581,7 +633,8 @@ object CETCalculator { start: Long, maxErrorExp: Int, minFail: Long, - numDigits: Int): Digits = { + numDigits: Int + ): Digits = { val leftBound = start - minFail val leftBoundDigits = NumberUtil.decompose(leftBound, base = 2, numDigits) val (prefix, halvingDigits) = @@ -594,17 +647,19 @@ object CETCalculator { private def singleCoveringCETCombinations[T]( primaryCET: T, coverCET: T, - numOracles: Int): Vector[T] = { + numOracles: Int + ): Vector[T] = { Vector(primaryCET) ++ Vector.fill(numOracles - 1)(coverCET) } - /** Generates all `2^num` possible vectors of length num containing - * only the elements in and out, in order + /** Generates all `2^num` possible vectors of length num containing only the + * elements in and out, in order */ private def inOrOutCombinations[T]( in: T, out: T, - num: Int): Vector[Vector[T]] = { + num: Int + ): Vector[Vector[T]] = { 0.until(num).foldLeft(Vector(Vector.empty[T])) { case (subCombinations, _) => val firstIn = subCombinations.map(combos => in +: combos) @@ -614,43 +669,51 @@ object CETCalculator { } } - /** For the case where secondary oracles can sign either - * coverCETInner or coverCETOuter + /** For the case where secondary oracles can sign either coverCETInner or + * coverCETOuter */ private def doubleCoveringCETCombinations[T]( primaryCET: T, coverCETInner: T, coverCETOuter: T, - numOracles: Int): Vector[Vector[T]] = { + numOracles: Int + ): Vector[Vector[T]] = { val combinations = inOrOutCombinations(coverCETInner, coverCETOuter, numOracles - 1) combinations.map(combos => primaryCET +: combos) } - /** For the case where secondary oracles can sign either - * coverCETInner or coverCETOuter, but not all can sign - * coverCETInner, and coverCETInner is what the primary signs + /** For the case where secondary oracles can sign either coverCETInner or + * coverCETOuter, but not all can sign coverCETInner, and coverCETInner is + * what the primary signs */ private def doubleCoveringRestrictedCETCombinations[T]( coverCETInner: T, coverCETOuter: T, - numOracles: Int): Vector[Vector[T]] = { - doubleCoveringCETCombinations(coverCETInner, - coverCETInner, - coverCETOuter, - numOracles).tail + numOracles: Int + ): Vector[Vector[T]] = { + doubleCoveringCETCombinations( + coverCETInner, + coverCETInner, + coverCETOuter, + numOracles + ).tail } - /** Given the primary oracle's CET, computes the set of CETs needed - * for two oracles with an allowed difference (which is bounded). + /** Given the primary oracle's CET, computes the set of CETs needed for two + * oracles with an allowed difference (which is bounded). * - * @param numDigits The number of binary digits signed by the oracles - * @param cetDigits Digits corresponding to a CET for the primary oracle - * @param maxErrorExp The exponent (of 2) representing the difference at which - * non-support (failure) is guaranteed - * @param minFailExp The exponent (of 2) representing the difference up to - * which support is guaranteed + * @param numDigits + * The number of binary digits signed by the oracles + * @param cetDigits + * Digits corresponding to a CET for the primary oracle + * @param maxErrorExp + * The exponent (of 2) representing the difference at which non-support + * (failure) is guaranteed + * @param minFailExp + * The exponent (of 2) representing the difference up to which support is + * guaranteed */ def computeCoveringCETsBinary( numDigits: Int, @@ -658,9 +721,12 @@ object CETCalculator { maxErrorExp: Int, minFailExp: Int, maximizeCoverage: Boolean, - numOracles: Int): Vector[MultiOracleDigits] = { - require(numOracles > 1, - "For single oracle, just use your cetDigits parameter") + numOracles: Int + ): Vector[MultiOracleDigits] = { + require( + numOracles > 1, + "For single oracle, just use your cetDigits parameter" + ) val maxNum = (1L << numDigits) - 1 val maxError = 1L << maxErrorExp @@ -713,10 +779,12 @@ object CETCalculator { Vector(multiOracleDigits) } else { val doubleCovering: Vector[Vector[Digits]] = - doubleCoveringCETCombinations(cetDigits, - coverCET, - leftCET, - numOracles) + doubleCoveringCETCombinations( + cetDigits, + coverCET, + leftCET, + numOracles + ) doubleCovering } } else if (end > rightErrorCET - minFail) { // case: Right CET @@ -740,15 +808,18 @@ object CETCalculator { Vector(singleCover) } else { val doubleCovering: Vector[Vector[Digits]] = - doubleCoveringCETCombinations(cetDigits, - coverCET, - rightCET, - numOracles) + doubleCoveringCETCombinations( + cetDigits, + coverCET, + rightCET, + numOracles + ) doubleCovering } } else { throw new RuntimeException( - s"Unknown CET with case: $cetDigits, $numDigits, $maxErrorExp, $minFailExp") + s"Unknown CET with case: $cetDigits, $numDigits, $maxErrorExp, $minFailExp" + ) } } else { // case: Large CET val builder = Vector.newBuilder[MultiOracleDigits] @@ -773,9 +844,11 @@ object CETCalculator { } val doubleCovering: Vector[MultiOracleDigits] = - doubleCoveringRestrictedCETCombinations(leftInnerCET, - leftCET, - numOracles) + doubleCoveringRestrictedCETCombinations( + leftInnerCET, + leftCET, + numOracles + ) builder.++=(doubleCovering) builder.result() @@ -813,9 +886,11 @@ object CETCalculator { numToVec(end + 1, numDigits, minFailExp) } - val doubleCover = doubleCoveringRestrictedCETCombinations(rightInnerCET, - rightCET, - numOracles) + val doubleCover = doubleCoveringRestrictedCETCombinations( + rightInnerCET, + rightCET, + numOracles + ) builder.++=(doubleCover) } @@ -823,18 +898,24 @@ object CETCalculator { } } - /** Given the primary oracle's CETs, computes the set of CETs needed - * for n oracles with an allowed difference (which is bounded). + /** Given the primary oracle's CETs, computes the set of CETs needed for n + * oracles with an allowed difference (which is bounded). * - * @param numDigits The number of binary digits signed by the oracles - * @param primaryCETs CETs corresponding to the primary oracle - * @param maxErrorExp The exponent (of 2) representing the difference at which - * non-support (failure) is guaranteed - * @param minFailExp The exponent (of 2) representing the difference up to - * which support is guaranteed - * @param maximizeCoverage The flag that determines whether CETs used in the - * non-middle small case are maximal or minimal in size - * @param numOracles The total number of oracles (including primary) needed for execution + * @param numDigits + * The number of binary digits signed by the oracles + * @param primaryCETs + * CETs corresponding to the primary oracle + * @param maxErrorExp + * The exponent (of 2) representing the difference at which non-support + * (failure) is guaranteed + * @param minFailExp + * The exponent (of 2) representing the difference up to which support is + * guaranteed + * @param maximizeCoverage + * The flag that determines whether CETs used in the non-middle small case + * are maximal or minimal in size + * @param numOracles + * The total number of oracles (including primary) needed for execution */ def computeMultiOracleCETsBinary( numDigits: Int, @@ -842,34 +923,45 @@ object CETCalculator { maxErrorExp: Int, minFailExp: Int, maximizeCoverage: Boolean, - numOracles: Int): Vector[MultiOracleOutcome] = { + numOracles: Int + ): Vector[MultiOracleOutcome] = { require(minFailExp < maxErrorExp) primaryCETs.flatMap { case CETOutcome(cetDigits, payout) => - computeCoveringCETsBinary(numDigits, - cetDigits, - maxErrorExp, - minFailExp, - maximizeCoverage, - numOracles) + computeCoveringCETsBinary( + numDigits, + cetDigits, + maxErrorExp, + minFailExp, + maximizeCoverage, + numOracles + ) .map(MultiOracleOutcome(_, payout)) } } - /** Computes the set of CETs needed for numOracles oracles with an - * allowed difference (which is bounded). + /** Computes the set of CETs needed for numOracles oracles with an allowed + * difference (which is bounded). * - * @param numDigits The number of binary digits signed by the oracles - * @param function The DLCPayoutCurve to use with primary oracles - * @param totalCollateral The funding output's value (ignoring fees) - * @param rounding The rounding intervals to use when computing CETs - * @param maxErrorExp The exponent (of 2) representing the difference at which - * non-support (failure) is guaranteed - * @param minFailExp The exponent (of 2) representing the difference up to - * which support is guaranteed - * @param maximizeCoverage The flag that determines whether CETs used in the - * non-middle small case are maximal or minimal in size - * @param numOracles The total number of oracles (including primary) needed for execution + * @param numDigits + * The number of binary digits signed by the oracles + * @param function + * The DLCPayoutCurve to use with primary oracles + * @param totalCollateral + * The funding output's value (ignoring fees) + * @param rounding + * The rounding intervals to use when computing CETs + * @param maxErrorExp + * The exponent (of 2) representing the difference at which non-support + * (failure) is guaranteed + * @param minFailExp + * The exponent (of 2) representing the difference up to which support is + * guaranteed + * @param maximizeCoverage + * The flag that determines whether CETs used in the non-middle small case + * are maximal or minimal in size + * @param numOracles + * The total number of oracles (including primary) needed for execution */ def computeMultiOracleCETsBinary( numDigits: Int, @@ -879,14 +971,17 @@ object CETCalculator { maxErrorExp: Int, minFailExp: Int, maximizeCoverage: Boolean, - numOracles: Int): Vector[MultiOracleOutcome] = { + numOracles: Int + ): Vector[MultiOracleOutcome] = { val primaryCETs = computeCETs(base = 2, numDigits, function, totalCollateral, rounding) - computeMultiOracleCETsBinary(numDigits, - primaryCETs, - maxErrorExp, - minFailExp, - maximizeCoverage, - numOracles) + computeMultiOracleCETsBinary( + numDigits, + primaryCETs, + maxErrorExp, + minFailExp, + maximizeCoverage, + numOracles + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/DLCAdaptorPointComputer.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/DLCAdaptorPointComputer.scala index fe8e66630a..0f563b5f38 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/DLCAdaptorPointComputer.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/DLCAdaptorPointComputer.scala @@ -27,27 +27,29 @@ object DLCAdaptorPointComputer { .map(CryptoUtil.serializeForHash) } - /** Computes: - * nonce + outcomeHash*pubKey - * where outcomeHash is as specified in the DLC spec. - * @see https://github.com/discreetlogcontracts/dlcspecs/blob/master/Oracle.md#signing-algorithm + /** Computes: nonce + outcomeHash*pubKey where outcomeHash is as specified in + * the DLC spec. + * @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/master/Oracle.md#signing-algorithm */ def computePoint( pubKey: SchnorrPublicKey, nonce: ECPublicKey, - outcome: ByteVector): ECPublicKey = { + outcome: ByteVector + ): ECPublicKey = { val hash = CryptoUtil .sha256SchnorrChallenge( nonce.schnorrNonce.bytes ++ pubKey.bytes ++ CryptoUtil .sha256DLCAttestation(outcome) - .bytes) + .bytes + ) .bytes nonce.add(pubKey.publicKey.multiply(FieldElement(hash))) } - /** This trie is used for computing adaptor points for a single oracle corresponding - * to digit prefixes while memoizing partial sums. + /** This trie is used for computing adaptor points for a single oracle + * corresponding to digit prefixes while memoizing partial sums. * * For example the point corresponding to 0110 and 01111010 both begin with * the 011 sub-sum. @@ -55,19 +57,21 @@ object DLCAdaptorPointComputer { * This trie stores all already computed sub-sums and new points are computed * by extending this Trie. * - * Note that this method should not be used if you have access to LibSecp256k1CryptoRuntime - * because calling CryptoUtil.combinePubKeys will outperform memoization in that case. + * Note that this method should not be used if you have access to + * LibSecp256k1CryptoRuntime because calling CryptoUtil.combinePubKeys will + * outperform memoization in that case. */ case class AdditionTrieNode( preComputeTable: Vector[Vector[ECPublicKey]], // Nonce -> Outcome -> Point depth: Int = 0, private var children: Vector[AdditionTrieNode] = Vector.empty, - private var pointOpt: Option[SecpPoint] = None) { + private var pointOpt: Option[SecpPoint] = None + ) { /** Populates children field with base empty nodes. * - * To avoid unnecessary computation (and recursion), - * this should be called lazily only when children are needed. + * To avoid unnecessary computation (and recursion), this should be called + * lazily only when children are needed. */ def initChildren(): Unit = { children = 0 @@ -76,12 +80,12 @@ object DLCAdaptorPointComputer { .map(_ => AdditionTrieNode(preComputeTable, depth + 1)) } - /** Uses the preComputeTable to calculate the adaptor point - * for the given digit prefix. + /** Uses the preComputeTable to calculate the adaptor point for the given + * digit prefix. * - * This is done by traversing (and where need be extending) the - * Trie according to the digits until the point corresponding to - * the input digits is reached. + * This is done by traversing (and where need be extending) the Trie + * according to the digits until the point corresponding to the input + * digits is reached. */ def computeSum(digits: Vector[Int]): ECPublicKey = { val point = pointOpt.get @@ -90,7 +94,8 @@ object DLCAdaptorPointComputer { point match { case SecpPointInfinity => throw new IllegalArgumentException( - "Sum cannot be point at infinity.") + "Sum cannot be point at infinity." + ) case point: SecpPointFinite => point.toPublicKey } } else { @@ -114,16 +119,20 @@ object DLCAdaptorPointComputer { /** Creates a fresh AdditionTreeNode for a given preComputeTable */ def makeRoot( - preComputeTable: Vector[Vector[ECPublicKey]]): AdditionTrieNode = { + preComputeTable: Vector[Vector[ECPublicKey]] + ): AdditionTrieNode = { AdditionTrieNode(preComputeTable, pointOpt = Some(SecpPointInfinity)) } } - /** Efficiently computes all adaptor points, in order, for a given ContractInfo. - * @see https://medium.com/crypto-garage/optimizing-numeric-outcome-dlc-creation-6d6091ac0e47 + /** Efficiently computes all adaptor points, in order, for a given + * ContractInfo. + * @see + * https://medium.com/crypto-garage/optimizing-numeric-outcome-dlc-creation-6d6091ac0e47 */ def computeAdaptorPoints( - contractInfo: SingleContractInfo): Vector[ECPublicKey] = { + contractInfo: SingleContractInfo + ): Vector[ECPublicKey] = { // The possible messages a single nonce may be used to sign val possibleOutcomes: Vector[ByteVector] = contractInfo.contractDescriptor match { @@ -174,7 +183,8 @@ object DLCAdaptorPointComputer { case UnsignedNumericOutcome(digits) => digits case _: SignedNumericOutcome => throw new UnsupportedOperationException( - "Signed numeric outcomes not supported!") + "Signed numeric outcomes not supported!" + ) } outcomeIndices.zipWithIndex.map { case (outcomeIndex, nonceIndex) => @@ -198,7 +208,8 @@ object DLCAdaptorPointComputer { additionTries(oracleIndex).computeSum(digits) case _: SignedNumericOutcome => throw new UnsupportedOperationException( - "Signed numeric outcomes not supported!") + "Signed numeric outcomes not supported!" + ) } } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/DLCUtil.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/DLCUtil.scala index 8fb6fb361c..d5b5e58415 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/DLCUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/DLCUtil.scala @@ -29,52 +29,66 @@ import scala.util.Try object DLCUtil { - /** @see https://github.com/discreetlogcontracts/dlcspecs/blob/master/Protocol.md#definition-of-contract_id - * @param fundingTxId the id of the transaction that contains the DLC funding output - * @param outputIdx the index of the output - * @param tempContractId the temporary contractId in the offer message + /** @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/master/Protocol.md#definition-of-contract_id + * @param fundingTxId + * the id of the transaction that contains the DLC funding output + * @param outputIdx + * the index of the output + * @param tempContractId + * the temporary contractId in the offer message * @return */ def computeContractId( fundingTxId: DoubleSha256DigestBE, outputIdx: Int, - tempContractId: Sha256Digest): ByteVector = { + tempContractId: Sha256Digest + ): ByteVector = { val u16 = UInt16(outputIdx) - //we need to pad the u16 due to how xor works in scodec so we don't lose precision + // we need to pad the u16 due to how xor works in scodec so we don't lose precision val padded = ByteVector.fill(30)(0.toByte) ++ u16.bytes fundingTxId.bytes .xor(tempContractId.bytes) .xor(padded) } - /** @see https://github.com/discreetlogcontracts/dlcspecs/blob/master/Protocol.md#definition-of-contract_id - * @param fundingTx the transaction that contains the DLC funding output - * @param outputIdx the index of the output - * @param tempContractId the temporary contractId in the offer message + /** @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/master/Protocol.md#definition-of-contract_id + * @param fundingTx + * the transaction that contains the DLC funding output + * @param outputIdx + * the index of the output + * @param tempContractId + * the temporary contractId in the offer message * @return */ def computeContractId( fundingTx: Transaction, outputIdx: Int, - tempContractId: Sha256Digest): ByteVector = { + tempContractId: Sha256Digest + ): ByteVector = { computeContractId(fundingTx.txIdBE, outputIdx, tempContractId) } /** Extracts an adaptor secret from cetSig assuming it is the completion - * adaptorSig (which it may not be) and returns the oracle signature if - * and only if adaptorSig does correspond to cetSig. + * adaptorSig (which it may not be) and returns the oracle signature if and + * only if adaptorSig does correspond to cetSig. * * This method is used to search through possible cetSigs until the correct * one is found by validating the returned signature. * - * @param adaptorPoint A potential adaptor point that could have been executed for - * @param adaptorSig The adaptor signature corresponding to outcome - * @param cetSig The actual signature for local's key found on-chain on a CET + * @param adaptorPoint + * A potential adaptor point that could have been executed for + * @param adaptorSig + * The adaptor signature corresponding to outcome + * @param cetSig + * The actual signature for local's key found on-chain on a CET */ private def sigFromOutcomeAndSigs( adaptorPoint: ECPublicKey, adaptorSig: ECAdaptorSignature, - cetSig: ECDigitalSignature): Try[FieldElement] = { + cetSig: ECDigitalSignature + ): Try[FieldElement] = { // This value is either the oracle signature S value or it is // useless garbage, but we don't know in this scope, the caller // must do further work to check this. @@ -85,14 +99,14 @@ object DLCUtil { } } - /** Given a [[ECDigitalSignature]] we found on the blockchain, and the set - * of possible adaptor signatures we have stored locally in our wallet - * we reverse engineer the actual outcome our counterparty broadcast + /** Given a [[ECDigitalSignature]] we found on the blockchain, and the set of + * possible adaptor signatures we have stored locally in our wallet we + * reverse engineer the actual outcome our counterparty broadcast */ def computeOutcome( completedSig: ECDigitalSignature, - possibleAdaptorSigs: Vector[(ECPublicKey, ECAdaptorSignature)]): Option[ - (FieldElement, ECPublicKey)] = { + possibleAdaptorSigs: Vector[(ECPublicKey, ECAdaptorSignature)] + ): Option[(FieldElement, ECPublicKey)] = { val sigOpt: Option[(ECPublicKey, ECAdaptorSignature)] = { possibleAdaptorSigs.find { case (adaptorPoint, adaptorSig) => val possibleOracleSigT = @@ -103,8 +117,10 @@ object DLCUtil { } sigOpt.map { case (adaptorPoint, adaptorSig) => - (sigFromOutcomeAndSigs(adaptorPoint, adaptorSig, completedSig).get, - adaptorPoint) + ( + sigFromOutcomeAndSigs(adaptorPoint, adaptorSig, completedSig).get, + adaptorPoint + ) } } @@ -114,16 +130,18 @@ object DLCUtil { acceptFundingKey: ECPublicKey, contractInfo: ContractInfo, localAdaptorSigs: Vector[(ECPublicKey, ECAdaptorSignature)], - cet: WitnessTransaction): Option[ - (SchnorrDigitalSignature, OracleOutcome)] = { + cet: WitnessTransaction + ): Option[(SchnorrDigitalSignature, OracleOutcome)] = { val allAdaptorPoints = contractInfo.adaptorPoints val cetSigs = cet.witness.head .asInstanceOf[P2WSHWitnessV0] .signatures - require(cetSigs.size == 2, - s"There must be only 2 signatures, got ${cetSigs.size}") + require( + cetSigs.size == 2, + s"There must be only 2 signatures, got ${cetSigs.size}" + ) val outcomeValues = cet.outputs.map(_.value).sorted val totalCollateral = contractInfo.totalCollateral @@ -140,7 +158,8 @@ object DLCUtil { // Off-by-one is okay because both parties round to the nearest // Satoshi for fees and if both round up they could be off-by-one. Math.abs( - (amts.head - outcomeValues.head).satoshis.toLong) <= 1 && Math + (amts.head - outcomeValues.head).satoshis.toLong + ) <= 1 && Math .abs((amts.last - outcomeValues.last).satoshis.toLong) <= 1 } .map { case (_, index) => allAdaptorPoints(index) } @@ -177,7 +196,8 @@ object DLCUtil { def calcContractId( offer: DLCOffer, - acceptWithoutSigs: DLCAcceptWithoutSigs): ByteVector = { + acceptWithoutSigs: DLCAcceptWithoutSigs + ): ByteVector = { val fundingKeys = Vector(offer.pubKeys.fundingKey, acceptWithoutSigs.pubKeys.fundingKey) val fundOutputSerialId = offer.fundOutputSerialId @@ -216,26 +236,30 @@ object DLCUtil { finalizer = fundingTxFinalizer ) - computeContractId(fundingTx = fundingTx, - outputIdx = fundingOutputIdx, - tempContractId = offer.tempContractId) + computeContractId( + fundingTx = fundingTx, + outputIdx = fundingOutputIdx, + tempContractId = offer.tempContractId + ) } - /** Checks that the oracles signatures given to us are correct - * Things we need to check - * 1. We have all the oracle signatures - * 2. The oracle signatures are for one of the contracts in the [[ContractInfo]] - * @see https://github.com/bitcoin-s/bitcoin-s/issues/4032 + /** Checks that the oracles signatures given to us are correct Things we need + * to check + * 1. We have all the oracle signatures 2. The oracle signatures are for + * one of the contracts in the [[ContractInfo]] + * @see + * https://github.com/bitcoin-s/bitcoin-s/issues/4032 */ def checkOracleSignaturesAgainstContract( contractInfo: ContractInfo, - oracleSigs: Vector[OracleSignatures]): Boolean = { + oracleSigs: Vector[OracleSignatures] + ): Boolean = { contractInfo match { case single: SingleContractInfo => checkSingleContractInfoOracleSigs(single, oracleSigs) case disjoint: DisjointUnionContractInfo => - //at least one disjoint union contract - //has to have matching signatures + // at least one disjoint union contract + // has to have matching signatures disjoint.contracts.exists { single: SingleContractInfo => checkSingleContractInfoOracleSigs(single, oracleSigs) } @@ -247,7 +271,8 @@ object DLCUtil { */ private def checkSingleContractInfoOracleSigs( contractInfo: SingleContractInfo, - oracleSignatures: Vector[OracleSignatures]): Boolean = { + oracleSignatures: Vector[OracleSignatures] + ): Boolean = { require(oracleSignatures.nonEmpty, s"Signatures cannot be empty") matchOracleSignatures(contractInfo, oracleSignatures).isDefined } @@ -255,13 +280,15 @@ object DLCUtil { /** Matches a [[SingleContractInfo]] to its oracle's signatures */ def matchOracleSignatures( contractInfo: SingleContractInfo, - oracleSignatures: Vector[OracleSignatures]): Option[OracleSignatures] = { + oracleSignatures: Vector[OracleSignatures] + ): Option[OracleSignatures] = { matchOracleSignatures(contractInfo.announcements, oracleSignatures) } def matchOracleSignatures( announcements: Vector[OracleAnnouncementTLV], - oracleSignatures: Vector[OracleSignatures]): Option[OracleSignatures] = { + oracleSignatures: Vector[OracleSignatures] + ): Option[OracleSignatures] = { val announcementNonces: Vector[Vector[SchnorrNonce]] = { announcements .map { ann => @@ -280,24 +307,28 @@ object DLCUtil { resultOpt } - /** Checks to see if the given oracle signatures and announcement have the same nonces */ + /** Checks to see if the given oracle signatures and announcement have the + * same nonces + */ private def matchOracleSignaturesForAnnouncements( announcement: OracleAnnouncementTLV, - signature: OracleSignatures): Option[OracleSignatures] = { + signature: OracleSignatures + ): Option[OracleSignatures] = { matchOracleSignatures( Vector(announcement), Vector(signature) ) } - /** Builds a set of oracle signatures from given announcements - * and attestations. This method discards attestments - * that do not have a matching announcement. Those attestments - * are not included in the returned set of [[OracleSignatures]] + /** Builds a set of oracle signatures from given announcements and + * attestations. This method discards attestments that do not have a matching + * announcement. Those attestments are not included in the returned set of + * [[OracleSignatures]] */ def buildOracleSignatures( announcements: OrderedAnnouncements, - attestments: Vector[OracleAttestmentTLV]): Vector[OracleSignatures] = { + attestments: Vector[OracleAttestmentTLV] + ): Vector[OracleSignatures] = { val result: Vector[OracleSignatures] = { val init = Vector.empty[OracleSignatures] attestments @@ -312,7 +343,7 @@ object DLCUtil { case Some(matchedSig) => acc.:+(matchedSig) case None => - //don't add it, skip it + // don't add it, skip it acc } }.toVector @@ -325,7 +356,8 @@ object DLCUtil { def buildOracleSignaturesNaive( announcements: OrderedAnnouncements, - attestments: Vector[OracleAttestmentTLV]): Vector[OracleSignatures] = { + attestments: Vector[OracleAttestmentTLV] + ): Vector[OracleSignatures] = { attestments.foldLeft(Vector.empty[OracleSignatures]) { (acc, sig) => // Nonces should be unique so searching for the first nonce should be safe @@ -345,7 +377,8 @@ object DLCUtil { acc :+ OracleSignatures(SingleOracleInfo(announcement), sig) case None => throw new RuntimeException( - s"Cannot find announcement for associated public key, ${sig.publicKey.hex}") + s"Cannot find announcement for associated public key, ${sig.publicKey.hex}" + ) } } } @@ -356,7 +389,8 @@ object DLCUtil { chainType: HDChainType, keyIndex: Int, networkParameters: NetworkParameters, - externalPayoutAddressOpt: Option[BitcoinAddress]): DLCPublicKeys = { + externalPayoutAddressOpt: Option[BitcoinAddress] + ): DLCPublicKeys = { val chainIndex = chainType.index val fundingKey = xpub @@ -371,7 +405,8 @@ object DLCUtil { val payoutKey = xpub .deriveChildPubKey( - BIP32Path.fromString(s"m/$chainIndex/${keyIndex + 1}")) + BIP32Path.fromString(s"m/$chainIndex/${keyIndex + 1}") + ) .get .key DLCPublicKeys.fromPubKeys(fundingKey, payoutKey, bitcoinNetwork) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/SigningVersion.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/SigningVersion.scala index 105abe0f51..4aa813c35b 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/SigningVersion.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/compute/SigningVersion.scala @@ -28,7 +28,8 @@ object SigningVersion extends StringFactory[SigningVersion] { override def calcNonceTweak( nonce: SchnorrNonce, - eventName: String): ByteVector = { + eventName: String + ): ByteVector = { val bytes = nonce.bytes ++ CryptoUtil.serializeForHash(eventName) CryptoUtil.taggedSha256(bytes, "DLCv0/Nonce").bytes @@ -46,7 +47,8 @@ object SigningVersion extends StringFactory[SigningVersion] { override def calcNonceTweak( nonce: SchnorrNonce, - eventName: String): ByteVector = { + eventName: String + ): ByteVector = { val bytes = nonce.bytes ++ CryptoUtil.serializeForHash(eventName) CryptoUtil.taggedSha256(bytes, "BasicSHA256").bytes @@ -60,12 +62,15 @@ object SigningVersion extends StringFactory[SigningVersion] { } } - /** V0 DLC Oracle singing algo, specified in https://github.com/discreetlogcontracts/dlcspecs/pull/113 */ + /** V0 DLC Oracle singing algo, specified in + * https://github.com/discreetlogcontracts/dlcspecs/pull/113 + */ final case object DLCOracleV0SigningVersion extends SigningVersion { override def calcNonceTweak( nonce: SchnorrNonce, - eventName: String): ByteVector = { + eventName: String + ): ByteVector = { val bytes = nonce.bytes ++ CryptoUtil.serializeForHash(eventName) CryptoUtil.taggedSha256(bytes, "DLC/oracle/nonce/v0").bytes diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCExecutor.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCExecutor.scala index 5b498afbee..64098cc2a7 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCExecutor.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCExecutor.scala @@ -22,37 +22,42 @@ case class DLCExecutor(signer: DLCTxSigner) { */ def setupDLCOffer( cetSigs: CETSignatures, - refundSig: PartialSignature): Try[SetupDLC] = { + refundSig: PartialSignature + ): Try[SetupDLC] = { require(isInitiator, "You should call setupDLCAccept") setupDLC(cetSigs, refundSig, None, None) } /** Constructs the non-initiator's SetupDLC given the initiator's - * CETSignatures and FundingSignatures which should arrive in - * a DLC sign message + * CETSignatures and FundingSignatures which should arrive in a DLC sign + * message */ def setupDLCAccept( cetSigs: CETSignatures, refundSig: PartialSignature, fundingSigs: FundingSignatures, - cetsOpt: Option[Vector[WitnessTransaction]]): Try[SetupDLC] = { + cetsOpt: Option[Vector[WitnessTransaction]] + ): Try[SetupDLC] = { require(!isInitiator, "You should call setupDLCOffer") setupDLC(cetSigs, refundSig, Some(fundingSigs), cetsOpt) } - /** Constructs a SetupDLC given the necessary signature information - * from the counter-party. + /** Constructs a SetupDLC given the necessary signature information from the + * counter-party. */ def setupDLC( cetSigs: CETSignatures, refundSig: PartialSignature, fundingSigsOpt: Option[FundingSignatures], - cetsOpt: Option[Vector[WitnessTransaction]]): Try[SetupDLC] = { + cetsOpt: Option[Vector[WitnessTransaction]] + ): Try[SetupDLC] = { if (!isInitiator) { - require(fundingSigsOpt.isDefined, - "Accepting party must provide remote funding signatures") + require( + fundingSigsOpt.isDefined, + "Accepting party must provide remote funding signatures" + ) } val CETSignatures(outcomeSigs) = cetSigs @@ -85,27 +90,31 @@ case class DLCExecutor(signer: DLCTxSigner) { signer.getPayout(sigs) } - /** Computes closing transactions from a DLCSetup and a set of OracleSignatures. - * The Vector[OracleSignatures] may contain more OracleSignatures than are needed. + /** Computes closing transactions from a DLCSetup and a set of + * OracleSignatures. The Vector[OracleSignatures] may contain more + * OracleSignatures than are needed. * * TODO: Test over-sharing of OracleSignatures */ def executeDLC( dlcSetup: SetupDLC, - oracleSigs: Vector[OracleSignatures]): ExecutedDLCOutcome = { + oracleSigs: Vector[OracleSignatures] + ): ExecutedDLCOutcome = { val remoteFundingPubKey = if (isInitiator) { builder.acceptFundingKey } else { builder.offerFundingKey } - DLCExecutor.executeDLC(dlcSetup.cets, - oracleSigs, - signer.fundingKey, - remoteFundingPubKey, - builder.contractInfo, - dlcSetup.fundingTx, - builder.fundOutputIndex) + DLCExecutor.executeDLC( + dlcSetup.cets, + oracleSigs, + signer.fundingKey, + remoteFundingPubKey, + builder.contractInfo, + dlcSetup.fundingTx, + builder.fundOutputIndex + ) } def executeRefundDLC(dlcSetup: SetupDLC): RefundDLCOutcome = { @@ -122,10 +131,12 @@ case class DLCExecutor(signer: DLCTxSigner) { object DLCExecutor { - /** Given DLC setup data and oracle signatures, computes the OracleOutcome and a fully signed CET. + /** Given DLC setup data and oracle signatures, computes the OracleOutcome and + * a fully signed CET. * - * This function will fail if no threshold-sized subset of the oracle signatures corresponds to - * a valid set of expected oracle signatures as per the oracle announcements in the ContractInfo. + * This function will fail if no threshold-sized subset of the oracle + * signatures corresponds to a valid set of expected oracle signatures as per + * the oracle announcements in the ContractInfo. */ def executeDLC( remoteCETInfos: Vector[(ECPublicKey, CETInfo)], @@ -149,7 +160,9 @@ object DLCExecutor { val oracleInfo = oracleInfoOpt.getOrElse( throw new IllegalArgumentException( - s"Signatures do not correspond to any possible outcome! $oracleSigs")) + s"Signatures do not correspond to any possible outcome! $oracleSigs" + ) + ) val threshold = oracleInfo.threshold val sigCombinations = CETCalculator.combinations(oracleSigs, threshold) @@ -170,28 +183,34 @@ object DLCExecutor { case Some((msg, CETInfo(ucet, remoteSig))) => (msg, ucet, remoteSig) case None => throw new IllegalArgumentException( - s"Signature does not correspond to any possible outcome! $oracleSigs") + s"Signature does not correspond to any possible outcome! $oracleSigs" + ) } val sigsUsed = sigsUsedOpt.get // Safe because msgOpt is defined if no throw val (fundingMultiSig, _) = DLCTxBuilder.buildFundingSPKs( - Vector(fundingKey.publicKey, remoteFundingPubKey)) + Vector(fundingKey.publicKey, remoteFundingPubKey) + ) val signingInfo = - DLCTxSigner.buildCETSigningInfo(fundOutputIndex, - fundingTx, - fundingMultiSig, - fundingKey) + DLCTxSigner.buildCETSigningInfo( + fundOutputIndex, + fundingTx, + fundingMultiSig, + fundingKey + ) - val cet = DLCTxSigner.completeCET(msg, - signingInfo, - fundingMultiSig, - fundingTx, - ucet, - remoteAdaptorSig, - remoteFundingPubKey, - sigsUsed) + val cet = DLCTxSigner.completeCET( + msg, + signingInfo, + fundingMultiSig, + fundingTx, + ucet, + remoteAdaptorSig, + remoteFundingPubKey, + sigsUsed + ) ExecutedDLCOutcome(fundingTx, cet, msg, sigsUsed) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCOutcome.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCOutcome.scala index a3ca9059dd..8712d30836 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCOutcome.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/DLCOutcome.scala @@ -11,10 +11,10 @@ case class ExecutedDLCOutcome( override val fundingTx: Transaction, cet: WitnessTransaction, outcome: OracleOutcome, - sigsUsed: Vector[OracleSignatures]) - extends DLCOutcome + sigsUsed: Vector[OracleSignatures] +) extends DLCOutcome case class RefundDLCOutcome( override val fundingTx: Transaction, - refundTx: WitnessTransaction) - extends DLCOutcome + refundTx: WitnessTransaction +) extends DLCOutcome diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/SetupDLC.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/SetupDLC.scala index c18f65c498..3d6e73a9d9 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/SetupDLC.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/execution/SetupDLC.scala @@ -6,11 +6,13 @@ import org.bitcoins.crypto.{ECAdaptorSignature, ECPublicKey} case class SetupDLC( fundingTx: Transaction, cets: Vector[(ECPublicKey, CETInfo)], - refundTx: WitnessTransaction) { + refundTx: WitnessTransaction +) { cets.foreach { case (msg, cetInfo) => require( cetInfo.tx.inputs.size == 1, - s"CETs should only spend the funding input, local CET for $msg has ${cetInfo.tx.inputs.size} inputs") + s"CETs should only spend the funding input, local CET for $msg has ${cetInfo.tx.inputs.size} inputs" + ) require( cetInfo.tx.inputs.head.previousOutput.txId == fundingTx.txId, s"CET is not spending the funding tx, ${cetInfo.tx.inputs.head}" @@ -18,7 +20,8 @@ case class SetupDLC( } require( refundTx.inputs.size == 1, - s"RefundTx should only spend the funding input, refundTx has ${refundTx.inputs.size} inputs") + s"RefundTx should only spend the funding input, refundTx has ${refundTx.inputs.size} inputs" + ) require( refundTx.inputs.head.previousOutput.txId == fundingTx.txId, s"RefundTx is not spending the funding tx, ${refundTx.inputs.head}" @@ -29,7 +32,8 @@ case class SetupDLC( case Some((_, info)) => info case None => throw new IllegalArgumentException( - s"No CET found for the given adaptor point $adaptorPoint") + s"No CET found for the given adaptor point $adaptorPoint" + ) } } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractDescriptor.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractDescriptor.scala index da4e0c2bac..07a39b5555 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractDescriptor.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractDescriptor.scala @@ -4,15 +4,14 @@ import org.bitcoins.core.currency.Satoshis import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.util.SeqWrapper -/** Fully determines a set of payouts for a DLC. - * These payouts are normally from the point of - * view of the offerer, from which the accepter's - * payouts can be determined by subtracting from totalCollateral. +/** Fully determines a set of payouts for a DLC. These payouts are normally from + * the point of view of the offerer, from which the accepter's payouts can be + * determined by subtracting from totalCollateral. * - * Payouts above totalCollateral may be subject to change - * as totalCollateral does not exist in a ContractDescriptor, - * which is reusable between DLCs. - * @see https://github.com/discreetlogcontracts/dlcspecs/blob/a8876ed28ed33d5f7d5104f01aa2a8d80d128460/Messaging.md#version-1-contract_descriptor + * Payouts above totalCollateral may be subject to change as totalCollateral + * does not exist in a ContractDescriptor, which is reusable between DLCs. + * @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/a8876ed28ed33d5f7d5104f01aa2a8d80d128460/Messaging.md#version-1-contract_descriptor */ sealed trait ContractDescriptor extends TLVSerializable[ContractDescriptorTLV] { @@ -20,21 +19,23 @@ sealed trait ContractDescriptor extends TLVSerializable[ContractDescriptorTLV] { * * WARNING: this(outcome) + flip(TC)(outcome) is not guaranteed to equal TC. * As such, this should not be used to generate pairs of ContractInfos and - * should only be used to replace a ContractInfo with another one of the flipped - * perspective. - * An example case is for MultiNonceContractInfo where flipping the interpolation points - * could lead to an off-by-one after rounding so that the sum above gives TC-1. - * In this example, only the offerer's ContractInfo should be used. + * should only be used to replace a ContractInfo with another one of the + * flipped perspective. An example case is for MultiNonceContractInfo where + * flipping the interpolation points could lead to an off-by-one after + * rounding so that the sum above gives TC-1. In this example, only the + * offerer's ContractInfo should be used. */ def flip(totalCollateral: Satoshis): ContractDescriptor } object ContractDescriptor extends TLVDeserializable[ContractDescriptorTLV, ContractDescriptor]( - ContractDescriptorTLV) { + ContractDescriptorTLV + ) { val empty: ContractDescriptor = EnumContractDescriptor( - Vector(EnumOutcome("") -> Satoshis.zero)) + Vector(EnumOutcome("") -> Satoshis.zero) + ) override def fromTLV(tlv: ContractDescriptorTLV): ContractDescriptor = { tlv match { @@ -47,8 +48,8 @@ object ContractDescriptor /** The ContractDescriptor for enumerated outcome DLCs */ case class EnumContractDescriptor( - outcomeValueMap: Vector[(EnumOutcome, Satoshis)]) - extends ContractDescriptor + outcomeValueMap: Vector[(EnumOutcome, Satoshis)] +) extends ContractDescriptor with TLVSerializable[ContractDescriptorV0TLV] with SeqWrapper[(EnumOutcome, Satoshis)] { @@ -74,7 +75,8 @@ case class EnumContractDescriptor( object EnumContractDescriptor extends TLVDeserializable[ContractDescriptorV0TLV, EnumContractDescriptor]( - ContractDescriptorV0TLV) { + ContractDescriptorV0TLV + ) { def fromStringVec(vec: Vector[(String, Satoshis)]): EnumContractDescriptor = { EnumContractDescriptor(vec.map { case (str, amt) => @@ -95,8 +97,8 @@ object EnumContractDescriptor case class NumericContractDescriptor( outcomeValueFunc: DLCPayoutCurve, numDigits: Int, - roundingIntervals: RoundingIntervals) - extends ContractDescriptor + roundingIntervals: RoundingIntervals +) extends ContractDescriptor with TLVSerializable[ContractDescriptorV1TLV] { private val minValue: Long = 0L @@ -123,19 +125,23 @@ case class NumericContractDescriptor( } override def toTLV: ContractDescriptorV1TLV = { - ContractDescriptorV1TLV(numDigits, - outcomeValueFunc.toTLV, - roundingIntervals.toTLV) + ContractDescriptorV1TLV( + numDigits, + outcomeValueFunc.toTLV, + roundingIntervals.toTLV + ) } } object NumericContractDescriptor extends TLVDeserializable[ ContractDescriptorV1TLV, - NumericContractDescriptor](ContractDescriptorV1TLV) { + NumericContractDescriptor + ](ContractDescriptorV1TLV) { override def fromTLV( - tlv: ContractDescriptorV1TLV): NumericContractDescriptor = { + tlv: ContractDescriptorV1TLV + ): NumericContractDescriptor = { NumericContractDescriptor( DLCPayoutCurve.fromTLV(tlv.payoutFunction), tlv.numDigits, diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractDescriptorTemplate.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractDescriptorTemplate.scala index 815d6c4165..5e4cd87b50 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractDescriptorTemplate.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractDescriptorTemplate.scala @@ -13,11 +13,13 @@ trait ContractDescriptorTemplate { require( individualCollateral >= Satoshis.zero, - s"individualCollateral must be greater than or equal to zero, got $individualCollateral") + s"individualCollateral must be greater than or equal to zero, got $individualCollateral" + ) require( totalCollateral > Satoshis.zero, - s"totalCollateral must be greater than or equal to zero, got $totalCollateral") + s"totalCollateral must be greater than or equal to zero, got $totalCollateral" + ) require( individualCollateral <= totalCollateral, @@ -27,7 +29,8 @@ trait ContractDescriptorTemplate { /** A template for creating a Contract For Difference DLC * - * @see https://www.investopedia.com/terms/c/contractfordifferences.asp + * @see + * https://www.investopedia.com/terms/c/contractfordifferences.asp */ sealed trait CFDTemplate extends ContractDescriptorTemplate { @@ -37,11 +40,14 @@ sealed trait CFDTemplate extends ContractDescriptorTemplate { def numDigits: Int - require(numDigits > 0, - s"Num digits must be greater than zero, got $numDigits") + require( + numDigits > 0, + s"Num digits must be greater than zero, got $numDigits" + ) require( strikePrice >= 0, - s"Strike price must be greater than or equal to zero, got $strikePrice") + s"Strike price must be greater than or equal to zero, got $strikePrice" + ) override val toContractDescriptor: NumericContractDescriptor = { val func: Long => Long = { outcome => @@ -82,7 +88,8 @@ case class ShortCFD( /** A template for doing an options contract DLC * - * @see https://www.investopedia.com/terms/o/optionscontract.asp + * @see + * https://www.investopedia.com/terms/o/optionscontract.asp */ sealed trait OptionTemplate extends ContractDescriptorTemplate { def premium: CurrencyUnit @@ -93,14 +100,19 @@ sealed trait OptionTemplate extends ContractDescriptorTemplate { def roundingIntervals: RoundingIntervals - require(premium >= Satoshis.zero, - s"Premium must be greater than or equal to zero, got $premium") + require( + premium >= Satoshis.zero, + s"Premium must be greater than or equal to zero, got $premium" + ) - require(numDigits > 0, - s"Num digits must be greater than zero, got $numDigits") + require( + numDigits > 0, + s"Num digits must be greater than zero, got $numDigits" + ) require( strikePrice >= 0, - s"Strike price must be greater than or equal to zero, got $strikePrice") + s"Strike price must be greater than or equal to zero, got $strikePrice" + ) override val toContractDescriptor: NumericContractDescriptor = { val maxNum: Long = (BigInt(2).pow(numDigits) - 1).toLong @@ -109,30 +121,37 @@ sealed trait OptionTemplate extends ContractDescriptorTemplate { case _: CallOption => val pointA = PiecewisePolynomialEndpoint( 0L, - (individualCollateral - premium).satoshis) + (individualCollateral - premium).satoshis + ) val pointB = PiecewisePolynomialEndpoint( strikePrice, - (individualCollateral - premium).satoshis) + (individualCollateral - premium).satoshis + ) val pointC = PiecewisePolynomialEndpoint(maxNum, totalCollateral.satoshis) - DLCPayoutCurve.polynomialInterpolate(Vector(pointA, pointB, pointC), - serializationVersion = - DLCSerializationVersion.Beta) + DLCPayoutCurve.polynomialInterpolate( + Vector(pointA, pointB, pointC), + serializationVersion = DLCSerializationVersion.Beta + ) case _: PutOption => val pointA = PiecewisePolynomialEndpoint(0L, totalCollateral.satoshis) val pointB = PiecewisePolynomialEndpoint( strikePrice, - (individualCollateral - premium).satoshis) + (individualCollateral - premium).satoshis + ) val pointC = - PiecewisePolynomialEndpoint(maxNum, - (individualCollateral - premium).satoshis) - DLCPayoutCurve.polynomialInterpolate(Vector(pointA, pointB, pointC), - serializationVersion = - DLCSerializationVersion.Beta) + PiecewisePolynomialEndpoint( + maxNum, + (individualCollateral - premium).satoshis + ) + DLCPayoutCurve.polynomialInterpolate( + Vector(pointA, pointB, pointC), + serializationVersion = DLCSerializationVersion.Beta + ) } NumericContractDescriptor(curve, numDigits = numDigits, roundingIntervals) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractInfo.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractInfo.scala index 4cb5fa79ce..1daef301f3 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractInfo.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractInfo.scala @@ -44,18 +44,23 @@ sealed trait ContractInfo extends TLVSerializable[ContractInfoTLV] { /** Returns the maximum payout the offerer could win from this contract */ def maxOffererPayout: Satoshis - /** Computes the CET set and their corresponding payouts using CETCalculator. */ + /** Computes the CET set and their corresponding payouts using CETCalculator. + */ def allOutcomesAndPayouts: Vector[(OracleOutcome, Satoshis)] /** Corresponds with this DLC's CET set */ lazy val allOutcomes: Vector[OracleOutcome] = allOutcomesAndPayouts.map(_._1) - /** Maps adpator points to their corresponding OracleOutcomes (which correspond to CETs) */ + /** Maps adpator points to their corresponding OracleOutcomes (which + * correspond to CETs) + */ lazy val sigPointMap: Map[ECPublicKey, OracleOutcome] = adaptorPoints.zip(allOutcomes).toMap - /** Map OracleOutcomes (which correspond to CETs) to their adpator point and payouts */ + /** Map OracleOutcomes (which correspond to CETs) to their adpator point and + * payouts + */ lazy val outcomeMap: Map[OracleOutcome, (ECPublicKey, Satoshis, Satoshis)] = { val builder = HashMap.newBuilder[OracleOutcome, (ECPublicKey, Satoshis, Satoshis)] @@ -75,9 +80,11 @@ sealed trait ContractInfo extends TLVSerializable[ContractInfoTLV] { } lazy val adaptorPointsIndexed: Vector[Indexed[ECPublicKey]] = Indexed( - adaptorPoints) + adaptorPoints + ) - /** Checks if the given OracleSignatures exactly match the given OracleOutcome. + /** Checks if the given OracleSignatures exactly match the given + * OracleOutcome. * * Warning: This will return false if too many OracleSignatures are given. * @@ -85,7 +92,8 @@ sealed trait ContractInfo extends TLVSerializable[ContractInfoTLV] { */ def verifySigs( outcome: OracleOutcome, - sigs: Vector[OracleSignatures]): Boolean = { + sigs: Vector[OracleSignatures] + ): Boolean = { if (!sigs.map(_.oracle).forall(outcome.oracles.contains)) { false } else { @@ -105,7 +113,8 @@ sealed trait ContractInfo extends TLVSerializable[ContractInfoTLV] { } } - /** Searches all possible outcomes for one which corresponds to the given signatures. + /** Searches all possible outcomes for one which corresponds to the given + * signatures. * * Warning: This will return false if too many OracleSignatures are given. */ @@ -117,7 +126,8 @@ sealed trait ContractInfo extends TLVSerializable[ContractInfoTLV] { /** Returns the adaptor point and payouts for a given OracleOutcome */ def resultOfOutcome( - outcome: OracleOutcome): (ECPublicKey, Satoshis, Satoshis) = { + outcome: OracleOutcome + ): (ECPublicKey, Satoshis, Satoshis) = { outcomeMap(outcome) } @@ -127,7 +137,8 @@ sealed trait ContractInfo extends TLVSerializable[ContractInfoTLV] { case Some(outcome) => outcome case None => throw new IllegalArgumentException( - s"Signatures do not correspond to a possible outcome! $sigs") + s"Signatures do not correspond to a possible outcome! $sigs" + ) } getPayouts(outcome) } @@ -139,22 +150,25 @@ sealed trait ContractInfo extends TLVSerializable[ContractInfoTLV] { (offerOutcome, acceptOutcome) } - /** A ContractInfo can be constructed by the offerer, but it will not contain new - * information which alters the DLC's contract which is received in the accept message. + /** A ContractInfo can be constructed by the offerer, but it will not contain + * new information which alters the DLC's contract which is received in the + * accept message. * - * Specifically if the total collateral changes or negotiation fields are relevant. + * Specifically if the total collateral changes or negotiation fields are + * relevant. * * In these cases, this function should be called to update the ContractInfo. */ def updateOnAccept( newTotalCollateral: Satoshis, - negotiationFields: DLCAccept.NegotiationFields): ContractInfo + negotiationFields: DLCAccept.NegotiationFields + ): ContractInfo def serializationVersion: DLCSerializationVersion = { contractDescriptors.head match { case _: EnumContractDescriptor => - //enum contracts weren't broken by - //https://github.com/bitcoin-s/bitcoin-s/pull/3854 + // enum contracts weren't broken by + // https://github.com/bitcoin-s/bitcoin-s/pull/3854 DLCSerializationVersion.Beta case n: NumericContractDescriptor => n.outcomeValueFunc.serializationVersion @@ -175,19 +189,20 @@ object ContractInfo /** Fully determines a DLC up to public keys and funding UTXOs to be used. * - * Contains all contract and oracle information and provides an external - * facing interface which should be used in place of directly accessing + * Contains all contract and oracle information and provides an external facing + * interface which should be used in place of directly accessing * ContractDescriptors or OracleInfos whenever possible to make future * refactoring simpler and to make the code more modular. * - * This class also contains lazy vals for all expensive computations - * done regarding CETs during DLC setup and execution. - * @see https://github.com/discreetlogcontracts/dlcspecs/blob/a8876ed28ed33d5f7d5104f01aa2a8d80d128460/Messaging.md#the-contract_info-type + * This class also contains lazy vals for all expensive computations done + * regarding CETs during DLC setup and execution. + * @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/a8876ed28ed33d5f7d5104f01aa2a8d80d128460/Messaging.md#the-contract_info-type */ case class SingleContractInfo( override val totalCollateral: Satoshis, - contractOraclePair: ContractOraclePair) - extends ContractInfo + contractOraclePair: ContractOraclePair +) extends ContractInfo with TLVSerializable[ContractInfoV0TLV] { override def contracts: Vector[SingleContractInfo] = { @@ -209,14 +224,17 @@ case class SingleContractInfo( } override def contractDescriptors: Vector[ContractDescriptor] = Vector( - contractDescriptor) + contractDescriptor + ) override def oracleInfos: Vector[OracleInfo] = Vector(oracleInfo) override def toTLV: ContractInfoV0TLV = { - ContractInfoV0TLV(totalCollateral, - contractDescriptor.toTLV, - oracleInfo.toTLV) + ContractInfoV0TLV( + totalCollateral, + contractDescriptor.toTLV, + oracleInfo.toTLV + ) } /** @inheritdoc */ @@ -232,15 +250,19 @@ case class SingleContractInfo( /** @inheritdoc */ override lazy val allOutcomesAndPayouts: Vector[(OracleOutcome, Satoshis)] = { contractOraclePair match { - case ContractOraclePair.EnumPair(descriptor, - single: EnumSingleOracleInfo) => + case ContractOraclePair.EnumPair( + descriptor, + single: EnumSingleOracleInfo + ) => descriptor.keys.map { outcome => // Safe .get because outcome is from descriptor.keys val payout = descriptor.find(_._1 == outcome).get._2 (EnumOracleOutcome(Vector(single), outcome), payout) } - case ContractOraclePair.EnumPair(descriptor: EnumContractDescriptor, - oracleInfo: EnumMultiOracleInfo) => + case ContractOraclePair.EnumPair( + descriptor: EnumContractDescriptor, + oracleInfo: EnumMultiOracleInfo + ) => descriptor.keys.flatMap { outcome => // Safe .get because outcome is from descriptor.keys val payout = descriptor.find(_._1 == outcome).get._2 @@ -252,25 +274,33 @@ case class SingleContractInfo( } case ContractOraclePair.NumericPair( descriptor, - oracleInfo: NumericSingleOracleInfo) => - val vec = CETCalculator.computeCETs(base = 2, - descriptor.numDigits, - descriptor.outcomeValueFunc, - totalCollateral, - descriptor.roundingIntervals) + oracleInfo: NumericSingleOracleInfo + ) => + val vec = CETCalculator.computeCETs( + base = 2, + descriptor.numDigits, + descriptor.outcomeValueFunc, + totalCollateral, + descriptor.roundingIntervals + ) vec.map { case CETOutcome(digits, amt) => - (NumericOracleOutcome(oracleInfo, UnsignedNumericOutcome(digits)), - amt) + ( + NumericOracleOutcome(oracleInfo, UnsignedNumericOutcome(digits)), + amt + ) } case ContractOraclePair.NumericPair( descriptor, - oracleInfo: NumericExactMultiOracleInfo) => - val vec = CETCalculator.computeCETs(base = 2, - descriptor.numDigits, - descriptor.outcomeValueFunc, - totalCollateral, - descriptor.roundingIntervals) + oracleInfo: NumericExactMultiOracleInfo + ) => + val vec = CETCalculator.computeCETs( + base = 2, + descriptor.numDigits, + descriptor.outcomeValueFunc, + totalCollateral, + descriptor.roundingIntervals + ) CETCalculator .combinations(oracleInfo.singleOracleInfos, oracleInfo.threshold) @@ -280,8 +310,10 @@ case class SingleContractInfo( (NumericOracleOutcome(oracles.map((_, outcome))), amt) } } - case ContractOraclePair.NumericPair(descriptor: NumericContractDescriptor, - oracleInfo: NumericMultiOracleInfo) => + case ContractOraclePair.NumericPair( + descriptor: NumericContractDescriptor, + oracleInfo: NumericMultiOracleInfo + ) => val vec: Vector[MultiOracleOutcome] = CETCalculator.computeMultiOracleCETsBinary( descriptor.numDigits, @@ -309,12 +341,14 @@ case class SingleContractInfo( /** @inheritdoc */ override def updateOnAccept( newTotalCollateral: Satoshis, - negotiationFields: DLCAccept.NegotiationFields): SingleContractInfo = { + negotiationFields: DLCAccept.NegotiationFields + ): SingleContractInfo = { contractOraclePair match { case ContractOraclePair.EnumPair(_, _) => if (negotiationFields != DLCAccept.NoNegotiationFields) { throw new IllegalArgumentException( - s"Cannot have rounding intervals for single nonce contract: $negotiationFields") + s"Cannot have rounding intervals for single nonce contract: $negotiationFields" + ) } if (newTotalCollateral == totalCollateral) { @@ -327,11 +361,13 @@ case class SingleContractInfo( val newRoundingIntervals = negotiationFields match { case DLCAccept.NegotiationFieldsV1(acceptRoundingIntervals) => descriptor.roundingIntervals.minRoundingWith( - acceptRoundingIntervals) + acceptRoundingIntervals + ) case DLCAccept.NoNegotiationFields => descriptor.roundingIntervals case _: DLCAccept.NegotiationFieldsV2 => throw new IllegalArgumentException( - s"Cannot use disjoint union negotiation fields for a SingleContractInfo, $negotiationFields") + s"Cannot use disjoint union negotiation fields for a SingleContractInfo, $negotiationFields" + ) } if ( @@ -343,8 +379,10 @@ case class SingleContractInfo( descriptor.copy(roundingIntervals = newRoundingIntervals) val contractOraclePair = ContractOraclePair.NumericPair(newDescriptor, oracleInfo) - SingleContractInfo(totalCollateral = newTotalCollateral, - contractOraclePair = contractOraclePair) + SingleContractInfo( + totalCollateral = newTotalCollateral, + contractOraclePair = contractOraclePair + ) } } } @@ -352,7 +390,8 @@ case class SingleContractInfo( object SingleContractInfo extends TLVDeserializable[ContractInfoV0TLV, SingleContractInfo]( - ContractInfoV0TLV) { + ContractInfoV0TLV + ) { lazy val dummy: ContractInfo = fromTLV(ContractInfoV0TLV.dummy) @@ -366,32 +405,41 @@ object SingleContractInfo def apply( enumDescriptor: EnumContractDescriptor, - enumOracleInfo: EnumOracleInfo): SingleContractInfo = { + enumOracleInfo: EnumOracleInfo + ): SingleContractInfo = { val enumPair = ContractOraclePair.EnumPair(enumDescriptor, enumOracleInfo) - SingleContractInfo(totalCollateral = enumDescriptor.values.maxBy(_.toLong), - enumPair) + SingleContractInfo( + totalCollateral = enumDescriptor.values.maxBy(_.toLong), + enumPair + ) } def apply( totalCollateral: Satoshis, contractDescriptor: ContractDescriptor, - oracleInfo: OracleInfo): SingleContractInfo = { + oracleInfo: OracleInfo + ): SingleContractInfo = { SingleContractInfo( totalCollateral, - ContractOraclePair.fromDescriptorOracle(contractDescriptor, oracleInfo)) + ContractOraclePair.fromDescriptorOracle(contractDescriptor, oracleInfo) + ) } } case class DisjointUnionContractInfo(contracts: Vector[SingleContractInfo]) extends ContractInfo with TLVSerializable[ContractInfoV1TLV] { - require(contracts.nonEmpty, - s"Cannot have empty contract oracle pairs for ContractInfoV1TLV") + require( + contracts.nonEmpty, + s"Cannot have empty contract oracle pairs for ContractInfoV1TLV" + ) override val totalCollateral: Satoshis = contracts.head.totalCollateral - require(contracts.forall(_.totalCollateral == totalCollateral), - "All contract total collaterals must be equal.") + require( + contracts.forall(_.totalCollateral == totalCollateral), + "All contract total collaterals must be equal." + ) override def oracleInfos: Vector[OracleInfo] = contracts.map(_.oracleInfo) @@ -402,7 +450,8 @@ case class DisjointUnionContractInfo(contracts: Vector[SingleContractInfo]) ContractInfoV1TLV( totalCollateral, contracts.map(contract => - (contract.contractDescriptor.toTLV, contract.oracleInfo.toTLV))) + (contract.contractDescriptor.toTLV, contract.oracleInfo.toTLV)) + ) } /** @inheritdoc */ @@ -417,12 +466,14 @@ case class DisjointUnionContractInfo(contracts: Vector[SingleContractInfo]) /** @inheritdoc */ override def updateOnAccept( newTotalCollateral: Satoshis, - negotiationFields: DLCAccept.NegotiationFields): DisjointUnionContractInfo = { + negotiationFields: DLCAccept.NegotiationFields + ): DisjointUnionContractInfo = { negotiationFields match { case DLCAccept.NegotiationFieldsV2(nestedNegotiationFields) => require( nestedNegotiationFields.length == contracts.length, - s"Expected ${contracts.length} negotiation fields, got $negotiationFields.") + s"Expected ${contracts.length} negotiation fields, got $negotiationFields." + ) val newContracts = contracts.zip(nestedNegotiationFields).map { case (contract, negotiationFields) => @@ -432,14 +483,16 @@ case class DisjointUnionContractInfo(contracts: Vector[SingleContractInfo]) DisjointUnionContractInfo(newContracts) case _: DLCAccept.NegotiationFields => throw new IllegalArgumentException( - s"Required disjoint union negotiation fields for disjoint union contract info, got $negotiationFields") + s"Required disjoint union negotiation fields for disjoint union contract info, got $negotiationFields" + ) } } } object DisjointUnionContractInfo extends TLVDeserializable[ContractInfoV1TLV, DisjointUnionContractInfo]( - ContractInfoV1TLV) { + ContractInfoV1TLV + ) { override def fromTLV(tlv: ContractInfoV1TLV): DisjointUnionContractInfo = { val contracts = tlv.contractOraclePairs.map { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractOraclePair.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractOraclePair.scala index 35c0e91e0b..8e1d8acdc7 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractOraclePair.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/ContractOraclePair.scala @@ -6,10 +6,9 @@ import org.bitcoins.core.protocol.tlv.{ NumericEventDescriptorTLV } -/** A pair of [[ContractDescriptor]] and [[OracleInfo]] - * This type is meant to ensure consistentcy between various - * [[ContractDescriptor]] and [[OracleInfo]] so that you cannot - * have an incorrect pairing. +/** A pair of [[ContractDescriptor]] and [[OracleInfo]] This type is meant to + * ensure consistentcy between various [[ContractDescriptor]] and + * [[OracleInfo]] so that you cannot have an incorrect pairing. */ sealed trait ContractOraclePair { def contractDescriptor: ContractDescriptor @@ -20,8 +19,8 @@ object ContractOraclePair { case class EnumPair( contractDescriptor: EnumContractDescriptor, - oracleInfo: EnumOracleInfo) - extends ContractOraclePair { + oracleInfo: EnumOracleInfo + ) extends ContractOraclePair { private val descriptorOutcomes = contractDescriptor.map(_._1).sortBy(_.outcome) @@ -42,8 +41,8 @@ object ContractOraclePair { case class NumericPair( contractDescriptor: NumericContractDescriptor, - oracleInfo: NumericOracleInfo) - extends ContractOraclePair { + oracleInfo: NumericOracleInfo + ) extends ContractOraclePair { private val isValid = oracleInfo.singleOracleInfos.forall { singleInfo => val announcementDescriptor = @@ -55,12 +54,13 @@ object ContractOraclePair { require(isValid, s"OracleInfo did not match ContractDescriptor: $this") } - /** Returns a valid [[ContractOraclePair]] if the - * [[ContractDescriptor]] and [[OracleInfo]] are of the same type + /** Returns a valid [[ContractOraclePair]] if the [[ContractDescriptor]] and + * [[OracleInfo]] are of the same type */ def fromDescriptorOracleOpt( descriptor: ContractDescriptor, - oracleInfo: OracleInfo): Option[ContractOraclePair] = { + oracleInfo: OracleInfo + ): Option[ContractOraclePair] = { (descriptor, oracleInfo) match { case (e: EnumContractDescriptor, o: EnumOracleInfo) => Some(EnumPair(e, o)) @@ -73,17 +73,19 @@ object ContractOraclePair { } } - /** Returns a valid [[ContractOraclePair]] if the - * [[ContractDescriptor]] and [[OracleInfo]] are of the same type + /** Returns a valid [[ContractOraclePair]] if the [[ContractDescriptor]] and + * [[OracleInfo]] are of the same type */ def fromDescriptorOracle( descriptor: ContractDescriptor, - oracleInfo: OracleInfo): ContractOraclePair = { + oracleInfo: OracleInfo + ): ContractOraclePair = { fromDescriptorOracleOpt(descriptor, oracleInfo) match { case Some(pair) => pair case None => sys.error( - s"You passed in an incompatible contract/oracle pair, contract=$descriptor, oracle=$oracleInfo") + s"You passed in an incompatible contract/oracle pair, contract=$descriptor, oracle=$oracleInfo" + ) } } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCFundingInput.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCFundingInput.scala index d8b9a7d22f..c589f486b7 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCFundingInput.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCFundingInput.scala @@ -61,7 +61,8 @@ object DLCFundingInput { prevTxVout: UInt32, sequence: UInt32, maxWitnessLen: UInt16, - redeemScriptOpt: Option[WitnessScriptPubKey]): DLCFundingInput = { + redeemScriptOpt: Option[WitnessScriptPubKey] + ): DLCFundingInput = { prevTx.outputs(prevTxVout.toInt).scriptPubKey match { case _: P2SHScriptPubKey => redeemScriptOpt match { @@ -70,37 +71,46 @@ object DLCFundingInput { case _: P2WPKHWitnessSPKV0 => require( maxWitnessLen == UInt16(107) || maxWitnessLen == UInt16(108), - s"P2WPKH max witness length must be 107 or 108, got $maxWitnessLen") + s"P2WPKH max witness length must be 107 or 108, got $maxWitnessLen" + ) case _: P2WSHWitnessSPKV0 => () case spk: TaprootScriptPubKey => throw new IllegalArgumentException( - s"Taproot not yet supported: $spk") + s"Taproot not yet supported: $spk" + ) case spk: UnassignedWitnessScriptPubKey => throw new IllegalArgumentException( - s"Unknown segwit version: $spk") + s"Unknown segwit version: $spk" + ) } - DLCFundingInputP2SHSegwit(inputSerialId, - prevTx, - prevTxVout, - sequence, - maxWitnessLen, - redeemScript) + DLCFundingInputP2SHSegwit( + inputSerialId, + prevTx, + prevTxVout, + sequence, + maxWitnessLen, + redeemScript + ) case None => throw new IllegalArgumentException( - "P2SH input requires a redeem script") + "P2SH input requires a redeem script" + ) } case _: P2WPKHWitnessSPKV0 => require( maxWitnessLen == UInt16(107) || maxWitnessLen == UInt16(108), - s"P2WPKH max witness length must be 107 or 108, got $maxWitnessLen") + s"P2WPKH max witness length must be 107 or 108, got $maxWitnessLen" + ) DLCFundingInputP2WPKHV0(inputSerialId, prevTx, prevTxVout, sequence) case _: P2WSHWitnessSPKV0 => - DLCFundingInputP2WSHV0(inputSerialId, - prevTx, - prevTxVout, - sequence, - maxWitnessLen) + DLCFundingInputP2WSHV0( + inputSerialId, + prevTx, + prevTxVout, + sequence, + maxWitnessLen + ) case spk: TaprootScriptPubKey => throw new IllegalArgumentException(s"Taproot not yet supported: $spk") case spk: UnassignedWitnessScriptPubKey => @@ -124,7 +134,8 @@ object DLCFundingInput { def fromInputSigningInfo( info: ScriptSignatureParams[InputInfo], inputSerialId: UInt64, - sequence: UInt32): DLCFundingInput = { + sequence: UInt32 + ): DLCFundingInput = { DLCFundingInput( inputSerialId, info.prevTransaction, @@ -142,10 +153,12 @@ case class DLCFundingInputP2WPKHV0( inputSerialId: UInt64, prevTx: Transaction, prevTxVout: UInt32, - sequence: UInt32) - extends DLCFundingInput { - require(output.scriptPubKey.isInstanceOf[P2WPKHWitnessSPKV0], - s"Funding input not P2WPKH: ${output.scriptPubKey}") + sequence: UInt32 +) extends DLCFundingInput { + require( + output.scriptPubKey.isInstanceOf[P2WPKHWitnessSPKV0], + s"Funding input not P2WPKH: ${output.scriptPubKey}" + ) override val maxWitnessLen: UInt16 = UInt16(107) override val redeemScriptOpt: Option[WitnessScriptPubKey] = None @@ -156,10 +169,12 @@ case class DLCFundingInputP2WSHV0( prevTx: Transaction, prevTxVout: UInt32, sequence: UInt32, - maxWitnessLen: UInt16) - extends DLCFundingInput { - require(output.scriptPubKey.isInstanceOf[P2WSHWitnessSPKV0], - s"Funding input not P2WSH: ${output.scriptPubKey}") + maxWitnessLen: UInt16 +) extends DLCFundingInput { + require( + output.scriptPubKey.isInstanceOf[P2WSHWitnessSPKV0], + s"Funding input not P2WSH: ${output.scriptPubKey}" + ) override val redeemScriptOpt: Option[WitnessScriptPubKey] = None } @@ -170,8 +185,8 @@ case class DLCFundingInputP2SHSegwit( prevTxVout: UInt32, sequence: UInt32, maxWitnessLen: UInt16, - redeemScript: WitnessScriptPubKey) - extends DLCFundingInput { + redeemScript: WitnessScriptPubKey +) extends DLCFundingInput { require( output.scriptPubKey == P2SHScriptPubKey(redeemScript), s"Funding input not correct P2SH: ${output.scriptPubKey}; expected ${P2SHScriptPubKey(redeemScript)}" @@ -182,7 +197,8 @@ case class DLCFundingInputP2SHSegwit( case class SpendingInfoWithSerialId( spendingInfo: ScriptSignatureParams[InputInfo], - serialId: UInt64) { + serialId: UInt64 +) { def toDLCFundingInput(sequence: UInt32): DLCFundingInput = DLCFundingInput.fromInputSigningInfo(spendingInfo, serialId, sequence) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCMessage.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCMessage.scala index eea2fd4f7b..0f8c9fd50c 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCMessage.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCMessage.scala @@ -41,7 +41,8 @@ object DLCMessage { @tailrec def genSerialIds( size: Int, - notEqualTo: Vector[UInt64] = Vector.empty): Vector[UInt64] = { + notEqualTo: Vector[UInt64] = Vector.empty + ): Vector[UInt64] = { val ids = 0.until(size).toVector.map(_ => genSerialId(notEqualTo)) if (ids.distinct.size != size) @@ -52,7 +53,9 @@ object DLCMessage { sealed trait DLCSetupMessage extends DLCMessage { def pubKeys: DLCPublicKeys - /** The collateral that the offerer/acceptor is putting up on their side of the DLC */ + /** The collateral that the offerer/acceptor is putting up on their side of + * the DLC + */ def collateral: Satoshis def fundingInputs: Vector[DLCFundingInput] @@ -61,20 +64,30 @@ object DLCMessage { require( collateral >= Satoshis.zero, - s"Cannot have a negative totalCollateral, got: ${collateral.toLong}") + s"Cannot have a negative totalCollateral, got: ${collateral.toLong}" + ) } - /** The initiating party starts the protocol by sending an offer message to the other party. + /** The initiating party starts the protocol by sending an offer message to + * the other party. * - * @param contractInfo The oracle public key and R point(s) to use to build the CETs as - * well as meta information to identify the oracle to be used in the contract, - * and a map to be used to create CETs. - * @param pubKeys The relevant public keys that the initiator will be using - * @param collateral How much the initiator inputs into the contract. - * @param fundingInputs The set of UTXOs to be used as input to the fund transaction. - * @param changeAddress The address to use to send the change for the initiator. - * @param feeRate The fee rate to be used when computing fees for the different transactions. - * @param timeouts The set of timeouts for the CETs + * @param contractInfo + * The oracle public key and R point(s) to use to build the CETs as well as + * meta information to identify the oracle to be used in the contract, and + * a map to be used to create CETs. + * @param pubKeys + * The relevant public keys that the initiator will be using + * @param collateral + * How much the initiator inputs into the contract. + * @param fundingInputs + * The set of UTXOs to be used as input to the fund transaction. + * @param changeAddress + * The address to use to send the change for the initiator. + * @param feeRate + * The fee rate to be used when computing fees for the different + * transactions. + * @param timeouts + * The set of timeouts for the CETs */ case class DLCOffer( protocolVersionOpt: Option[Int], @@ -88,18 +101,20 @@ object DLCMessage { fundOutputSerialId: UInt64, feeRate: SatoshisPerVirtualByte, timeouts: DLCTimeouts, - isExternalAddress: Boolean = false) - extends DLCSetupMessage { + isExternalAddress: Boolean = false + ) extends DLCSetupMessage { require(fundingInputs.nonEmpty, s"DLCOffer fundingINnputs cannot be empty") require( fundingInputs.map(_.inputSerialId).distinct.size == fundingInputs.size, - "All funding input serial ids must be unique") + "All funding input serial ids must be unique" + ) require( changeSerialId != fundOutputSerialId, - s"changeSerialId ($changeSerialId) cannot be equal to fundOutputSerialId ($fundOutputSerialId)") + s"changeSerialId ($changeSerialId) cannot be equal to fundOutputSerialId ($fundOutputSerialId)" + ) require( collateral <= contractInfo.totalCollateral, @@ -154,7 +169,8 @@ object DLCMessage { contractInfo = contractInfo, pubKeys = DLCPublicKeys( offer.fundingPubKey, - BitcoinAddress.fromScriptPubKey(offer.payoutSPK, network)), + BitcoinAddress.fromScriptPubKey(offer.payoutSPK, network) + ), collateral = offer.offererCollateralSatoshis, fundingInputs = offer.fundingInputs.map { case input: FundingInputV0TLV => DLCFundingInput.fromTLV(input) @@ -175,7 +191,9 @@ object DLCMessage { } } - /** DLC Accept message that contains refund signatures, but does not contain cet signatures */ + /** DLC Accept message that contains refund signatures, but does not contain + * cet signatures + */ case class DLCAcceptWithoutCetSigs( totalCollateral: Satoshis, pubKeys: DLCPublicKeys, @@ -185,7 +203,8 @@ object DLCMessage { changeSerialId: UInt64, refundSig: PartialSignature, negotiationFields: DLCAccept.NegotiationFields, - tempContractId: Sha256Digest) { + tempContractId: Sha256Digest + ) { def withCetSigs(cetSigs: CETSignatures): DLCAccept = { DLCAccept( @@ -203,7 +222,9 @@ object DLCMessage { } } - /** DLC accept message that does not contain cet signatures or refund signatures */ + /** DLC accept message that does not contain cet signatures or refund + * signatures + */ case class DLCAcceptWithoutSigs( totalCollateral: Satoshis, pubKeys: DLCPublicKeys, @@ -212,7 +233,8 @@ object DLCMessage { payoutSerialId: UInt64, changeSerialId: UInt64, negotiationFields: DLCAccept.NegotiationFields, - tempContractId: Sha256Digest) { + tempContractId: Sha256Digest + ) { def withRefundSigs(refundSig: PartialSignature): DLCAcceptWithoutCetSigs = { DLCAcceptWithoutCetSigs( @@ -230,7 +252,8 @@ object DLCMessage { def withSigs( cetSigs: CETSignatures, - refundSig: PartialSignature): DLCAccept = { + refundSig: PartialSignature + ): DLCAccept = { DLCAccept( collateral = totalCollateral, pubKeys = pubKeys, @@ -257,12 +280,13 @@ object DLCMessage { refundSig: PartialSignature, negotiationFields: DLCAccept.NegotiationFields, tempContractId: Sha256Digest, - isExternalAddress: Boolean = false) - extends DLCSetupMessage { + isExternalAddress: Boolean = false + ) extends DLCSetupMessage { require( fundingInputs.map(_.inputSerialId).distinct.size == fundingInputs.size, - "All funding input serial ids must be unique") + "All funding input serial ids must be unique" + ) def toTLV: DLCAcceptTLV = { DLCAcceptTLV( @@ -332,11 +356,12 @@ object DLCMessage { } case class NegotiationFieldsV2( - nestedNegotiationFields: Vector[NegotiationFields]) - extends TLVSerializable[NegotiationFieldsV2TLV] + nestedNegotiationFields: Vector[NegotiationFields] + ) extends TLVSerializable[NegotiationFieldsV2TLV] with NegotiationFields { require( - nestedNegotiationFields.forall(!_.isInstanceOf[NegotiationFieldsV2])) + nestedNegotiationFields.forall(!_.isInstanceOf[NegotiationFieldsV2]) + ) override def toTLV: NegotiationFieldsV2TLV = { NegotiationFieldsV2TLV(nestedNegotiationFields.map(_.toTLV)) @@ -352,7 +377,8 @@ object DLCMessage { NegotiationFieldsV1(RoundingIntervals.fromTLV(roundingIntervalsTLV)) case NegotiationFieldsV2TLV(nestedNegotiationFields) => NegotiationFieldsV2( - nestedNegotiationFields.map(NegotiationFields.fromTLV)) + nestedNegotiationFields.map(NegotiationFields.fromTLV) + ) } } } @@ -360,22 +386,25 @@ object DLCMessage { def fromTLV( accept: DLCAcceptTLV, network: NetworkParameters, - adaptorPoints: Vector[ECPublicKey]): DLCAccept = { + adaptorPoints: Vector[ECPublicKey] + ): DLCAccept = { val outcomeSigs = accept.cetSignatures match { case CETSignaturesV0TLV(sigs) => adaptorPoints.zip(sigs) } - //add hashtype + // add hashtype val refundSigWithHashType = { ECDigitalSignature.fromBytes( - accept.refundSignature.bytes.:+(HashType.sigHashAllByte)) + accept.refundSignature.bytes.:+(HashType.sigHashAllByte) + ) } DLCAccept( collateral = accept.acceptCollateralSatoshis, pubKeys = DLCPublicKeys( accept.fundingPubKey, - BitcoinAddress.fromScriptPubKey(accept.payoutSPK, network)), + BitcoinAddress.fromScriptPubKey(accept.payoutSPK, network) + ), fundingInputs = accept.fundingInputs.map { case input: FundingInputV0TLV => DLCFundingInput.fromTLV(input) }, @@ -396,7 +425,8 @@ object DLCMessage { def fromTLV( accept: DLCAcceptTLV, network: NetworkParameters, - contractInfo: ContractInfo): DLCAccept = { + contractInfo: ContractInfo + ): DLCAccept = { fromTLV(accept, network, contractInfo.adaptorPoints) } @@ -406,7 +436,8 @@ object DLCMessage { def fromMessage( accept: LnMessage[DLCAcceptTLV], - offer: DLCOffer): DLCAccept = { + offer: DLCOffer + ): DLCAccept = { fromTLV(accept.tlv, offer) } } @@ -415,8 +446,8 @@ object DLCMessage { cetSigs: CETSignatures, refundSig: PartialSignature, fundingSigs: FundingSignatures, - contractId: ByteVector) - extends DLCMessage { + contractId: ByteVector + ) extends DLCMessage { def toTLV: DLCSignTLV = { DLCSignTLV( @@ -439,7 +470,8 @@ object DLCMessage { sign: DLCSignTLV, fundingPubKey: ECPublicKey, adaptorPoints: Vector[ECPublicKey], - fundingOutPoints: Vector[TransactionOutPoint]): DLCSign = { + fundingOutPoints: Vector[TransactionOutPoint] + ): DLCSign = { val outcomeSigs = sign.cetSignatures match { case CETSignaturesV0TLV(sigs) => adaptorPoints.zip(sigs) @@ -454,7 +486,9 @@ object DLCMessage { val refundSig = PartialSignature( fundingPubKey, ECDigitalSignature( - sign.refundSignature.bytes :+ HashType.sigHashAll.byte)) + sign.refundSignature.bytes :+ HashType.sigHashAll.byte + ) + ) DLCSign( cetSigs = CETSignatures(outcomeSigs), refundSig = refundSig, @@ -464,10 +498,12 @@ object DLCMessage { } def fromTLV(sign: DLCSignTLV, offer: DLCOffer): DLCSign = { - fromTLV(sign, - offer.pubKeys.fundingKey, - offer.contractInfo.adaptorPoints, - offer.fundingInputs.map(_.outPoint)) + fromTLV( + sign, + offer.pubKeys.fundingKey, + offer.contractInfo.adaptorPoints, + offer.fundingInputs.map(_.outPoint) + ) } def fromMessage(sign: LnMessage[DLCSignTLV], offer: DLCOffer): DLCSign = { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCPayoutCurve.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCPayoutCurve.scala index 3d064af6ad..915ecdd2fa 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCPayoutCurve.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCPayoutCurve.scala @@ -14,15 +14,17 @@ import scala.util.{Failure, Success, Try} /** A DLC payout curve defined by piecewise interpolating points */ case class DLCPayoutCurve( pieces: OrderedDLCPayoutCurvePieces, - serializationVersion: DLCSerializationVersion) - extends TLVSerializable[PayoutFunctionV0TLV] { + serializationVersion: DLCSerializationVersion +) extends TLVSerializable[PayoutFunctionV0TLV] { val endpoints: Vector[OutcomePayoutPoint] = { pieces.toVector.map(_.leftEndpoint).:+(pieces.last.rightEndpoint) } - require(pieces.map(_.rightEndpoint) == endpoints.tail, - s"Endpoints must line up: $this") + require( + pieces.map(_.rightEndpoint) == endpoints.tail, + s"Endpoints must line up: $this" + ) override def toTLV: PayoutFunctionV0TLV = { val tlvEndpoints = endpoints.map(_.toTLVPoint) @@ -61,7 +63,8 @@ case class DLCPayoutCurve( def getPayout( outcome: Long, rounding: RoundingIntervals, - totalCollateral: Satoshis): Satoshis = { + totalCollateral: Satoshis + ): Satoshis = { val Indexed(func, _) = componentFor(outcome) func(outcome, rounding, totalCollateral) } @@ -74,7 +77,8 @@ case class DLCPayoutCurve( def apply( outcome: Long, rounding: RoundingIntervals, - totalCollateral: Satoshis): Satoshis = + totalCollateral: Satoshis + ): Satoshis = getPayout(outcome, rounding, totalCollateral) def flip(totalCollateral: Satoshis): DLCPayoutCurve = { @@ -86,7 +90,8 @@ case class DLCPayoutCurve( object DLCPayoutCurve extends TLVDeserializable[PayoutFunctionV0TLV, DLCPayoutCurve]( - PayoutFunctionV0TLV) { + PayoutFunctionV0TLV + ) { override def fromTLV(tlv: PayoutFunctionV0TLV): DLCPayoutCurve = { val pieces = @@ -100,9 +105,12 @@ object DLCPayoutCurve def polynomialInterpolate( points: Vector[PiecewisePolynomialPoint], - serializationVersion: DLCSerializationVersion): DLCPayoutCurve = { - require(points.head.isEndpoint && points.last.isEndpoint, - s"First and last points must be endpoints: $points") + serializationVersion: DLCSerializationVersion + ): DLCPayoutCurve = { + require( + points.head.isEndpoint && points.last.isEndpoint, + s"First and last points must be endpoints: $points" + ) val initMidpoints = Vector.empty[PiecewisePolynomialMidpoint] val initCurvePieces = Vector.empty[DLCPolynomialPayoutCurvePiece] @@ -117,9 +125,11 @@ object DLCPayoutCurve .+:(lastEndpoint) .:+(endpoint) val points = all.map(_.toOutcomePayoutPoint) - (endpoint, - Vector.empty, - piecesSoFar.:+(DLCPolynomialPayoutCurvePiece(points))) + ( + endpoint, + Vector.empty, + piecesSoFar.:+(DLCPolynomialPayoutCurvePiece(points)) + ) } } @@ -129,7 +139,8 @@ object DLCPayoutCurve def fromPoints( points: Vector[TLVPoint], - serializationVersion: DLCSerializationVersion): DLCPayoutCurve = { + serializationVersion: DLCSerializationVersion + ): DLCPayoutCurve = { val pieceEndpoints = points.map { p => PiecewisePolynomialEndpoint(p.outcome, p.value) @@ -202,7 +213,8 @@ object PiecewisePolynomialPoint { def apply( outcome: Long, payout: BigDecimal, - isEndpoint: Boolean): PiecewisePolynomialPoint = { + isEndpoint: Boolean + ): PiecewisePolynomialPoint = { if (isEndpoint) { PiecewisePolynomialEndpoint(outcome, payout) } else { @@ -213,7 +225,8 @@ object PiecewisePolynomialPoint { def apply( outcome: Long, payout: CurrencyUnit, - isEndpoint: Boolean): PiecewisePolynomialPoint = { + isEndpoint: Boolean + ): PiecewisePolynomialPoint = { PiecewisePolynomialPoint(outcome, payout.toBigDecimal, isEndpoint) } } @@ -246,8 +259,10 @@ sealed trait DLCPayoutCurvePiece extends TLVSerializable[PayoutCurvePieceTLV] { def leftEndpoint: OutcomePayoutPoint def rightEndpoint: OutcomePayoutPoint - require(leftEndpoint.outcome < rightEndpoint.outcome, - s"Points must be ascending: $this") + require( + leftEndpoint.outcome < rightEndpoint.outcome, + s"Points must be ascending: $this" + ) def apply(outcome: Long): Satoshis @@ -258,7 +273,8 @@ sealed trait DLCPayoutCurvePiece extends TLVSerializable[PayoutCurvePieceTLV] { def apply( outcome: Long, rounding: RoundingIntervals, - totalCollateral: Satoshis): Satoshis = { + totalCollateral: Satoshis + ): Satoshis = { val rounded = rounding.round(outcome, apply(outcome)).toLong val modified = math.min(math.max(rounded, 0), totalCollateral.toLong) @@ -270,7 +286,8 @@ sealed trait DLCPayoutCurvePiece extends TLVSerializable[PayoutCurvePieceTLV] { Satoshis( bd.setScale(6, RoundingMode.HALF_UP) .setScale(0, RoundingMode.FLOOR) - .toLongExact) + .toLongExact + ) } def flip(totalCollateral: Satoshis): DLCPayoutCurvePiece @@ -281,16 +298,21 @@ object DLCPayoutCurvePiece { def fromTLV( leftEndpoint: TLVPoint, curvePiece: PayoutCurvePieceTLV, - rightEndpoint: TLVPoint): DLCPayoutCurvePiece = { + rightEndpoint: TLVPoint + ): DLCPayoutCurvePiece = { curvePiece match { case polynomial: PolynomialPayoutCurvePieceTLV => - DLCPolynomialPayoutCurvePiece.fromTLV(leftEndpoint, - polynomial, - rightEndpoint) + DLCPolynomialPayoutCurvePiece.fromTLV( + leftEndpoint, + polynomial, + rightEndpoint + ) case hyperbola: HyperbolaPayoutCurvePieceTLV => - DLCHyperbolaPayoutCurvePiece.fromTLV(leftEndpoint, - hyperbola, - rightEndpoint) + DLCHyperbolaPayoutCurvePiece.fromTLV( + leftEndpoint, + hyperbola, + rightEndpoint + ) } } } @@ -304,8 +326,8 @@ case class DLCHyperbolaPayoutCurvePiece( c: BigDecimal, d: BigDecimal, leftEndpoint: OutcomePayoutPoint, - rightEndpoint: OutcomePayoutPoint) - extends DLCPayoutCurvePiece + rightEndpoint: OutcomePayoutPoint +) extends DLCPayoutCurvePiece with TLVSerializable[HyperbolaPayoutCurvePieceTLV] { require(a * d != b * c, s"a*d cannot equal b*c: $this") @@ -330,8 +352,10 @@ case class DLCHyperbolaPayoutCurvePiece( resultT match { case Success(result) => result case Failure(err) => - throw new IllegalArgumentException(s"Illegal input outcome $outcome.", - err) + throw new IllegalArgumentException( + s"Illegal input outcome $outcome.", + err + ) } } @@ -367,7 +391,8 @@ object DLCHyperbolaPayoutCurvePiece { def fromTLV( leftEndpoint: TLVPoint, curvePiece: HyperbolaPayoutCurvePieceTLV, - rightEndpoint: TLVPoint): DLCHyperbolaPayoutCurvePiece = { + rightEndpoint: TLVPoint + ): DLCHyperbolaPayoutCurvePiece = { DLCHyperbolaPayoutCurvePiece( curvePiece.usePositivePiece, curvePiece.translateOutcome.toBigDecimal, @@ -382,7 +407,9 @@ object DLCHyperbolaPayoutCurvePiece { } } -/** A single piece of a larger piecewise function defined between left and right endpoints */ +/** A single piece of a larger piecewise function defined between left and right + * endpoints + */ sealed trait DLCPolynomialPayoutCurvePiece extends DLCPayoutCurvePiece with TLVSerializable[PolynomialPayoutCurvePieceTLV] { @@ -393,14 +420,20 @@ sealed trait DLCPolynomialPayoutCurvePiece } midpoints.headOption.foreach { firstMidpoint => - require(leftEndpoint.outcome < firstMidpoint.outcome, - s"Points must be ascending: $this") - require(midpoints.init.zip(midpoints.tail).forall { case (m1, m2) => - m1.outcome < m2.outcome - }, - s"Points must be ascending: $this") - require(rightEndpoint.outcome > midpoints.last.outcome, - s"Points must be ascending: $this") + require( + leftEndpoint.outcome < firstMidpoint.outcome, + s"Points must be ascending: $this" + ) + require( + midpoints.init.zip(midpoints.tail).forall { case (m1, m2) => + m1.outcome < m2.outcome + }, + s"Points must be ascending: $this" + ) + require( + rightEndpoint.outcome > midpoints.last.outcome, + s"Points must be ascending: $this" + ) } override def toTLV: PolynomialPayoutCurvePieceTLV = { @@ -408,7 +441,8 @@ sealed trait DLCPolynomialPayoutCurvePiece } override def flip( - totalCollateral: Satoshis): DLCPolynomialPayoutCurvePiece = { + totalCollateral: Satoshis + ): DLCPolynomialPayoutCurvePiece = { val flippedPoints = points.map { point => point.copy(payout = totalCollateral.toLong - point.payout) } @@ -420,7 +454,8 @@ sealed trait DLCPolynomialPayoutCurvePiece object DLCPolynomialPayoutCurvePiece { def apply( - points: Vector[OutcomePayoutPoint]): DLCPolynomialPayoutCurvePiece = { + points: Vector[OutcomePayoutPoint] + ): DLCPolynomialPayoutCurvePiece = { points match { case Vector(left: OutcomePayoutPoint, right: OutcomePayoutPoint) => if (left.payout == right.payout) { @@ -428,14 +463,18 @@ object DLCPolynomialPayoutCurvePiece { } else { OutcomePayoutLine(left, right) } - case Vector(left: OutcomePayoutPoint, - mid: OutcomePayoutPoint, - right: OutcomePayoutPoint) => + case Vector( + left: OutcomePayoutPoint, + mid: OutcomePayoutPoint, + right: OutcomePayoutPoint + ) => OutcomePayoutQuadratic(left, mid, right) - case Vector(left: OutcomePayoutPoint, - mid1: OutcomePayoutPoint, - mid2: OutcomePayoutPoint, - right: OutcomePayoutPoint) => + case Vector( + left: OutcomePayoutPoint, + mid1: OutcomePayoutPoint, + mid2: OutcomePayoutPoint, + right: OutcomePayoutPoint + ) => OutcomePayoutCubic(left, mid1, mid2, right) case _ => OutcomePayoutPolynomial(points) } @@ -444,7 +483,8 @@ object DLCPolynomialPayoutCurvePiece { def fromTLV( leftEndpoint: TLVPoint, curvePiece: PolynomialPayoutCurvePieceTLV, - rightEndpoint: TLVPoint): DLCPolynomialPayoutCurvePiece = { + rightEndpoint: TLVPoint + ): DLCPolynomialPayoutCurvePiece = { val tlvPoints = curvePiece.midpoints.+:(leftEndpoint).:+(rightEndpoint) val points = tlvPoints.map(OutcomePayoutPoint.fromTLVPoint) @@ -454,10 +494,12 @@ object DLCPolynomialPayoutCurvePiece { case class OutcomePayoutConstant( leftEndpoint: OutcomePayoutPoint, - rightEndpoint: OutcomePayoutPoint) - extends DLCPolynomialPayoutCurvePiece { - require(leftEndpoint.payout == rightEndpoint.payout, - "Constant function must have same values on endpoints") + rightEndpoint: OutcomePayoutPoint +) extends DLCPolynomialPayoutCurvePiece { + require( + leftEndpoint.payout == rightEndpoint.payout, + "Constant function must have same values on endpoints" + ) override lazy val midpoints: Vector[OutcomePayoutPoint] = Vector.empty @@ -465,11 +507,13 @@ case class OutcomePayoutConstant( bigDecimalSats(leftEndpoint.payout) } -/** A Line between left and right endpoints defining a piece of a larger payout curve */ +/** A Line between left and right endpoints defining a piece of a larger payout + * curve + */ case class OutcomePayoutLine( leftEndpoint: OutcomePayoutPoint, - rightEndpoint: OutcomePayoutPoint) - extends DLCPolynomialPayoutCurvePiece { + rightEndpoint: OutcomePayoutPoint +) extends DLCPolynomialPayoutCurvePiece { override lazy val midpoints: Vector[OutcomePayoutPoint] = Vector.empty lazy val slope: BigDecimal = { @@ -484,20 +528,23 @@ case class OutcomePayoutLine( } } -/** A quadratic between left and right endpoints defining a piece of a larger payout curve. - * A quadratic equation defines a parabola: https://en.wikipedia.org/wiki/Quadratic_function +/** A quadratic between left and right endpoints defining a piece of a larger + * payout curve. A quadratic equation defines a parabola: + * https://en.wikipedia.org/wiki/Quadratic_function */ case class OutcomePayoutQuadratic( leftEndpoint: OutcomePayoutPoint, midpoint: OutcomePayoutPoint, - rightEndpoint: OutcomePayoutPoint) - extends DLCPolynomialPayoutCurvePiece { + rightEndpoint: OutcomePayoutPoint +) extends DLCPolynomialPayoutCurvePiece { override lazy val midpoints: Vector[OutcomePayoutPoint] = Vector(midpoint) private lazy val (x01, x02, x12) = - (leftEndpoint.outcome - midpoint.outcome, - leftEndpoint.outcome - rightEndpoint.outcome, - midpoint.outcome - rightEndpoint.outcome) + ( + leftEndpoint.outcome - midpoint.outcome, + leftEndpoint.outcome - rightEndpoint.outcome, + midpoint.outcome - rightEndpoint.outcome + ) private lazy val (x10, x20, x21) = (-x01, -x02, -x12) @@ -518,38 +565,46 @@ case class OutcomePayoutQuadratic( } } -/** A cubic between left and right endpoints defining a piece of a larger payout curve */ +/** A cubic between left and right endpoints defining a piece of a larger payout + * curve + */ case class OutcomePayoutCubic( leftEndpoint: OutcomePayoutPoint, leftMidpoint: OutcomePayoutPoint, rightMidpoint: OutcomePayoutPoint, - rightEndpoint: OutcomePayoutPoint) - extends DLCPolynomialPayoutCurvePiece { + rightEndpoint: OutcomePayoutPoint +) extends DLCPolynomialPayoutCurvePiece { override lazy val midpoints: Vector[OutcomePayoutPoint] = Vector(leftMidpoint, rightMidpoint) private lazy val (x01, x02, x03, x12, x13, x23) = - (leftEndpoint.outcome - leftMidpoint.outcome, - leftEndpoint.outcome - rightMidpoint.outcome, - leftEndpoint.outcome - rightEndpoint.outcome, - leftMidpoint.outcome - rightMidpoint.outcome, - leftMidpoint.outcome - rightEndpoint.outcome, - rightMidpoint.outcome - rightEndpoint.outcome) + ( + leftEndpoint.outcome - leftMidpoint.outcome, + leftEndpoint.outcome - rightMidpoint.outcome, + leftEndpoint.outcome - rightEndpoint.outcome, + leftMidpoint.outcome - rightMidpoint.outcome, + leftMidpoint.outcome - rightEndpoint.outcome, + rightMidpoint.outcome - rightEndpoint.outcome + ) private lazy val (x10, x20, x30, x21, x31, x32) = (-x01, -x02, -x03, -x12, -x13, -x23) - private lazy val (y0, y1, y2, y3) = (leftEndpoint.payout, - leftMidpoint.payout, - rightMidpoint.payout, - rightEndpoint.payout) + private lazy val (y0, y1, y2, y3) = ( + leftEndpoint.payout, + leftMidpoint.payout, + rightMidpoint.payout, + rightEndpoint.payout + ) private lazy val (c0, c1, c2, c3) = - (y0 / (x01 * x02 * x03), - y1 / (x10 * x12 * x13), - y2 / (x20 * x21 * x23), - y3 / (x30 * x31 * x32)) + ( + y0 / (x01 * x02 * x03), + y1 / (x10 * x12 * x13), + y2 / (x20 * x21 * x23), + y3 / (x30 * x31 * x32) + ) override def apply(outcome: Long): Satoshis = { val x0 = outcome - leftEndpoint.outcome @@ -564,10 +619,12 @@ case class OutcomePayoutCubic( } } -/** A polynomial interpolating points and defining a piece of a larger payout curve */ +/** A polynomial interpolating points and defining a piece of a larger payout + * curve + */ case class OutcomePayoutPolynomial( - override val points: Vector[OutcomePayoutPoint]) - extends DLCPolynomialPayoutCurvePiece { + override val points: Vector[OutcomePayoutPoint] +) extends DLCPolynomialPayoutCurvePiece { override lazy val leftEndpoint: OutcomePayoutPoint = points.head diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCPublicKeys.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCPublicKeys.scala index 4f1e75dc06..fe0cc05dbf 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCPublicKeys.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCPublicKeys.scala @@ -12,15 +12,19 @@ object DLCPublicKeys { def fromPrivKeys( fundingPrivKey: ECPrivateKey, payoutKey: ECPrivateKey, - network: BitcoinNetwork): DLCPublicKeys = { + network: BitcoinNetwork + ): DLCPublicKeys = { fromPubKeys(fundingPrivKey.publicKey, payoutKey.publicKey, network) } def fromPubKeys( fundingKey: ECPublicKey, payoutKey: ECPublicKey, - network: BitcoinNetwork): DLCPublicKeys = { - DLCPublicKeys(fundingKey, - Bech32Address(P2WPKHWitnessSPKV0(payoutKey), network)) + network: BitcoinNetwork + ): DLCPublicKeys = { + DLCPublicKeys( + fundingKey, + Bech32Address(P2WPKHWitnessSPKV0(payoutKey), network) + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCSignatures.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCSignatures.scala index 9d1545ae69..dea80d707b 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCSignatures.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCSignatures.scala @@ -9,14 +9,14 @@ import org.bitcoins.crypto.{ECAdaptorSignature, ECPublicKey} sealed trait DLCSignatures case class FundingSignatures( - sigs: Vector[(TransactionOutPoint, ScriptWitnessV0)]) - extends SeqWrapper[(TransactionOutPoint, ScriptWitnessV0)] + sigs: Vector[(TransactionOutPoint, ScriptWitnessV0)] +) extends SeqWrapper[(TransactionOutPoint, ScriptWitnessV0)] with DLCSignatures { require(sigs.nonEmpty, s"FundingSignatures.sigs cannot be empty") - override protected def wrapped: Vector[ - (TransactionOutPoint, ScriptWitnessV0)] = sigs + override protected def wrapped + : Vector[(TransactionOutPoint, ScriptWitnessV0)] = sigs def get(outPoint: TransactionOutPoint): Option[ScriptWitnessV0] = { sigs.find(_._1 == outPoint).map(_._2) @@ -38,8 +38,10 @@ case class FundingSignatures( case class CETSignatures(outcomeSigs: Vector[(ECPublicKey, ECAdaptorSignature)]) extends DLCSignatures { - require(outcomeSigs.nonEmpty, - s"CETSignatures cannot have outcomeSigs be empty") + require( + outcomeSigs.nonEmpty, + s"CETSignatures cannot have outcomeSigs be empty" + ) lazy val keys: Vector[ECPublicKey] = outcomeSigs.map(_._1) lazy val adaptorSigs: Vector[ECAdaptorSignature] = outcomeSigs.map(_._2) @@ -54,6 +56,7 @@ case class CETSignatures(outcomeSigs: Vector[(ECPublicKey, ECAdaptorSignature)]) .find(_._1 == key) .map(_._2) .getOrElse( - throw new IllegalArgumentException(s"No signature found for $key")) + throw new IllegalArgumentException(s"No signature found for $key") + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCState.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCState.scala index dd2da19092..017e272546 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCState.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCState.scala @@ -13,17 +13,17 @@ object DLCState extends StringFactory[DLCState] { /** Means that someone has attempted to claim the DLC */ sealed abstract class ClosedState extends DLCState - /** A state meant to represent we are computing adaptor sigs. - * Computing adaptor signatures can take awhile on certain hardware - * (raspberry pi) which is why we model this state + /** A state meant to represent we are computing adaptor sigs. Computing + * adaptor signatures can take awhile on certain hardware (raspberry pi) + * which is why we model this state */ sealed abstract class AdaptorSigComputationState extends InProgressState /** A state that requires an oracle outcome to be valid */ sealed trait ClosedViaOracleOutcomeState extends ClosedState - /** The state where an offer has been created but no - * accept message has yet been created/received. + /** The state where an offer has been created but no accept message has yet + * been created/received. */ final case object Offered extends InProgressState { override val order: Int = 0 @@ -33,8 +33,8 @@ object DLCState extends StringFactory[DLCState] { override val order: Int = 1 } - /** The state where an offer has been accepted but - * no sign message has yet been created/received. + /** The state where an offer has been accepted but no sign message has yet + * been created/received. */ final case object Accepted extends InProgressState { override val order: Int = 2 @@ -44,62 +44,62 @@ object DLCState extends StringFactory[DLCState] { override val order: Int = 3 } - /** The state where the initiating party has created - * a sign message in response to an accept message - * but the DLC funding transaction has not yet been - * broadcasted to the network. + /** The state where the initiating party has created a sign message in + * response to an accept message but the DLC funding transaction has not yet + * been broadcasted to the network. */ final case object Signed extends InProgressState { override val order: Int = 4 } - /** The state where the accepting (non-initiating) - * party has broadcasted the DLC funding transaction - * to the blockchain, and it has not yet been confirmed. + /** The state where the accepting (non-initiating) party has broadcasted the + * DLC funding transaction to the blockchain, and it has not yet been + * confirmed. */ final case object Broadcasted extends InProgressState { override val order: Int = 5 } - /** The state where the DLC funding transaction has been - * confirmed on-chain and no execution paths have yet been - * initiated. + /** The state where the DLC funding transaction has been confirmed on-chain + * and no execution paths have yet been initiated. */ final case object Confirmed extends InProgressState { override val order: Int = 6 } - /** The state where one of the CETs has been accepted by the network - * and executed by ourselves. + /** The state where one of the CETs has been accepted by the network and + * executed by ourselves. */ final case object Claimed extends ClosedViaOracleOutcomeState { override val order: Int = 7 } - /** The state where one of the CETs has been accepted by the network - * and executed by a remote party. + /** The state where one of the CETs has been accepted by the network and + * executed by a remote party. */ final case object RemoteClaimed extends ClosedViaOracleOutcomeState { override val order: Int = 7 } - /** The state where the DLC refund transaction has been - * accepted by the network. + /** The state where the DLC refund transaction has been accepted by the + * network. */ final case object Refunded extends ClosedState { val order: Int = 7 } - val all: Vector[DLCState] = Vector(Offered, - AcceptComputingAdaptorSigs, - Accepted, - SignComputingAdaptorSigs, - Signed, - Broadcasted, - Confirmed, - Claimed, - RemoteClaimed, - Refunded) + val all: Vector[DLCState] = Vector( + Offered, + AcceptComputingAdaptorSigs, + Accepted, + SignComputingAdaptorSigs, + Signed, + Broadcasted, + Confirmed, + Claimed, + RemoteClaimed, + Refunded + ) /** The states where you can cancel a DLC in your wallet */ val cancellableState = Vector( diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCStatus.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCStatus.scala index bef083e242..7a495c1cd5 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCStatus.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCStatus.scala @@ -63,11 +63,13 @@ sealed trait ClosedDLCStatus extends SignedDLCStatus { def counterPartyPayout: CurrencyUnit def accounting: DLCAccounting = { - DLCAccounting(dlcId, - localCollateral, - remoteCollateral, - myPayout, - counterPartyPayout) + DLCAccounting( + dlcId, + localCollateral, + remoteCollateral, + myPayout, + counterPartyPayout + ) } def pnl: CurrencyUnit = accounting.pnl @@ -112,8 +114,8 @@ object DLCStatus { totalCollateral: CurrencyUnit, localCollateral: CurrencyUnit, payoutAddress: Option[PayoutAddress], - peer: Option[String]) - extends AcceptedDLCStatus { + peer: Option[String] + ) extends AcceptedDLCStatus { override val state: DLCState.AcceptComputingAdaptorSigs.type = DLCState.AcceptComputingAdaptorSigs @@ -131,8 +133,8 @@ object DLCStatus { totalCollateral: CurrencyUnit, localCollateral: CurrencyUnit, payoutAddress: Option[PayoutAddress], - peer: Option[String]) - extends AcceptedDLCStatus { + peer: Option[String] + ) extends AcceptedDLCStatus { override val state: DLCState.Accepted.type = DLCState.Accepted } @@ -149,8 +151,8 @@ object DLCStatus { localCollateral: CurrencyUnit, fundingTxId: DoubleSha256DigestBE, payoutAddress: Option[PayoutAddress], - peer: Option[String]) - extends SignedDLCStatus { + peer: Option[String] + ) extends SignedDLCStatus { override val state: DLCState.SignComputingAdaptorSigs.type = DLCState.SignComputingAdaptorSigs @@ -169,8 +171,8 @@ object DLCStatus { localCollateral: CurrencyUnit, fundingTxId: DoubleSha256DigestBE, payoutAddress: Option[PayoutAddress], - peer: Option[String]) - extends SignedDLCStatus { + peer: Option[String] + ) extends SignedDLCStatus { override val state: DLCState.Signed.type = DLCState.Signed } @@ -187,8 +189,8 @@ object DLCStatus { localCollateral: CurrencyUnit, fundingTxId: DoubleSha256DigestBE, payoutAddress: Option[PayoutAddress], - peer: Option[String]) - extends SignedDLCStatus { + peer: Option[String] + ) extends SignedDLCStatus { override val state: DLCState.Broadcasted.type = DLCState.Broadcasted } @@ -205,8 +207,8 @@ object DLCStatus { localCollateral: CurrencyUnit, fundingTxId: DoubleSha256DigestBE, payoutAddress: Option[PayoutAddress], - peer: Option[String]) - extends SignedDLCStatus { + peer: Option[String] + ) extends SignedDLCStatus { override val state: DLCState.Confirmed.type = DLCState.Confirmed } @@ -228,8 +230,8 @@ object DLCStatus { myPayout: CurrencyUnit, counterPartyPayout: CurrencyUnit, payoutAddress: Option[PayoutAddress], - peer: Option[String]) - extends ClaimedDLCStatus { + peer: Option[String] + ) extends ClaimedDLCStatus { override val state: DLCState.Claimed.type = DLCState.Claimed } @@ -251,8 +253,8 @@ object DLCStatus { myPayout: CurrencyUnit, counterPartyPayout: CurrencyUnit, payoutAddress: Option[PayoutAddress], - peer: Option[String]) - extends ClaimedDLCStatus { + peer: Option[String] + ) extends ClaimedDLCStatus { override val state: DLCState.RemoteClaimed.type = DLCState.RemoteClaimed override val oracleSigs: OrderedSchnorrSignatures = @@ -275,8 +277,8 @@ object DLCStatus { myPayout: CurrencyUnit, counterPartyPayout: CurrencyUnit, payoutAddress: Option[PayoutAddress], - peer: Option[String]) - extends ClosedDLCStatus { + peer: Option[String] + ) extends ClosedDLCStatus { override val state: DLCState.Refunded.type = DLCState.Refunded } @@ -309,7 +311,8 @@ object DLCStatus { } def getOracleSignatures( - status: DLCStatus): Option[OrderedSchnorrSignatures] = { + status: DLCStatus + ): Option[OrderedSchnorrSignatures] = { status match { case claimed: ClaimedDLCStatus => Some(claimed.oracleSigs) @@ -319,16 +322,16 @@ object DLCStatus { } } - /** Calculates the outcome and signature for the CET - * that was broadcast on chain. + /** Calculates the outcome and signature for the CET that was broadcast on + * chain. */ def calculateOutcomeAndSig( isInitiator: Boolean, offer: DLCOffer, accept: DLCAccept, sign: DLCSign, - cet: WitnessTransaction): Option[ - (SchnorrDigitalSignature, OracleOutcome)] = { + cet: WitnessTransaction + ): Option[(SchnorrDigitalSignature, OracleOutcome)] = { val localAdaptorSigs = if (isInitiator) { sign.cetSigs.outcomeSigs } else { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCTemplate.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCTemplate.scala index 8df2c70918..1506b21cbb 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCTemplate.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCTemplate.scala @@ -18,12 +18,15 @@ sealed trait DLCTemplate { def toContractInfo: ContractInfo - require(oracleThreshold > 0, - s"Oracle threshold must be greater than zero, got $oracleThreshold") + require( + oracleThreshold > 0, + s"Oracle threshold must be greater than zero, got $oracleThreshold" + ) require(oracles.nonEmpty, "Must provide at least one oracle") require( oracleThreshold <= oracles.size, - s"Oracle threshold ($oracleThreshold) cannot be greater than number of oracles ${oracles.size}") + s"Oracle threshold ($oracleThreshold) cannot be greater than number of oracles ${oracles.size}" + ) } case class SingleOracleDLCTemplate( @@ -36,7 +39,8 @@ case class SingleOracleDLCTemplate( override val oracleThreshold: Int = 1 override val oracleInfo: NumericSingleOracleInfo = NumericSingleOracleInfo( - oracle) + oracle + ) override val toContractInfo: ContractInfo = { val pair: NumericPair = @@ -55,19 +59,24 @@ case class MultiOracleDLCTemplate( contractDescriptor: NumericContractDescriptor ) extends DLCTemplate { - require(maxErrorExp > 0, - s"maxErrorExp must be greater than 0, got $maxErrorExp") + require( + maxErrorExp > 0, + s"maxErrorExp must be greater than 0, got $maxErrorExp" + ) require(minFailExp > 0, s"minFailExp must be greater than 0, got $minFailExp") require( minFailExp < maxErrorExp, - s"minFailExp ($minFailExp) must be less than maxErrorExp ($maxErrorExp)") + s"minFailExp ($minFailExp) must be less than maxErrorExp ($maxErrorExp)" + ) override val oracleInfo: NumericMultiOracleInfo = - NumericMultiOracleInfo(threshold = oracleThreshold, - announcements = OrderedAnnouncements(oracles), - maxErrorExp = maxErrorExp, - minFailExp = minFailExp, - maximizeCoverage = maximizeCoverage) + NumericMultiOracleInfo( + threshold = oracleThreshold, + announcements = OrderedAnnouncements(oracles), + maxErrorExp = maxErrorExp, + minFailExp = minFailExp, + maximizeCoverage = maximizeCoverage + ) override val toContractInfo: ContractInfo = { val pair: NumericPair = diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCTimeouts.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCTimeouts.scala index 16966cc8bf..94364ca3a8 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCTimeouts.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/DLCTimeouts.scala @@ -6,8 +6,10 @@ import org.bitcoins.core.protocol.BlockTimeStamp import org.bitcoins.crypto.{Factory, NetworkElement} import scodec.bits.ByteVector -/** @param contractMaturity The CLTV in milliseconds when a signature is expected - * @param contractTimeout The CLTV timeout in milliseconds after which the refund tx is valid +/** @param contractMaturity + * The CLTV in milliseconds when a signature is expected + * @param contractTimeout + * The CLTV timeout in milliseconds after which the refund tx is valid */ case class DLCTimeouts( contractMaturity: BlockTimeStamp, @@ -17,11 +19,13 @@ case class DLCTimeouts( case (_: BlockTime, _: BlockTime) => if (contractMaturity.toUInt32 >= contractTimeout.toUInt32) throw new IllegalArgumentException( - s"contract must mature before it expires, ${contractTimeout.toUInt32} >= ${contractMaturity.toUInt32}") + s"contract must mature before it expires, ${contractTimeout.toUInt32} >= ${contractMaturity.toUInt32}" + ) case (_: BlockHeight, _: BlockHeight) => if (contractMaturity.toUInt32 >= contractTimeout.toUInt32) throw new IllegalArgumentException( - s"contract must mature before it expires, ${contractTimeout.toUInt32} >= ${contractMaturity.toUInt32}") + s"contract must mature before it expires, ${contractTimeout.toUInt32} >= ${contractMaturity.toUInt32}" + ) case (_: BlockTime, _: BlockHeight) | (_: BlockHeight, _: BlockTime) => () } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleInfo.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleInfo.scala index f95576719e..0ea2b0394a 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleInfo.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleInfo.scala @@ -4,8 +4,8 @@ import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.util.sorted._ import org.bitcoins.crypto._ -/** Specifies the set of oracles and their corresponding announcements - * and parameters to be used in a DLC. +/** Specifies the set of oracles and their corresponding announcements and + * parameters to be used in a DLC. */ sealed trait OracleInfo extends TLVSerializable[OracleInfoTLV] { @@ -47,9 +47,12 @@ object OracleInfo None case numeric: NumericMultiOracleInfo => Some( - OracleParamsV0TLV(numeric.maxErrorExp, - numeric.minFailExp, - numeric.maximizeCoverage)) + OracleParamsV0TLV( + numeric.maxErrorExp, + numeric.minFailExp, + numeric.maximizeCoverage + ) + ) } } } @@ -79,8 +82,8 @@ sealed trait SingleOracleInfo /** The order of the given sigs should correspond to the given outcome. */ def verifySigs(outcome: DLCOutcomeType, sigs: OracleSignatures): Boolean - /** Computes the signature point (aka signature anticipation) for a given outcome. - * This point is used for adaptor signing. + /** Computes the signature point (aka signature anticipation) for a given + * outcome. This point is used for adaptor signing. */ def sigPoint(outcome: DLCOutcomeType): ECPublicKey = { publicKey.computeSigPoint(outcome.serialized, nonces.toVector) @@ -100,7 +103,8 @@ sealed trait SingleOracleInfo object SingleOracleInfo extends TLVDeserializable[OracleInfoV0TLV, SingleOracleInfo]( - OracleInfoV0TLV) { + OracleInfoV0TLV + ) { def apply(announcement: OracleAnnouncementTLV): SingleOracleInfo = { announcement.eventTLV.eventDescriptor match { @@ -126,9 +130,11 @@ object SingleOracleInfo case class EnumSingleOracleInfo(announcement: OracleAnnouncementTLV) extends SingleOracleInfo with EnumOracleInfo { - require(announcement.eventTLV.eventDescriptor - .isInstanceOf[EnumEventDescriptorV0TLV], - s"Enum OracleInfo requires EnumEventDescriptor, $announcement") + require( + announcement.eventTLV.eventDescriptor + .isInstanceOf[EnumEventDescriptorV0TLV], + s"Enum OracleInfo requires EnumEventDescriptor, $announcement" + ) val nonce: SchnorrNonce = { announcement.eventTLV match { @@ -140,40 +146,49 @@ case class EnumSingleOracleInfo(announcement: OracleAnnouncementTLV) /** @inheritdoc */ override def verifySigs( outcome: DLCOutcomeType, - sigs: OracleSignatures): Boolean = { + sigs: OracleSignatures + ): Boolean = { outcome match { case EnumOutcome(outcome) => sigs match { case _: NumericOracleSignatures => throw new IllegalArgumentException( - s"Expected one signature, got $sigs") + s"Expected one signature, got $sigs" + ) case EnumOracleSignature(_, sig) => if (sig.rx != nonce) { throw new IllegalArgumentException( - s"Expected R value of $nonce, got $sig") + s"Expected R value of $nonce, got $sig" + ) } else { - publicKey.verify(CryptoUtil.sha256DLCAttestation(outcome).bytes, - sig) + publicKey.verify( + CryptoUtil.sha256DLCAttestation(outcome).bytes, + sig + ) } } case UnsignedNumericOutcome(_) | _: SignedNumericOutcome => throw new IllegalArgumentException( - s"Expected EnumOutcome, got $outcome") + s"Expected EnumOutcome, got $outcome" + ) } } } object EnumSingleOracleInfo extends TLVDeserializable[OracleInfoV0TLV, EnumSingleOracleInfo]( - OracleInfoV0TLV) { + OracleInfoV0TLV + ) { def dummyForKeys( privKey: ECPrivateKey, nonce: SchnorrNonce, - events: Vector[EnumOutcome]): EnumSingleOracleInfo = { + events: Vector[EnumOutcome] + ): EnumSingleOracleInfo = { EnumSingleOracleInfo( OracleAnnouncementV0TLV - .dummyForEventsAndKeys(privKey, nonce, events)) + .dummyForEventsAndKeys(privKey, nonce, events) + ) } override def fromTLV(tlv: OracleInfoV0TLV): EnumSingleOracleInfo = { @@ -181,29 +196,34 @@ object EnumSingleOracleInfo } } -/** Specifies a single oracles' information for an Numeric Outcome DLC - * through an announcement +/** Specifies a single oracles' information for an Numeric Outcome DLC through + * an announcement */ case class NumericSingleOracleInfo(announcement: OracleAnnouncementTLV) extends SingleOracleInfo with NumericOracleInfo { - require(announcement.eventTLV.eventDescriptor - .isInstanceOf[NumericEventDescriptorTLV], - s"Numeric OracleInfo requires NumericEventDescriptor, $announcement") + require( + announcement.eventTLV.eventDescriptor + .isInstanceOf[NumericEventDescriptorTLV], + s"Numeric OracleInfo requires NumericEventDescriptor, $announcement" + ) /** @inheritdoc */ override def verifySigs( outcome: DLCOutcomeType, - oracleSignatures: OracleSignatures): Boolean = { + oracleSignatures: OracleSignatures + ): Boolean = { require(oracleSignatures.nonEmpty, "At least one signature is required") require( oracleSignatures.length <= nonces.length, - s"Too many signatures (expected at most ${nonces.length}), got $oracleSignatures") + s"Too many signatures (expected at most ${nonces.length}), got $oracleSignatures" + ) outcome match { case EnumOutcome(_) | _: SignedNumericOutcome => throw new IllegalArgumentException( - s"Expected numeric outcome, got $outcome") + s"Expected numeric outcome, got $outcome" + ) case UnsignedNumericOutcome(digits) => val sigs: Vector[SchnorrDigitalSignature] = oracleSignatures match { case unsorted: NumericOracleSignaturesUnsorted => @@ -218,12 +238,15 @@ case class NumericSingleOracleInfo(announcement: OracleAnnouncementTLV) .zip(sigs.take(digits.length).zip(nonces.take(digits.length))) .foldLeft(digits.length <= sigs.length) { case (result, (digit, (sig, nonce))) => - require(sig.rx == nonce, - s"Unexpected nonce in ${sig.hex}, expected ${nonce.hex}") + require( + sig.rx == nonce, + s"Unexpected nonce in ${sig.hex}, expected ${nonce.hex}" + ) result && publicKey.verify( CryptoUtil.sha256DLCAttestation(digit.toString).bytes, - sig) + sig + ) } } } @@ -233,14 +256,16 @@ object NumericSingleOracleInfo { def dummyForKeys( privKey: ECPrivateKey, - nonces: OrderedNonces): NumericSingleOracleInfo = { + nonces: OrderedNonces + ): NumericSingleOracleInfo = { NumericSingleOracleInfo( - OracleAnnouncementV0TLV.dummyForKeys(privKey, nonces)) + OracleAnnouncementV0TLV.dummyForKeys(privKey, nonces) + ) } } -/** Represents the oracle information for more than one oracle through - * multiple announcements. +/** Represents the oracle information for more than one oracle through multiple + * announcements. */ sealed trait MultiOracleInfo[+T <: SingleOracleInfo] extends OracleInfo @@ -251,14 +276,15 @@ sealed trait MultiOracleInfo[+T <: SingleOracleInfo] require( announcements.length >= threshold, - s"Cannot have threshold ($threshold) above the number of oracles (${announcements.length})") + s"Cannot have threshold ($threshold) above the number of oracles (${announcements.length})" + ) // Override this with a val to invoke requirements def singleOracleInfos: Vector[T] } -/** Represents the oracle information for more than one oracle where - * all oracles sign exactly corresponding messages. +/** Represents the oracle information for more than one oracle where all oracles + * sign exactly corresponding messages. */ sealed trait ExactMultiOracleInfo[+T <: SingleOracleInfo] extends MultiOracleInfo[T] @@ -269,9 +295,10 @@ sealed trait ExactMultiOracleInfo[+T <: SingleOracleInfo] } object ExactMultiOracleInfo - extends TLVDeserializable[ - OracleInfoV1TLV, - ExactMultiOracleInfo[SingleOracleInfo]](OracleInfoV1TLV) { + extends TLVDeserializable[OracleInfoV1TLV, + ExactMultiOracleInfo[ + SingleOracleInfo + ]](OracleInfoV1TLV) { def apply(tlv: OracleInfoV1TLV): ExactMultiOracleInfo[SingleOracleInfo] = { tlv.oracles.head.eventTLV.eventDescriptor match { @@ -283,47 +310,48 @@ object ExactMultiOracleInfo } override def fromTLV( - tlv: OracleInfoV1TLV): ExactMultiOracleInfo[SingleOracleInfo] = { + tlv: OracleInfoV1TLV + ): ExactMultiOracleInfo[SingleOracleInfo] = { ExactMultiOracleInfo(tlv) } } -/** Represents the oracle information for more than one oracle where - * all oracles sign exactly corresponding messages from isomorphic Enums. +/** Represents the oracle information for more than one oracle where all oracles + * sign exactly corresponding messages from isomorphic Enums. */ case class EnumMultiOracleInfo( threshold: Int, - announcements: OrderedAnnouncements) - extends ExactMultiOracleInfo[EnumSingleOracleInfo] + announcements: OrderedAnnouncements +) extends ExactMultiOracleInfo[EnumSingleOracleInfo] with EnumOracleInfo { override val singleOracleInfos: Vector[EnumSingleOracleInfo] = announcements.toVector.map(EnumSingleOracleInfo.apply) } -/** Represents the oracle information for more than one oracle where - * all oracles sign exactly equal numeric outcomes. +/** Represents the oracle information for more than one oracle where all oracles + * sign exactly equal numeric outcomes. */ case class NumericExactMultiOracleInfo( threshold: Int, - announcements: OrderedAnnouncements) - extends ExactMultiOracleInfo[NumericSingleOracleInfo] + announcements: OrderedAnnouncements +) extends ExactMultiOracleInfo[NumericSingleOracleInfo] with NumericOracleInfo { val singleOracleInfos: Vector[NumericSingleOracleInfo] = announcements.toVector.map(NumericSingleOracleInfo.apply) } -/** Represents the oracle information and parameters for more than - * one oracle where the oracles may be signing slightly different numeric outcomes. +/** Represents the oracle information and parameters for more than one oracle + * where the oracles may be signing slightly different numeric outcomes. */ case class NumericMultiOracleInfo( threshold: Int, announcements: OrderedAnnouncements, maxErrorExp: Int, minFailExp: Int, - maximizeCoverage: Boolean) - extends MultiOracleInfo[NumericSingleOracleInfo] + maximizeCoverage: Boolean +) extends MultiOracleInfo[NumericSingleOracleInfo] with TLVSerializable[OracleInfoV2TLV] with NumericOracleInfo { @@ -334,25 +362,30 @@ case class NumericMultiOracleInfo( OracleInfoV2TLV( threshold, announcements, - OracleParamsV0TLV(maxErrorExp, minFailExp, maximizeCoverage)) + OracleParamsV0TLV(maxErrorExp, minFailExp, maximizeCoverage) + ) } } object NumericMultiOracleInfo extends TLVDeserializable[OracleInfoV2TLV, NumericMultiOracleInfo]( - OracleInfoV2TLV) { + OracleInfoV2TLV + ) { def apply( threshold: Int, announcements: OrderedAnnouncements, - params: OracleParamsTLV): NumericMultiOracleInfo = { + params: OracleParamsTLV + ): NumericMultiOracleInfo = { params match { case OracleParamsV0TLV(maxErrorExp, minFailExp, maximizeCoverage) => - NumericMultiOracleInfo(threshold, - announcements, - maxErrorExp, - minFailExp, - maximizeCoverage) + NumericMultiOracleInfo( + threshold, + announcements, + maxErrorExp, + minFailExp, + maximizeCoverage + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleOutcome.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleOutcome.scala index a8aedb12ac..94c3c41bd4 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleOutcome.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleOutcome.scala @@ -8,20 +8,23 @@ import org.bitcoins.core.protocol.tlv.{ import org.bitcoins.core.protocol.transaction.WitnessTransaction import org.bitcoins.crypto.{ECPublicKey, SchnorrNonce} -/** OracleOutcomes are in one-to-one correspondence with Contract - * Execution Transactions (CETs) and are defined by a set of oracles - * needed to execute with a given CET, representing a certain outcome - * and using a certain signature point (aka adaptor point). +/** OracleOutcomes are in one-to-one correspondence with Contract Execution + * Transactions (CETs) and are defined by a set of oracles needed to execute + * with a given CET, representing a certain outcome and using a certain + * signature point (aka adaptor point). */ sealed trait OracleOutcome { - /** The oracles whose signatures are needed for execution with this outcome. */ + /** The oracles whose signatures are needed for execution with this outcome. + */ def oracles: Vector[SingleOracleInfo] - /** The DLCOutcomeType this OracleOutcome corresponds to (from a payout perspective). + /** The DLCOutcomeType this OracleOutcome corresponds to (from a payout + * perspective). * - * Note that for the case of multi-oracle numeric outcomes with bounded differences - * allowed between oracles, this corresponds to the primary oracle's outcome. + * Note that for the case of multi-oracle numeric outcomes with bounded + * differences allowed between oracles, this corresponds to the primary + * oracle's outcome. */ def outcome: DLCOutcomeType @@ -29,7 +32,9 @@ sealed trait OracleOutcome { protected def computeSigPoint: ECPublicKey - /** The adaptor point used to encrypt the signatures for this corresponding CET. */ + /** The adaptor point used to encrypt the signatures for this corresponding + * CET. + */ lazy val sigPoint: ECPublicKey = { computeSigPoint } @@ -38,13 +43,13 @@ sealed trait OracleOutcome { def aggregateNonce: SchnorrNonce } -/** Corresponds to a CET in an Enumerated Outcome DLC where some set of `threshold` - * oracles have signed a given EnumOutcome. +/** Corresponds to a CET in an Enumerated Outcome DLC where some set of + * `threshold` oracles have signed a given EnumOutcome. */ case class EnumOracleOutcome( oracles: Vector[EnumSingleOracleInfo], - outcome: EnumOutcome) - extends OracleOutcome { + outcome: EnumOutcome +) extends OracleOutcome { override protected def computeSigPoint: ECPublicKey = { oracles.map(_.sigPoint(outcome)).reduce(_.add(_)) @@ -65,9 +70,11 @@ case class EnumOracleOutcome( /** Corresponds to a CET in an Numeric Outcome DLC where some set of `threshold` * oracles have each signed some NumericOutcome. */ -case class NumericOracleOutcome(override val oraclesAndOutcomes: Vector[ - (NumericSingleOracleInfo, UnsignedNumericOutcome)]) - extends OracleOutcome { +case class NumericOracleOutcome( + override val oraclesAndOutcomes: Vector[ + (NumericSingleOracleInfo, UnsignedNumericOutcome) + ] +) extends OracleOutcome { override def oracles: Vector[NumericSingleOracleInfo] = { oraclesAndOutcomes.map(_._1) @@ -103,7 +110,8 @@ object NumericOracleOutcome { def apply( oracleInfo: NumericSingleOracleInfo, - outcome: UnsignedNumericOutcome): NumericOracleOutcome = { + outcome: UnsignedNumericOutcome + ): NumericOracleOutcome = { NumericOracleOutcome(Vector((oracleInfo, outcome))) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleSignatures.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleSignatures.scala index c19cb8b211..f2a2cb48e8 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleSignatures.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/OracleSignatures.scala @@ -6,7 +6,8 @@ import org.bitcoins.core.util.SeqWrapper import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures import org.bitcoins.crypto.{CryptoUtil, ECPrivateKey, SchnorrDigitalSignature} -/** Corresponds to a set of SchnorrDigitalSignatures given by a single oracle. */ +/** Corresponds to a set of SchnorrDigitalSignatures given by a single oracle. + */ sealed trait OracleSignatures extends SeqWrapper[SchnorrDigitalSignature] { /** This oracle's signatures */ @@ -39,11 +40,14 @@ object OracleSignatures { def apply( oracle: SingleOracleInfo, - attestment: OracleAttestmentTLV): OracleSignatures = { + attestment: OracleAttestmentTLV + ): OracleSignatures = { oracle match { case info: EnumSingleOracleInfo => - require(attestment.sigs.length == 1, - s"Expected one signature, got ${attestment.sigs.toVector}") + require( + attestment.sigs.length == 1, + s"Expected one signature, got ${attestment.sigs.toVector}" + ) EnumOracleSignature(info, attestment.sigs.head) case info: NumericSingleOracleInfo => attestment match { @@ -51,7 +55,7 @@ object OracleSignatures { val sorted = OrderedSchnorrSignatures.fromUnsorted(v0.unsortedSignatures) if (v0.unsortedSignatures == sorted) { - //means they are sorted + // means they are sorted NumericOracleSignaturesSorted(info, v0.sigs) } else { NumericOracleSignaturesUnsorted(info, v0.unsortedSignatures) @@ -62,7 +66,8 @@ object OracleSignatures { def apply( oracle: SingleOracleInfo, - sigs: Vector[SchnorrDigitalSignature]): OracleSignatures = { + sigs: Vector[SchnorrDigitalSignature] + ): OracleSignatures = { oracle match { case info: EnumSingleOracleInfo => require(sigs.length == 1, s"Expected one signature, got ${sigs}") @@ -71,7 +76,7 @@ object OracleSignatures { val sorted = OrderedSchnorrSignatures.fromUnsorted(sigs) if (sigs == sorted) { - //means they are sorted + // means they are sorted NumericOracleSignaturesSorted(info, sorted) } else { NumericOracleSignaturesUnsorted(info, sigs) @@ -79,14 +84,15 @@ object OracleSignatures { } } - /** Computes the aggregate s value from the given signatures to be used - * in the given outcome. + /** Computes the aggregate s value from the given signatures to be used in the + * given outcome. * * This is what is used to decrypt a CET adaptor signature. */ def computeAggregateSignature( outcome: OracleOutcome, - sigs: Vector[OracleSignatures]): ECPrivateKey = { + sigs: Vector[OracleSignatures] + ): ECPrivateKey = { outcome match { case EnumOracleOutcome(_, enumOutcome) => sigs.map(_.aggregateSig(enumOutcome)).reduce(_.add(_)) @@ -105,8 +111,8 @@ object OracleSignatures { /** Wraps a single oracle signature of an Enum event. */ case class EnumOracleSignature( oracle: EnumSingleOracleInfo, - sig: SchnorrDigitalSignature) - extends OracleSignatures { + sig: SchnorrDigitalSignature +) extends OracleSignatures { override val sigs: Vector[SchnorrDigitalSignature] = Vector(sig) lazy val getOutcome: EnumOutcome = { @@ -118,13 +124,18 @@ case class EnumOracleSignature( val outcome = potentialOutcomes .find { potentialOutcome => oracle.publicKey - .verify(CryptoUtil - .sha256DLCAttestation(potentialOutcome.toString) - .bytes, - sig) + .verify( + CryptoUtil + .sha256DLCAttestation(potentialOutcome.toString) + .bytes, + sig + ) } - .getOrElse(throw new IllegalArgumentException( - s"Signature $sig does not match any outcome $potentialOutcomes")) + .getOrElse( + throw new IllegalArgumentException( + s"Signature $sig does not match any outcome $potentialOutcomes" + ) + ) EnumOutcome(outcome) } @@ -146,20 +157,26 @@ sealed trait NumericOracleSignatures extends OracleSignatures { (0 until base) .find { possibleDigit => oracle.publicKey - .verify(CryptoUtil - .sha256DLCAttestation(possibleDigit.toString) - .bytes, - sig) + .verify( + CryptoUtil + .sha256DLCAttestation(possibleDigit.toString) + .bytes, + sig + ) } - .getOrElse(throw new IllegalArgumentException( - s"Signature $sig does not match any digit 0-${base - 1}")) + .getOrElse( + throw new IllegalArgumentException( + s"Signature $sig does not match any digit 0-${base - 1}" + ) + ) } UnsignedNumericOutcome(digits.toVector) } /** Computes the NumericOutcome to which these signatures correspond. */ - def computeOutcome(possibleOutcomes: Vector[DLCOutcomeType]): Option[ - UnsignedNumericOutcome] = { + def computeOutcome( + possibleOutcomes: Vector[DLCOutcomeType] + ): Option[UnsignedNumericOutcome] = { val digitsSigned = getOutcome.digits CETCalculator.searchForNumericOutcome(digitsSigned, possibleOutcomes) @@ -169,16 +186,19 @@ sealed trait NumericOracleSignatures extends OracleSignatures { s"${getClass.getSimpleName}(${oracle.announcement.publicKey}, $sigs)" } -/** Wraps a set of oracle signatures of numeric digits that are sorted by nonces */ +/** Wraps a set of oracle signatures of numeric digits that are sorted by nonces + */ case class NumericOracleSignaturesSorted( oracle: NumericSingleOracleInfo, - sortedSignatures: OrderedSchnorrSignatures) - extends NumericOracleSignatures { + sortedSignatures: OrderedSchnorrSignatures +) extends NumericOracleSignatures { override val sigs: Vector[SchnorrDigitalSignature] = sortedSignatures.toVector } -/** Numeric oracle signatures that are not sorted by their nonce. This is needed for v0 attestations */ +/** Numeric oracle signatures that are not sorted by their nonce. This is needed + * for v0 attestations + */ case class NumericOracleSignaturesUnsorted( oracle: NumericSingleOracleInfo, - sigs: Vector[SchnorrDigitalSignature]) - extends NumericOracleSignatures + sigs: Vector[SchnorrDigitalSignature] +) extends NumericOracleSignatures diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/RoundingIntervals.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/RoundingIntervals.scala index e35a3d738b..112f7b567a 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/RoundingIntervals.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/models/RoundingIntervals.scala @@ -11,18 +11,21 @@ import org.bitcoins.core.util.NumberUtil import scala.annotation.tailrec -/** Specifies a list of intervals with corresponding rounding moduli. - * In particular, each element (outcome, roundingMod) of intervalStarts - * represents the beginning of a new interval at outcome with new modulus roundingMod. +/** Specifies a list of intervals with corresponding rounding moduli. In + * particular, each element (outcome, roundingMod) of intervalStarts represents + * the beginning of a new interval at outcome with new modulus roundingMod. * - * @see https://github.com/discreetlogcontracts/dlcspecs/blob/8ee4bbe816c9881c832b1ce320b9f14c72e3506f/NumericOutcome.md#rounding-intervals + * @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/8ee4bbe816c9881c832b1ce320b9f14c72e3506f/NumericOutcome.md#rounding-intervals */ case class RoundingIntervals(intervalStarts: Vector[IntervalStart]) { if (intervalStarts.nonEmpty) { - require(intervalStarts.init.zip(intervalStarts.tail).forall { - case (i1, i2) => i1.firstOutcome < i2.firstOutcome - }, - s"Intervals must be ascending: $intervalStarts") + require( + intervalStarts.init.zip(intervalStarts.tail).forall { case (i1, i2) => + i1.firstOutcome < i2.firstOutcome + }, + s"Intervals must be ascending: $intervalStarts" + ) } def toTLV: RoundingIntervalsV0TLV = { @@ -31,7 +34,9 @@ case class RoundingIntervals(intervalStarts: Vector[IntervalStart]) { }) } - /** Returns the rounding interval (start, end, mod) containing the given outcome */ + /** Returns the rounding interval (start, end, mod) containing the given + * outcome + */ def intervalContaining(outcome: BigDecimal): Interval = { implicit val ord: Ordering[IntervalStart] = Ordering.by[IntervalStart, (BigDecimal, Long)](i => @@ -39,8 +44,10 @@ case class RoundingIntervals(intervalStarts: Vector[IntervalStart]) { // Using Long.MaxValue guarantees that index will point to index of right endpoint of interval val index = - NumberUtil.search(intervalStarts, - IntervalStart(outcome, Long.MaxValue)) - 1 + NumberUtil.search( + intervalStarts, + IntervalStart(outcome, Long.MaxValue) + ) - 1 if (index == -1) { val firstIntervalChange = @@ -101,7 +108,8 @@ case class RoundingIntervals(intervalStarts: Vector[IntervalStart]) { thisIntervals: Vector[IntervalStart], thisCurrentMod: Long, otherIntervals: Vector[IntervalStart], - otherCurrentMod: Long): Unit = { + otherCurrentMod: Long + ): Unit = { if (thisIntervals.isEmpty) { val otherEnd = otherIntervals.map { case IntervalStart(startRange, otherMod) => @@ -120,30 +128,38 @@ case class RoundingIntervals(intervalStarts: Vector[IntervalStart]) { if (thisNextStart < otherNextStart) { addInterval(thisNextStart, Math.min(thisNextMod, otherCurrentMod)) - minMerge(thisIntervals.tail, - thisNextMod, - otherIntervals, - otherCurrentMod) + minMerge( + thisIntervals.tail, + thisNextMod, + otherIntervals, + otherCurrentMod + ) } else if (thisNextStart > otherNextStart) { addInterval(otherNextStart, Math.min(otherNextMod, thisCurrentMod)) - minMerge(thisIntervals, - thisCurrentMod, - otherIntervals.tail, - otherNextMod) + minMerge( + thisIntervals, + thisCurrentMod, + otherIntervals.tail, + otherNextMod + ) } else { addInterval(thisNextStart, Math.min(thisNextMod, otherNextMod)) - minMerge(thisIntervals.tail, - thisNextMod, - otherIntervals.tail, - otherNextMod) + minMerge( + thisIntervals.tail, + thisNextMod, + otherIntervals.tail, + otherNextMod + ) } } } - minMerge(thisIntervals = intervalStarts, - thisCurrentMod = 1L, - otherIntervals = other.intervalStarts, - otherCurrentMod = 1L) + minMerge( + thisIntervals = intervalStarts, + thisCurrentMod = 1L, + otherIntervals = other.intervalStarts, + otherCurrentMod = 1L + ) models.RoundingIntervals(builder.result()).canonicalForm() } @@ -171,9 +187,12 @@ object RoundingIntervals { case class Interval( firstOutcome: BigDecimal, nextFirstOutcome: BigDecimal, - roundingMod: Long) { - require(firstOutcome < nextFirstOutcome, - s"First outcome must come before last, $this") + roundingMod: Long + ) { + require( + firstOutcome < nextFirstOutcome, + s"First outcome must come before last, $this" + ) } def fromTLV(tlv: RoundingIntervalsV0TLV): RoundingIntervals = { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/sign/DLCTxSigner.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/sign/DLCTxSigner.scala index e3cae94937..2a524a6c7e 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/sign/DLCTxSigner.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/sign/DLCTxSigner.scala @@ -24,15 +24,15 @@ import scodec.bits.ByteVector import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success, Try} -/** Responsible for constructing all DLC signatures - * and signed transactions +/** Responsible for constructing all DLC signatures and signed transactions */ case class DLCTxSigner( builder: DLCTxBuilder, isInitiator: Boolean, fundingKey: AdaptorSign, finalAddress: BitcoinAddress, - fundingUtxos: Vector[ScriptSignatureParams[InputInfo]]) { + fundingUtxos: Vector[ScriptSignatureParams[InputInfo]] +) { private val offer = builder.offer private val accept = builder.accept @@ -57,9 +57,11 @@ case class DLCTxSigner( .sortBy(_.outPoint.bytes) .zip(offer.fundingInputs.sortBy(_.outPoint.bytes)) .map { case (utxo, fund) => - DLCFundingInput.fromInputSigningInfo(utxo, - fund.inputSerialId, - fund.sequence) + DLCFundingInput.fromInputSigningInfo( + utxo, + fund.inputSerialId, + fund.sequence + ) } .sortBy(_.inputSerialId) val sortedOfferInputs = offer.fundingInputs.sortBy(_.inputSerialId) @@ -82,9 +84,11 @@ case class DLCTxSigner( .sortBy(_.outPoint.bytes) .zip(accept.fundingInputs.sortBy(_.outPoint.bytes)) .map { case (utxo, fund) => - DLCFundingInput.fromInputSigningInfo(utxo, - fund.inputSerialId, - fund.sequence) + DLCFundingInput.fromInputSigningInfo( + utxo, + fund.inputSerialId, + fund.sequence + ) } .sortBy(_.inputSerialId) val sortedAcceptInputs = accept.fundingInputs.sortBy(_.inputSerialId) @@ -121,14 +125,18 @@ case class DLCTxSigner( DLCTxSigner.signFundingTx(builder.buildFundingTx, utxos) } - /** Constructs the signed DLC funding transaction given remote FundingSignatures */ + /** Constructs the signed DLC funding transaction given remote + * FundingSignatures + */ def completeFundingTx(remoteSigs: FundingSignatures): Try[Transaction] = { signFundingTx().flatMap { localSigs => - DLCTxSigner.completeFundingTx(localSigs, - remoteSigs, - offer.fundingInputs, - accept.fundingInputs, - builder.buildFundingTx) + DLCTxSigner.completeFundingTx( + localSigs, + remoteSigs, + offer.fundingInputs, + accept.fundingInputs, + builder.buildFundingTx + ) } } @@ -140,10 +148,12 @@ case class DLCTxSigner( case Some(info) => info case None => val signingInfo = - DLCTxSigner.buildCETSigningInfo(builder.fundOutputIndex, - builder.buildFundingTx, - builder.fundingMultiSig, - fundingKey) + DLCTxSigner.buildCETSigningInfo( + builder.fundOutputIndex, + builder.buildFundingTx, + builder.fundingMultiSig, + fundingKey + ) _cetSigningInfo = Some(signingInfo) @@ -156,31 +166,39 @@ case class DLCTxSigner( signCETs(Vector(Indexed(adaptorPoint, index))).head._2 } - /** Signs remote's Contract Execution Transaction (CET) for a given outcomes */ - def buildAndSignCETs(adaptorPoints: Vector[Indexed[ECPublicKey]]): Vector[ - (ECPublicKey, WitnessTransaction, ECAdaptorSignature)] = { + /** Signs remote's Contract Execution Transaction (CET) for a given outcomes + */ + def buildAndSignCETs( + adaptorPoints: Vector[Indexed[ECPublicKey]] + ): Vector[(ECPublicKey, WitnessTransaction, ECAdaptorSignature)] = { val outcomesAndCETs = builder.buildCETsMap(adaptorPoints) DLCTxSigner.buildAndSignCETs(outcomesAndCETs, cetSigningInfo, fundingKey) } - /** Signs remote's Contract Execution Transaction (CET) for a given outcomes */ - def signCETs(adaptorPoints: Vector[Indexed[ECPublicKey]]): Vector[ - (ECPublicKey, ECAdaptorSignature)] = { + /** Signs remote's Contract Execution Transaction (CET) for a given outcomes + */ + def signCETs( + adaptorPoints: Vector[Indexed[ECPublicKey]] + ): Vector[(ECPublicKey, ECAdaptorSignature)] = { buildAndSignCETs(adaptorPoints).map { case (outcome, _, sig) => outcome -> sig } } - /** Signs remote's Contract Execution Transaction (CET) for a given outcomes and their corresponding CETs */ - def signGivenCETs(outcomesAndCETs: Vector[AdaptorPointCETPair]): Vector[ - (ECPublicKey, ECAdaptorSignature)] = { + /** Signs remote's Contract Execution Transaction (CET) for a given outcomes + * and their corresponding CETs + */ + def signGivenCETs( + outcomesAndCETs: Vector[AdaptorPointCETPair] + ): Vector[(ECPublicKey, ECAdaptorSignature)] = { DLCTxSigner.signCETs(outcomesAndCETs, cetSigningInfo, fundingKey) } def completeCET( outcome: OracleOutcome, remoteAdaptorSig: ECAdaptorSignature, - oracleSigs: Vector[OracleSignatures]): WitnessTransaction = { + oracleSigs: Vector[OracleSignatures] + ): WitnessTransaction = { val index = builder.contractInfo.allOutcomes.indexOf(outcome) DLCTxSigner.completeCET( @@ -204,11 +222,13 @@ case class DLCTxSigner( def completeRefundTx(remoteSig: PartialSignature): WitnessTransaction = { val localSig = signRefundTx - DLCTxSigner.completeRefundTx(localSig, - remoteSig, - builder.fundingMultiSig, - builder.buildFundingTx, - builder.buildRefundTx) + DLCTxSigner.completeRefundTx( + localSig, + remoteSig, + builder.fundingMultiSig, + builder.buildFundingTx, + builder.buildRefundTx + ) } /** Creates all of this party's CETSignatures */ @@ -221,25 +241,30 @@ case class DLCTxSigner( /** Creates CET signatures async */ def createCETSigsAsync()(implicit - ec: ExecutionContext): Future[CETSignatures] = { + ec: ExecutionContext + ): Future[CETSignatures] = { val adaptorPoints = builder.contractInfo.adaptorPointsIndexed - //divide and conquer + // divide and conquer - //we want a batch size of at least 1 + // we want a batch size of at least 1 val size = - Math.max(adaptorPoints.length / Runtime.getRuntime.availableProcessors(), - 1) + Math.max( + adaptorPoints.length / Runtime.getRuntime.availableProcessors(), + 1 + ) val computeBatchFn: Vector[Indexed[ECPublicKey]] => Future[ - Vector[(ECPublicKey, ECAdaptorSignature)]] = { - adaptorPoints: Vector[Indexed[ECPublicKey]] => - FutureUtil.makeAsync(() => signCETs(adaptorPoints)) + Vector[(ECPublicKey, ECAdaptorSignature)] + ] = { adaptorPoints: Vector[Indexed[ECPublicKey]] => + FutureUtil.makeAsync(() => signCETs(adaptorPoints)) } val cetSigsF: Future[Vector[(ECPublicKey, ECAdaptorSignature)]] = { - FutureUtil.batchAndParallelExecute(elements = adaptorPoints, - f = computeBatchFn, - batchSize = size) + FutureUtil.batchAndParallelExecute( + elements = adaptorPoints, + f = computeBatchFn, + batchSize = size + ) }.map(_.flatten) for { @@ -258,20 +283,21 @@ case class DLCTxSigner( /** The equivalent of [[createCETsAndCETSigs()]] but async */ def createCETsAndCETSigsAsync()(implicit - ec: ExecutionContext): Future[(CETSignatures, Vector[WitnessTransaction])] = { + ec: ExecutionContext + ): Future[(CETSignatures, Vector[WitnessTransaction])] = { val adaptorPoints = builder.contractInfo.adaptorPointsIndexed val fn = { adaptorPoints: Vector[Indexed[ECPublicKey]] => FutureUtil.makeAsync(() => buildAndSignCETs(adaptorPoints)) } val cetsAndSigsF: Future[ - Vector[Vector[(ECPublicKey, WitnessTransaction, ECAdaptorSignature)]]] = { + Vector[Vector[(ECPublicKey, WitnessTransaction, ECAdaptorSignature)]] + ] = { FutureUtil.batchAndParallelExecute[Indexed[ECPublicKey], - Vector[( - ECPublicKey, - WitnessTransaction, - ECAdaptorSignature)]]( - elements = adaptorPoints, - f = fn) + Vector[ + (ECPublicKey, + WitnessTransaction, + ECAdaptorSignature) + ]](elements = adaptorPoints, f = fn) } for { @@ -281,9 +307,12 @@ case class DLCTxSigner( } yield (CETSignatures(msgs.zip(sigs)), cets) } - /** Creates this party's CETSignatures given the outcomes and their unsigned CETs */ + /** Creates this party's CETSignatures given the outcomes and their unsigned + * CETs + */ def createCETSigs( - outcomesAndCETs: Vector[AdaptorPointCETPair]): CETSignatures = { + outcomesAndCETs: Vector[AdaptorPointCETPair] + ): CETSignatures = { val cetSigs = signGivenCETs(outcomesAndCETs) CETSignatures(cetSigs) @@ -298,7 +327,8 @@ object DLCTxSigner { fundingKey: AdaptorSign, payoutPrivKey: AdaptorSign, network: BitcoinNetwork, - fundingUtxos: Vector[ScriptSignatureParams[InputInfo]]): DLCTxSigner = { + fundingUtxos: Vector[ScriptSignatureParams[InputInfo]] + ): DLCTxSigner = { val payoutAddr = Bech32Address(P2WPKHWitnessSPKV0(payoutPrivKey.publicKey), network) DLCTxSigner(builder, isInitiator, fundingKey, payoutAddr, fundingUtxos) @@ -308,7 +338,8 @@ object DLCTxSigner { fundOutputIndex: Int, fundingTx: Transaction, fundingMultiSig: MultiSignatureScriptPubKey, - fundingKey: Sign): ECSignatureParams[P2WSHV0InputInfo] = { + fundingKey: Sign + ): ECSignatureParams[P2WSHV0InputInfo] = { val fundingOutPoint = TransactionOutPoint(fundingTx.txId, UInt32(fundOutputIndex)) @@ -329,16 +360,20 @@ object DLCTxSigner { sigPoint: ECPublicKey, cet: WitnessTransaction, cetSigningInfo: ECSignatureParams[P2WSHV0InputInfo], - fundingKey: AdaptorSign): ECAdaptorSignature = { - signCETs(Vector(AdaptorPointCETPair(sigPoint, cet)), - cetSigningInfo, - fundingKey).head._2 + fundingKey: AdaptorSign + ): ECAdaptorSignature = { + signCETs( + Vector(AdaptorPointCETPair(sigPoint, cet)), + cetSigningInfo, + fundingKey + ).head._2 } def signCETs( outcomesAndCETs: Vector[AdaptorPointCETPair], cetSigningInfo: ECSignatureParams[P2WSHV0InputInfo], - fundingKey: AdaptorSign): Vector[(ECPublicKey, ECAdaptorSignature)] = { + fundingKey: AdaptorSign + ): Vector[(ECPublicKey, ECAdaptorSignature)] = { buildAndSignCETs(outcomesAndCETs, cetSigningInfo, fundingKey).map { case (outcome, _, sig) => outcome -> sig } @@ -347,15 +382,16 @@ object DLCTxSigner { def buildAndSignCETs( outcomesAndCETs: Vector[AdaptorPointCETPair], cetSigningInfo: ECSignatureParams[P2WSHV0InputInfo], - fundingKey: AdaptorSign): Vector[ - (ECPublicKey, WitnessTransaction, ECAdaptorSignature)] = { + fundingKey: AdaptorSign + ): Vector[(ECPublicKey, WitnessTransaction, ECAdaptorSignature)] = { outcomesAndCETs.map { case AdaptorPointCETPair(sigPoint, cet) => val hashToSign = TransactionSignatureSerializer.hashForSignature( cet, cetSigningInfo, HashType.sigHashAll, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) val adaptorSig = fundingKey.adaptorSign(sigPoint, hashToSign.bytes) (sigPoint, cet, adaptorSig) @@ -371,13 +407,16 @@ object DLCTxSigner { ucet: WitnessTransaction, remoteAdaptorSig: ECAdaptorSignature, remoteFundingPubKey: ECPublicKey, - oracleSigs: Vector[OracleSignatures]): WitnessTransaction = { + oracleSigs: Vector[OracleSignatures] + ): WitnessTransaction = { val signLowR: ByteVector => ECDigitalSignature = cetSigningInfo.signer.signLowR(_: ByteVector) - val localSig = TransactionSignatureCreator.createSig(ucet, - cetSigningInfo, - signLowR, - HashType.sigHashAll) + val localSig = TransactionSignatureCreator.createSig( + ucet, + cetSigningInfo, + signLowR, + HashType.sigHashAll + ) val oracleSigSum = OracleSignatures.computeAggregateSignature(outcome, oracleSigs) @@ -415,10 +454,12 @@ object DLCTxSigner { val signLowR: ByteVector => ECDigitalSignature = refundSigningInfo.signer.signLowR(_: ByteVector) - val sig = TransactionSignatureCreator.createSig(refundTx, - refundSigningInfo, - signLowR, - HashType.sigHashAll) + val sig = TransactionSignatureCreator.createSig( + refundTx, + refundSigningInfo, + signLowR, + HashType.sigHashAll + ) PartialSignature(fundingPubKey, sig) } @@ -429,7 +470,8 @@ object DLCTxSigner { remoteSig: PartialSignature, fundingMultiSig: MultiSignatureScriptPubKey, fundingTx: Transaction, - uRefundTx: WitnessTransaction): WitnessTransaction = { + uRefundTx: WitnessTransaction + ): WitnessTransaction = { val psbt = PSBT .fromUnsignedTx(uRefundTx) .addUTXOToInput(fundingTx, index = 0) @@ -453,37 +495,39 @@ object DLCTxSigner { ): Try[FundingSignatures] = { val sigsT = fundingUtxos .foldLeft[Try[Vector[(TransactionOutPoint, ScriptWitnessV0)]]]( - Success(Vector.empty)) { - case (sigsT, SpendingInfoWithSerialId(utxo, _)) => - sigsT.flatMap { sigs => - val sigComponent = - BitcoinSigner.sign(utxo, fundingTx, isDummySignature = false) - val witnessT = - sigComponent.transaction match { - case wtx: WitnessTransaction => - val witness = wtx.witness(sigComponent.inputIndex.toInt) - if (witness == EmptyScriptWitness) { - Failure( - new RuntimeException( - s"Funding Inputs must be SegWit: $utxo")) - } else { - Success(witness) - } - case _: NonWitnessTransaction => + Success(Vector.empty) + ) { case (sigsT, SpendingInfoWithSerialId(utxo, _)) => + sigsT.flatMap { sigs => + val sigComponent = + BitcoinSigner.sign(utxo, fundingTx, isDummySignature = false) + val witnessT = + sigComponent.transaction match { + case wtx: WitnessTransaction => + val witness = wtx.witness(sigComponent.inputIndex.toInt) + if (witness == EmptyScriptWitness) { Failure( new RuntimeException( - s"Funding Inputs must be SegWit: $utxo")) - } - - witnessT.flatMap { - case witness: ScriptWitnessV0 => - Success(sigs.:+((utxo.outPoint, witness))) - case witness: ScriptWitness => + s"Funding Inputs must be SegWit: $utxo" + ) + ) + } else { + Success(witness) + } + case _: NonWitnessTransaction => Failure( - new RuntimeException( - s"Unrecognized script witness: $witness")) + new RuntimeException(s"Funding Inputs must be SegWit: $utxo") + ) } + + witnessT.flatMap { + case witness: ScriptWitnessV0 => + Success(sigs.:+((utxo.outPoint, witness))) + case witness: ScriptWitness => + Failure( + new RuntimeException(s"Unrecognized script witness: $witness") + ) } + } } sigsT.map { sigs => @@ -503,21 +547,24 @@ object DLCTxSigner { remoteSigs: FundingSignatures, offerFundingInputs: Vector[DLCFundingInput], acceptFundingInputs: Vector[DLCFundingInput], - fundingTx: Transaction): Try[Transaction] = { + fundingTx: Transaction + ): Try[Transaction] = { val fundingInputs = (offerFundingInputs ++ acceptFundingInputs).sortBy(_.inputSerialId) val allSigs = localSigs.merge(remoteSigs) val psbt = fundingInputs.zipWithIndex.foldLeft( - PSBT.fromUnsignedTxWithP2SHScript(fundingTx)) { - case (psbt, (fundingInput, index)) => - val witness = allSigs(fundingInput.outPoint) + PSBT.fromUnsignedTxWithP2SHScript(fundingTx) + ) { case (psbt, (fundingInput, index)) => + val witness = allSigs(fundingInput.outPoint) - psbt - .addUTXOToInput(fundingInput.prevTx, index) - .addFinalizedScriptWitnessToInput(fundingInput.scriptSignature, - witness, - index) + psbt + .addUTXOToInput(fundingInput.prevTx, index) + .addFinalizedScriptWitnessToInput( + fundingInput.scriptSignature, + witness, + index + ) } val finalizedT = if (psbt.isFinalized) { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/dlc/verify/DLCSignatureVerifier.scala b/core/src/main/scala/org/bitcoins/core/protocol/dlc/verify/DLCSignatureVerifier.scala index 4ec4196da0..506aa6a5a4 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/dlc/verify/DLCSignatureVerifier.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/dlc/verify/DLCSignatureVerifier.scala @@ -28,17 +28,20 @@ case class DLCSignatureVerifier(builder: DLCTxBuilder, isInitiator: Boolean) { private def fundingTx: Transaction = builder.buildFundingTx def verifyRemoteFundingSigs(remoteSigs: FundingSignatures): Boolean = { - DLCSignatureVerifier.validateRemoteFundingSigs(fundingTx, - remoteSigs, - isInitiator, - builder.offerFundingInputs, - builder.acceptFundingInputs) + DLCSignatureVerifier.validateRemoteFundingSigs( + fundingTx, + remoteSigs, + isInitiator, + builder.offerFundingInputs, + builder.acceptFundingInputs + ) } /** Verifies remote's CET signature for a given outcome hash */ def verifyCETSig( adaptorPoint: Indexed[ECPublicKey], - sig: ECAdaptorSignature): Boolean = { + sig: ECAdaptorSignature + ): Boolean = { val remoteFundingPubKey = if (isInitiator) { builder.acceptFundingKey } else { @@ -46,21 +49,25 @@ case class DLCSignatureVerifier(builder: DLCTxBuilder, isInitiator: Boolean) { } val cet = builder.buildCET(adaptorPoint) - DLCSignatureVerifier.validateCETSignature(adaptorPoint.element, - sig, - remoteFundingPubKey, - fundingTx, - builder.fundOutputIndex, - cet) + DLCSignatureVerifier.validateCETSignature( + adaptorPoint.element, + sig, + remoteFundingPubKey, + fundingTx, + builder.fundOutputIndex, + cet + ) } - def verifyCETSigs(sigs: Vector[(Indexed[ECPublicKey], ECAdaptorSignature)])( - implicit ec: ExecutionContext): Future[Boolean] = { + def verifyCETSigs( + sigs: Vector[(Indexed[ECPublicKey], ECAdaptorSignature)] + )(implicit ec: ExecutionContext): Future[Boolean] = { val correctNumberOfSigs = sigs.size >= builder.contractInfo.allOutcomes.length val verifyFn: Vector[(Indexed[ECPublicKey], ECAdaptorSignature)] => Future[ - Boolean] = { outcomeSigs => + Boolean + ] = { outcomeSigs => FutureUtil.makeAsync { () => outcomeSigs.forall { case (outcome, sig) => verifyCETSig(outcome, sig) @@ -79,10 +86,12 @@ case class DLCSignatureVerifier(builder: DLCTxBuilder, isInitiator: Boolean) { def verifyRefundSig(sig: PartialSignature): Boolean = { val refundTx = builder.buildRefundTx - DLCSignatureVerifier.validateRefundSignature(sig, - fundingTx, - builder.fundOutputIndex, - refundTx) + DLCSignatureVerifier.validateRefundSignature( + sig, + fundingTx, + builder.fundOutputIndex, + refundTx + ) } } @@ -100,15 +109,18 @@ object DLCSignatureVerifier { transaction = cet, inputIndex = UInt32.zero, output = fundingTx.outputs(fundOutputIndex), - flags = Policy.standardFlags) + flags = Policy.standardFlags + ) val hashType = HashType( - ByteVector(0.toByte, 0.toByte, 0.toByte, HashType.sigHashAll.byte)) + ByteVector(0.toByte, 0.toByte, 0.toByte, HashType.sigHashAll.byte) + ) val hash = TransactionSignatureSerializer.hashForSignature( txSigComponent = sigComponent, hashType = hashType, - taprootOptions = TaprootSerializationOptions.empty) + taprootOptions = TaprootSerializationOptions.empty + ) remoteFundingPubKey.adaptorVerify(hash.bytes, adaptorPoint, sig) } @@ -123,7 +135,8 @@ object DLCSignatureVerifier { transaction = refundTx, inputIndex = UInt32.zero, output = fundingTx.outputs(fundOutputIndex), - flags = Policy.standardFlags) + flags = Policy.standardFlags + ) TransactionSignatureChecker .checkSignature( @@ -142,7 +155,8 @@ object DLCSignatureVerifier { fundingSigs: FundingSignatures, localIsInitiator: Boolean, offerFundingInputs: Vector[DLCFundingInput], - acceptFundingInputs: Vector[DLCFundingInput]): Boolean = { + acceptFundingInputs: Vector[DLCFundingInput] + ): Boolean = { val fundingInputs = offerFundingInputs ++ acceptFundingInputs val serialIdMap = @@ -175,14 +189,17 @@ object DLCSignatureVerifier { case Some(input) => input case None => throw new RuntimeException( - s"Could not find fundingInput for outpoint $outPoint") + s"Could not find fundingInput for outpoint $outPoint" + ) } psbt .addUTXOToInput(fundingInput.prevTx, idx) - .addFinalizedScriptWitnessToInput(fundingInput.scriptSignature, - witness, - idx) + .addFinalizedScriptWitnessToInput( + fundingInput.scriptSignature, + witness, + idx + ) .finalizeInput(idx) }.flatten match { case Success(finalized) => diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnHumanReadablePart.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnHumanReadablePart.scala index a16bde3dfe..d3b57ec5cb 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnHumanReadablePart.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnHumanReadablePart.scala @@ -11,8 +11,10 @@ import scala.util.matching.Regex import scala.util.{Failure, Success, Try} sealed abstract class LnHumanReadablePart extends Bech32HumanReadablePart { - require(amount.isEmpty || amount.get.toBigInt > 0, - s"Invoice amount must be greater then 0, got $amount") + require( + amount.isEmpty || amount.get.toBigInt > 0, + s"Invoice amount must be greater then 0, got $amount" + ) def network: LnParams @@ -57,7 +59,9 @@ object LnHumanReadablePart extends StringFactory[LnHumanReadablePart] { def network: LnParams = LnBitcoinRegTest } - /** Tries to construct a LN HRP with optional amount specified from the given string */ + /** Tries to construct a LN HRP with optional amount specified from the given + * string + */ def apply(bech32: String): Try[LnHumanReadablePart] = fromStringT(bech32) def apply(network: NetworkParameters): LnHumanReadablePart = { @@ -67,7 +71,8 @@ object LnHumanReadablePart extends StringFactory[LnHumanReadablePart] { def apply( network: NetworkParameters, - amount: LnCurrencyUnit): LnHumanReadablePart = { + amount: LnCurrencyUnit + ): LnHumanReadablePart = { val lnNetwork = LnParams.fromNetworkParameters(network) LnHumanReadablePart(lnNetwork, Some(amount)) } @@ -76,25 +81,33 @@ object LnHumanReadablePart extends StringFactory[LnHumanReadablePart] { fromLnParams(network) } - /** Will return a [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] - * without a [[org.bitcoins.core.protocol.ln.currency.LnCurrencyUnit LnCurrencyUnit]] encoded in the invoice + /** Will return a + * [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] + * without a + * [[org.bitcoins.core.protocol.ln.currency.LnCurrencyUnit LnCurrencyUnit]] + * encoded in the invoice */ def fromLnParams(network: LnParams): LnHumanReadablePart = { LnHumanReadablePart(network, None) } - /** Will return a [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] - * with the provide [[org.bitcoins.core.protocol.ln.currency.LnCurrencyUnit LnCurrencyUnit]] encoded in the invoice + /** Will return a + * [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] + * with the provide + * [[org.bitcoins.core.protocol.ln.currency.LnCurrencyUnit LnCurrencyUnit]] + * encoded in the invoice */ def apply( network: LnParams, - amount: Option[LnCurrencyUnit]): LnHumanReadablePart = { + amount: Option[LnCurrencyUnit] + ): LnHumanReadablePart = { fromParamsAmount(network, amount) } def fromParamsAmount( network: LnParams, - amount: Option[LnCurrencyUnit]): LnHumanReadablePart = { + amount: Option[LnCurrencyUnit] + ): LnHumanReadablePart = { network match { case LnParams.LnBitcoinMainNet => lnbc(amount) case LnParams.LnBitcoinTestNet => lntb(amount) @@ -103,14 +116,14 @@ object LnHumanReadablePart extends StringFactory[LnHumanReadablePart] { } } - /** First two chars MUST be 'ln' - * Next chars must be the BIP173 currency prefixes. For more information, see + /** First two chars MUST be 'ln' Next chars must be the BIP173 currency + * prefixes. For more information, see * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#human-readable-part BOLT11]] * and * [[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#Specification BIP173]] */ override def fromStringT(bech32: String): Try[LnHumanReadablePart] = { - //Select all of the letters, until we hit a number, as the network + // Select all of the letters, until we hit a number, as the network val networkPattern: Regex = "^[a-z]*".r val networkStringOpt = networkPattern.findFirstIn(bech32) val lnParamsOpt = networkStringOpt.flatMap(LnParams.fromPrefixString) @@ -118,7 +131,9 @@ object LnHumanReadablePart extends StringFactory[LnHumanReadablePart] { if (lnParamsOpt.isEmpty) { Failure( new IllegalArgumentException( - s"Could not parse a valid network prefix, got $bech32")) + s"Could not parse a valid network prefix, got $bech32" + ) + ) } else { val lnParams = lnParamsOpt.get @@ -126,12 +141,14 @@ object LnHumanReadablePart extends StringFactory[LnHumanReadablePart] { val amountString = bech32.slice(prefixSize, bech32.length) val amount = LnCurrencyUnits.fromEncodedString(amountString).toOption - //If we are able to parse something as an amount, but are unable to convert it to a LnCurrencyUnit, we should fail. + // If we are able to parse something as an amount, but are unable to convert it to a LnCurrencyUnit, we should fail. if (amount.isEmpty && !amountString.isEmpty) { Failure( new IllegalArgumentException( s"Parsed an amount, " + - s"but could not convert to a valid currency, got: $amountString")) + s"but could not convert to a valid currency, got: $amountString" + ) + ) } else { Success(LnHumanReadablePart(lnParams, amount)) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnInvoice.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnInvoice.scala index c36e7703af..7538e2ca60 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnInvoice.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnInvoice.scala @@ -17,12 +17,15 @@ import scala.util.{Failure, Success, Try} sealed abstract class LnInvoice { - require(timestamp < LnInvoice.MAX_TIMESTAMP_U64, - s"timestamp ${timestamp.toBigInt} < ${LnInvoice.MAX_TIMESTAMP}") + require( + timestamp < LnInvoice.MAX_TIMESTAMP_U64, + s"timestamp ${timestamp.toBigInt} < ${LnInvoice.MAX_TIMESTAMP}" + ) require( isValidSignature, - s"Did not receive a valid digital signature for the invoice $toString") + s"Did not receive a valid digital signature for the invoice $toString" + ) def hrp: LnHumanReadablePart @@ -46,10 +49,11 @@ sealed abstract class LnInvoice { amount.map(_.toPicoBitcoins) } - /** The [[org.bitcoins.core.protocol.ln.node.NodeId NodeId]] that we are paying this invoice too - * We can either recover this with public key recovery from - * the [[org.bitcoins.core.protocol.ln.LnInvoiceSignature LnInvoiceSignature]] or if - * [[org.bitcoins.core.protocol.ln.LnTag.NodeIdTag LnTag.NodeIdTag]] is + /** The [[org.bitcoins.core.protocol.ln.node.NodeId NodeId]] that we are + * paying this invoice too We can either recover this with public key + * recovery from the + * [[org.bitcoins.core.protocol.ln.LnInvoiceSignature LnInvoiceSignature]] or + * if [[org.bitcoins.core.protocol.ln.LnTag.NodeIdTag LnTag.NodeIdTag]] is * defined we MUST use that NodeId, as per * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#requirements-3 BOLT11]] */ @@ -81,8 +85,9 @@ sealed abstract class LnInvoice { sig } - /** The hash that is signed by the [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]] corresponding - * to the `nodeId` + /** The hash that is signed by the + * [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]] corresponding to the + * `nodeId` */ private def sigHash: Sha256Digest = { val hash = CryptoUtil.sha256(signatureData) @@ -118,8 +123,8 @@ object LnInvoice extends StringFactory[LnInvoice] { hrp: LnHumanReadablePart, timestamp: UInt64, lnTags: LnTaggedFields, - signature: LnInvoiceSignature) - extends LnInvoice + signature: LnInvoiceSignature + ) extends LnInvoice val MAX_TIMESTAMP: BigInt = NumberUtil.pow2(35) @@ -135,7 +140,8 @@ object LnInvoice extends StringFactory[LnInvoice] { def createChecksum( hrp: LnHumanReadablePart, - data: Vector[UInt5]): Vector[UInt5] = { + data: Vector[UInt5] + ): Vector[UInt5] = { val hrpBytes = hrpExpand(hrp) val u5s = Bech32.createChecksum(hrpBytes ++ data, Bech32Encoding.Bech32) u5s @@ -149,21 +155,22 @@ object LnInvoice extends StringFactory[LnInvoice] { def apply(hrp: LnHumanReadablePart, data: Vector[UInt5]): LnInvoice = { - //https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#data-part + // https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#data-part val TIMESTAMP_LEN = 7 val SIGNATURE_LEN = 104 val MIN_LENGTH = TIMESTAMP_LEN + SIGNATURE_LEN if (data.length < MIN_LENGTH) { throw new IllegalArgumentException( - s"Cannot create invoice with data length less then $MIN_LENGTH, got ${data.length}") + s"Cannot create invoice with data length less then $MIN_LENGTH, got ${data.length}" + ) } else { - //first 35 bits is time stamp + // first 35 bits is time stamp val timestampU5s = data.take(TIMESTAMP_LEN) val timestamp = decodeTimestamp(timestampU5s) - //last bits should be a 520 bit signature - //should be 104 5 bit increments (104 * 5 = 520) + // last bits should be a 520 bit signature + // should be 104 5 bit increments (104 * 5 = 520) val signatureU5s = data.takeRight(SIGNATURE_LEN) val signature = LnInvoiceSignature.fromU5s(signatureU5s) @@ -171,10 +178,12 @@ object LnInvoice extends StringFactory[LnInvoice] { val taggedFields = LnTaggedFields.fromUInt5s(tags) - LnInvoice(hrp = hrp, - timestamp = timestamp, - lnTags = taggedFields, - signature = signature) + LnInvoice( + hrp = hrp, + timestamp = timestamp, + lnTags = taggedFields, + signature = signature + ) } } @@ -187,7 +196,8 @@ object LnInvoice extends StringFactory[LnInvoice] { } if (sepIndexes.isEmpty) { throw new IllegalArgumentException( - "LnInvoice did not have the correct separator") + "LnInvoice did not have the correct separator" + ) } else { val (_, sepIndex) = sepIndexes.last @@ -228,30 +238,37 @@ object LnInvoice extends StringFactory[LnInvoice] { hrp: LnHumanReadablePart, timestamp: UInt64, lnTags: LnTaggedFields, - signature: LnInvoiceSignature): LnInvoice = { - LnInvoiceImpl(hrp = hrp, - timestamp = timestamp, - lnTags = lnTags, - signature = signature) + signature: LnInvoiceSignature + ): LnInvoice = { + LnInvoiceImpl( + hrp = hrp, + timestamp = timestamp, + lnTags = lnTags, + signature = signature + ) } def apply( hrp: LnHumanReadablePart, timestamp: UInt64, lnTags: LnTaggedFields, - privateKey: ECPrivateKey): LnInvoice = { + privateKey: ECPrivateKey + ): LnInvoice = { val signature = buildLnInvoiceSignature(hrp, timestamp, lnTags, privateKey) - LnInvoiceImpl(hrp = hrp, - timestamp = timestamp, - lnTags = lnTags, - signature = signature) + LnInvoiceImpl( + hrp = hrp, + timestamp = timestamp, + lnTags = lnTags, + signature = signature + ) } def buildSignatureData( hrp: LnHumanReadablePart, timestamp: UInt64, - lnTags: LnTaggedFields): ByteVector = { + lnTags: LnTaggedFields + ): ByteVector = { val tsu5 = uInt64ToBase32(timestamp) val payloadU5 = tsu5 ++ lnTags.data val payloadU8 = Bech32.from5bitTo8bit(payloadU5, pad = true) @@ -262,7 +279,8 @@ object LnInvoice extends StringFactory[LnInvoice] { def buildSigHashData( hrp: LnHumanReadablePart, timestamp: UInt64, - lnTags: LnTaggedFields): Sha256Digest = { + lnTags: LnTaggedFields + ): Sha256Digest = { val sigdata = buildSignatureData(hrp, timestamp, lnTags) CryptoUtil.sha256(sigdata) } @@ -271,7 +289,8 @@ object LnInvoice extends StringFactory[LnInvoice] { hrp: LnHumanReadablePart, timestamp: UInt64, lnTags: LnTaggedFields, - privateKey: ECPrivateKey): LnInvoiceSignature = { + privateKey: ECPrivateKey + ): LnInvoiceSignature = { val sigHash = buildSigHashData(hrp, timestamp, lnTags) val sig = privateKey.sign(sigHash) @@ -281,49 +300,66 @@ object LnInvoice extends StringFactory[LnInvoice] { LnInvoiceSignature(recoverId = recoveryId, signature = sig) } - /** The easiest way to create a [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] - * is by just passing the given pareameters and - * and then build will create a [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] - * with a valid [[org.bitcoins.core.protocol.ln.LnInvoiceSignature LnInvoiceSignature]] - * @param hrp the [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] - * @param timestamp the timestamp on the invoice - * @param lnTags the various tags in the invoice - * @param privateKey - the key used to sign the invoice + /** The easiest way to create a + * [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] is by just passing + * the given pareameters and and then build will create a + * [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] with a valid + * [[org.bitcoins.core.protocol.ln.LnInvoiceSignature LnInvoiceSignature]] + * @param hrp + * the + * [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] + * @param timestamp + * the timestamp on the invoice + * @param lnTags + * the various tags in the invoice + * @param privateKey + * \- the key used to sign the invoice */ def build( hrp: LnHumanReadablePart, timestamp: UInt64, lnTags: LnTaggedFields, - privateKey: ECPrivateKey): LnInvoice = { + privateKey: ECPrivateKey + ): LnInvoice = { val lnInvoiceSignature = buildLnInvoiceSignature(hrp, timestamp, lnTags, privateKey) - LnInvoice(hrp = hrp, - timestamp = timestamp, - lnTags = lnTags, - signature = lnInvoiceSignature) + LnInvoice( + hrp = hrp, + timestamp = timestamp, + lnTags = lnTags, + signature = lnInvoiceSignature + ) } - /** The easiest way to create a [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] - * is by just passing the given parameters and - * and then build will create a [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] - * with a valid [[org.bitcoins.core.protocol.ln.LnInvoiceSignature LnInvoiceSignature]] - * @param hrp the [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] - * @param lnTags the various tags in the invoice - * @param privateKey - the key used to sign the invoice + /** The easiest way to create a + * [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] is by just passing + * the given parameters and and then build will create a + * [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] with a valid + * [[org.bitcoins.core.protocol.ln.LnInvoiceSignature LnInvoiceSignature]] + * @param hrp + * the + * [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] + * @param lnTags + * the various tags in the invoice + * @param privateKey + * \- the key used to sign the invoice */ def build( hrp: LnHumanReadablePart, lnTags: LnTaggedFields, - privateKey: ECPrivateKey): LnInvoice = { + privateKey: ECPrivateKey + ): LnInvoice = { val timestamp = UInt64(System.currentTimeMillis() / 1000L) val lnInvoiceSignature = buildLnInvoiceSignature(hrp, timestamp, lnTags, privateKey) - LnInvoice(hrp = hrp, - timestamp = timestamp, - lnTags = lnTags, - signature = lnInvoiceSignature) + LnInvoice( + hrp = hrp, + timestamp = timestamp, + lnTags = lnTags, + signature = lnInvoiceSignature + ) } private def uInt64ToBase32(input: UInt64): Vector[UInt5] = { @@ -337,20 +373,26 @@ object LnInvoice extends StringFactory[LnInvoice] { numNoPadding.toVector } - /** Checks the checksum on a [[org.bitcoins.core.protocol.Bech32Address Bech32Address]] - * and if it is valid, strips the checksum from @d and returns strictly - * the payload - * @param h - the [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] of the invoice - * @param d - the payload WITH the checksum included + /** Checks the checksum on a + * [[org.bitcoins.core.protocol.Bech32Address Bech32Address]] and if it is + * valid, strips the checksum from @d and returns strictly the payload + * @param h + * \- the + * [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] + * of the invoice + * @param d + * \- the payload WITH the checksum included */ private def stripChecksumIfValid( h: LnHumanReadablePart, - d: Vector[UInt5]): Try[Vector[UInt5]] = { + d: Vector[UInt5] + ): Try[Vector[UInt5]] = { if (verifyChecksum(h, d)) { if (d.size < 6) Success(Vector.empty) else Success(d.take(d.size - 6)) } else Failure( - new IllegalArgumentException("Checksum was invalid on the LnInvoice")) + new IllegalArgumentException("Checksum was invalid on the LnInvoice") + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnInvoiceSignature.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnInvoiceSignature.scala index 71aead6a00..244daa6caa 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnInvoiceSignature.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnInvoiceSignature.scala @@ -7,18 +7,21 @@ import org.bitcoins.core.util.Bech32 import org.bitcoins.crypto.{ECDigitalSignature, Factory, NetworkElement} import scodec.bits.ByteVector -/** 520 bit digital signature that signs the [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]]; - * See +/** 520 bit digital signature that signs the + * [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]]; See * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#data-part BOLT11]] * for more info. */ sealed abstract class LnInvoiceSignature extends NetworkElement { - require(recoverId.toInt >= 0 && recoverId.toInt <= 3, - s"signature recovery byte must be 0,1,2,3, got ${recoverId.toInt}") + require( + recoverId.toInt >= 0 && recoverId.toInt <= 3, + s"signature recovery byte must be 0,1,2,3, got ${recoverId.toInt}" + ) require( bytes.length == 65, - s"LnInvoiceSignatures MUST be 65 bytes in length, got ${bytes.length}") + s"LnInvoiceSignatures MUST be 65 bytes in length, got ${bytes.length}" + ) def signature: ECDigitalSignature def recoverId: UInt8 @@ -37,12 +40,13 @@ object LnInvoiceSignature extends Factory[LnInvoiceSignature] { private case class LnInvoiceSignatureImpl( recoverId: UInt8, - signature: ECDigitalSignature) - extends LnInvoiceSignature + signature: ECDigitalSignature + ) extends LnInvoiceSignature def apply( recoverId: UInt8, - signature: ECDigitalSignature): LnInvoiceSignature = { + signature: ECDigitalSignature + ): LnInvoiceSignature = { LnInvoiceSignatureImpl(recoverId, signature) } @@ -58,7 +62,8 @@ object LnInvoiceSignature extends Factory[LnInvoiceSignature] { def fromRS( r: BigInteger, s: BigInteger, - recovId: UInt8): LnInvoiceSignature = { + recovId: UInt8 + ): LnInvoiceSignature = { val sig = ECDigitalSignature.fromRS(r, s) LnInvoiceSignature(recovId, sig) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnParams.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnParams.scala index e2769c22e4..abde947142 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnParams.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnParams.scala @@ -70,10 +70,12 @@ object LnParams { } val allNetworks: Vector[LnParams] = - Vector(LnBitcoinMainNet, - LnBitcoinTestNet, - LnBitcoinSigNet, - LnBitcoinRegTest) + Vector( + LnBitcoinMainNet, + LnBitcoinTestNet, + LnBitcoinSigNet, + LnBitcoinRegTest + ) private val prefixes: Map[String, LnParams] = { val vec: Vector[(String, LnParams)] = { @@ -85,7 +87,8 @@ object LnParams { } /** Returns a [[org.bitcoins.core.protocol.ln.LnParams LnParams]] whose - * network prefix matches the given string. See [[https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#human-readable-part BOLT11 ]] + * network prefix matches the given string. See + * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#human-readable-part BOLT11]] * for more details on prefixes. */ def fromPrefixString(str: String): Option[LnParams] = { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnPolicy.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnPolicy.scala index c9bca3bda4..f469bd8689 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnPolicy.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnPolicy.scala @@ -5,10 +5,11 @@ import org.bitcoins.core.protocol.ln.currency.{LnMultiplier, MilliSatoshis} sealed abstract class LnPolicy { - /** The "amount_msat" field has been artificially limited to a UInt32. This means that the current maximum transaction that can be completed - * over the lightning network is 4294967295 MilliSatoshi. - * This is a self imposed limit, and is subject to change. - * Please see [[https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#adding-an-htlc-update_add_htlc BOLT2]] + /** The "amount_msat" field has been artificially limited to a UInt32. This + * means that the current maximum transaction that can be completed over the + * lightning network is 4294967295 MilliSatoshi. This is a self imposed + * limit, and is subject to change. Please see + * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#adding-an-htlc-update_add_htlc BOLT2]] * for more info. */ val maxAmountMSat: MilliSatoshis = MilliSatoshis(4294967295L) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTagPrefix.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTagPrefix.scala index eea95e9bc7..20585fb0f7 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTagPrefix.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTagPrefix.scala @@ -10,8 +10,9 @@ sealed abstract class LnTagPrefix { override def toString: String = value.toString } -/** This defines the necessary Lightning Network Tag Prefix's, as specified in BOLT-11 - * Please see: https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#tagged-fields +/** This defines the necessary Lightning Network Tag Prefix's, as specified in + * BOLT-11 Please see: + * https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#tagged-fields */ object LnTagPrefix extends StringFactory[LnTagPrefix] { @@ -59,16 +60,18 @@ object LnTagPrefix extends StringFactory[LnTagPrefix] { } private lazy val allKnown: Map[Char, LnTagPrefix] = - List(PaymentHash, - Description, - NodeId, - DescriptionHash, - ExpiryTime, - CltvExpiry, - FallbackAddress, - RoutingInfo, - Features, - Secret) + List( + PaymentHash, + Description, + NodeId, + DescriptionHash, + ExpiryTime, + CltvExpiry, + FallbackAddress, + RoutingInfo, + Features, + Secret + ) .map(prefix => prefix.value -> prefix) .toMap diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTaggedFields.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTaggedFields.scala index 340f944041..2a00154ca3 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTaggedFields.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTaggedFields.scala @@ -10,7 +10,8 @@ import scala.annotation.tailrec import scala.collection.mutable import scala.reflect.ClassTag -/** An aggregation of all the individual tagged fields in a [[org.bitcoins.core.protocol.ln.LnInvoice]] +/** An aggregation of all the individual tagged fields in a + * [[org.bitcoins.core.protocol.ln.LnInvoice]] */ sealed abstract class LnTaggedFields extends SeqWrapper[LnTag] @@ -22,8 +23,10 @@ sealed abstract class LnTaggedFields descriptionHash.nonEmpty, "You must supply either a description hash, or a literal description that is 640 characters or less to create an invoice." ) - require(!(description.nonEmpty && descriptionHash.nonEmpty), - "Cannot have both description and description hash") + require( + !(description.nonEmpty && descriptionHash.nonEmpty), + "Cannot have both description and description hash" + ) def tags: Vector[LnTag] @@ -96,11 +99,11 @@ object LnTaggedFields { cltvExpiry: Option[LnTag.MinFinalCltvExpiry] = None, fallbackAddress: Option[LnTag.FallbackAddressTag] = None, routingInfo: Option[LnTag.RoutingInfo] = None, - features: Option[LnTag.FeaturesTag] = None): LnTaggedFields = { + features: Option[LnTag.FeaturesTag] = None + ): LnTaggedFields = { - val (description, descriptionHash): ( - Option[LnTag.DescriptionTag], - Option[LnTag.DescriptionHashTag]) = { + val (description, descriptionHash) + : (Option[LnTag.DescriptionTag], Option[LnTag.DescriptionHashTag]) = { descriptionOrHash match { case Left(description) => @@ -110,26 +113,30 @@ object LnTaggedFields { } } - val tags = Vector(Some(paymentHash), - description, - nodeId, - descriptionHash, - expiryTime, - cltvExpiry, - fallbackAddress, - routingInfo, - features, - secret).flatten + val tags = Vector( + Some(paymentHash), + description, + nodeId, + descriptionHash, + expiryTime, + cltvExpiry, + fallbackAddress, + routingInfo, + features, + secret + ).flatten InvoiceTagImpl(tags) } def apply(tags: Vector[LnTag]): LnTaggedFields = InvoiceTagImpl(tags) - /** This is intended to parse all of the [[org.bitcoins.core.protocol.ln.LnTaggedFields LnTaggedFields]] - * from the tagged part of the ln invoice. This should only be called - * if other information has already been remove from the invoice - * like the [[LnHumanReadablePart]] - * @param u5s payload of the tagged fields in the invoice + /** This is intended to parse all of the + * [[org.bitcoins.core.protocol.ln.LnTaggedFields LnTaggedFields]] from the + * tagged part of the ln invoice. This should only be called if other + * information has already been remove from the invoice like the + * [[LnHumanReadablePart]] + * @param u5s + * payload of the tagged fields in the invoice * @return */ def fromUInt5s(u5s: Vector[UInt5]): LnTaggedFields = { @@ -140,14 +147,15 @@ object LnTaggedFields { val prefix = LnTagPrefix .fromUInt5(h) .getOrElse( - throw new RuntimeException("Unknown LN invoice tag prefix")) + throw new RuntimeException("Unknown LN invoice tag prefix") + ) - //next two 5 bit increments are data_length + // next two 5 bit increments are data_length val dataLengthU5s = List(h1, h2) val dataLength = LnUtil.decodeDataLength(dataLengthU5s) - //t is the actual possible payload + // t is the actual possible payload val payload: Vector[UInt5] = t.take(dataLength.toInt) val tag = LnTag.fromLnTagPrefix(prefix, payload) @@ -157,7 +165,8 @@ object LnTaggedFields { loop(newRemaining, fields :+ tag) case _ +: _ | _ +: _ +: _ => throw new IllegalArgumentException( - "Failed to parse LnTaggedFields, needs 15bits of meta data to be able to parse") + "Failed to parse LnTaggedFields, needs 15bits of meta data to be able to parse" + ) case _: Vector[_] => fields } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTags.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTags.scala index 6a950e24f7..6f3635e145 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTags.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/LnTags.scala @@ -52,8 +52,8 @@ sealed trait LnTag { } } -/** All of the different invoice tags that are currently defined - * Refer to BOLT11 for a full list +/** All of the different invoice tags that are currently defined Refer to BOLT11 + * for a full list * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#tagged-fields]] */ object LnTag { @@ -87,7 +87,8 @@ object LnTag { P2WPKHWitnessSPKV0.fromHash(hash) case _: Long => throw new IllegalArgumentException( - s"Can only create witness spk out of a 32 byte or 20 byte hash, got ${bytes.length}") + s"Can only create witness spk out of a 32 byte or 20 byte hash, got ${bytes.length}" + ) } Bech32Address(witSPK, np) } @@ -95,7 +96,8 @@ object LnTag { def fromU8( version: UInt8, bytes: ByteVector, - np: NetworkParameters): FallbackAddressTag = { + np: NetworkParameters + ): FallbackAddressTag = { val address: Address = version match { case P2PKH.u8 => val hash = Sha256Hash160Digest(bytes) @@ -108,13 +110,15 @@ object LnTag { WitnessVersion(uint8.toInt) match { case Some(witV) => val asm = witV.version +: BitcoinScriptUtil.calculatePushOp( - bytes) :+ ScriptConstant(bytes) + bytes + ) :+ ScriptConstant(bytes) val scriptPubKey = WitnessScriptPubKey(asm.toVector) Bech32mAddress(scriptPubKey, np) case None => throw new IllegalArgumentException( - s"Illegal version to create a fallback address from, got $version") + s"Illegal version to create a fallback address from, got $version" + ) } } LnTag.FallbackAddressTag(address) @@ -190,9 +194,9 @@ object LnTag { } } - /** `min_final_ctlv_expiry` is the minimum difference between - * HTLC CLTV timeout and the current block height, for the - * terminal case (C). This is denominated in blocks. + /** `min_final_ctlv_expiry` is the minimum difference between HTLC CLTV + * timeout and the current block height, for the terminal case (C). This is + * denominated in blocks. * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#cltv_expiry_delta-selection]] */ case class MinFinalCltvExpiry(u32: UInt32) extends LnTag { @@ -255,7 +259,8 @@ object LnTag { @tailrec def loop( remaining: ByteVector, - accum: Vector[LnRoute]): Vector[LnRoute] = { + accum: Vector[LnRoute] + ): Vector[LnRoute] = { if (remaining.isEmpty) { accum } else { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/PaymentSecret.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/PaymentSecret.scala index 5e30200905..3e7cdbf55d 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/PaymentSecret.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/PaymentSecret.scala @@ -4,8 +4,10 @@ import org.bitcoins.crypto._ import scodec.bits.ByteVector final case class PaymentSecret(bytes: ByteVector) extends NetworkElement { - require(bytes.size == 32, - s"Payment secret must be 32 bytes in size, got: " + bytes.length) + require( + bytes.size == 32, + s"Payment secret must be 32 bytes in size, got: " + bytes.length + ) lazy val hash: Sha256Digest = CryptoUtil.sha256(bytes) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ChannelId.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ChannelId.scala index f2929c52d4..9db9e0f19d 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ChannelId.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ChannelId.scala @@ -3,34 +3,39 @@ package org.bitcoins.core.protocol.ln.channel import org.bitcoins.crypto.{Factory, NetworkElement} import scodec.bits.ByteVector -/** There are two types of ChannelIds in the lightning protocol - * There is a 'temporary' channel id used for the hand shake when initially establishing - * a channel and then a FundedChannelId indicating a channel that has a validly signed tx - * For more information on the distinction between these two types please read - * about +/** There are two types of ChannelIds in the lightning protocol There is a + * 'temporary' channel id used for the hand shake when initially establishing a + * channel and then a FundedChannelId indicating a channel that has a validly + * signed tx For more information on the distinction between these two types + * please read about * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#channel-establishment establishing a channel]] */ sealed abstract class ChannelId extends NetworkElement -/** Represents the the temporary channelId created in the - * `open_channel` msg of the +/** Represents the the temporary channelId created in the `open_channel` msg of + * the * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#the-open_channel-message LN p2p protocol]] */ case class TempChannelId(bytes: ByteVector) extends ChannelId { - require(bytes.length == 32, - s"ChannelId must be 32 bytes in size, got ${bytes.length}") + require( + bytes.length == 32, + s"ChannelId must be 32 bytes in size, got ${bytes.length}" + ) } -/** Represents the stable ChannelId that represents a channel that has been signed by both parties - * This is created in the `funding_signed` msg on the +/** Represents the stable ChannelId that represents a channel that has been + * signed by both parties This is created in the `funding_signed` msg on the * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#the-funding_signed-message LN p2p protocol]]. * - * This channelId is derived It's derived from the funding transaction by combining the `funding_txid` and - * the `funding_output_index` using big-endian exclusive-OR (i.e. `funding_output_index` alters the last 2 bytes). + * This channelId is derived It's derived from the funding transaction by + * combining the `funding_txid` and the `funding_output_index` using big-endian + * exclusive-OR (i.e. `funding_output_index` alters the last 2 bytes). */ case class FundedChannelId(bytes: ByteVector) extends ChannelId { - require(bytes.length == 32, - s"ChannelId must be 32 bytes in size, got ${bytes.length}") + require( + bytes.length == 32, + s"ChannelId must be 32 bytes in size, got ${bytes.length}" + ) } object FundedChannelId extends Factory[FundedChannelId] { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ChannelState.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ChannelState.scala index 2a2bf96434..fc8db3e45f 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ChannelState.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ChannelState.scala @@ -2,7 +2,8 @@ package org.bitcoins.core.protocol.ln.channel import org.bitcoins.crypto.StringFactory -/** Copied from [[https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala Eclair]] +/** Copied from + * [[https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelTypes.scala Eclair]] */ sealed trait ChannelState diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ShortChannelId.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ShortChannelId.scala index a817f4ee5e..8fa24c1d65 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ShortChannelId.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/channel/ShortChannelId.scala @@ -19,8 +19,10 @@ case class ShortChannelId(u64: UInt64) extends NetworkElement { */ override def toString: String = toHumanReadableString - /** Converts the short channel id into the human readable form defined in BOLT. - * @see [[https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md BOLT7]] + /** Converts the short channel id into the human readable form defined in + * BOLT. + * @see + * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md BOLT7]] * * Output example: * {{{ @@ -54,18 +56,26 @@ object ShortChannelId extends Factory[ShortChannelId] { def apply( blockHeight: BigInt, txIndex: Int, - outputIndex: Int): ShortChannelId = { - require(blockHeight >= 0 && blockHeight <= 0xffffff, - s"ShortChannelId: invalid block height $blockHeight") + outputIndex: Int + ): ShortChannelId = { + require( + blockHeight >= 0 && blockHeight <= 0xffffff, + s"ShortChannelId: invalid block height $blockHeight" + ) - require(txIndex >= 0 && txIndex <= 0xffffff, - s"ShortChannelId:invalid tx index $txIndex") + require( + txIndex >= 0 && txIndex <= 0xffffff, + s"ShortChannelId:invalid tx index $txIndex" + ) - require(outputIndex >= 0 && outputIndex <= 0xffff, - s"ShortChannelId: invalid output index $outputIndex") + require( + outputIndex >= 0 && outputIndex <= 0xffff, + s"ShortChannelId: invalid output index $outputIndex" + ) val u64 = UInt64( - ((blockHeight & 0xffffffL) << 40) | ((txIndex & 0xffffffL) << 16) | (outputIndex & 0xffffL)) + ((blockHeight & 0xffffffL) << 40) | ((txIndex & 0xffffffL) << 16) | (outputIndex & 0xffffL) + ) ShortChannelId(u64) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnit.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnit.scala index d783578043..9b6c83a2cc 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnit.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnCurrencyUnit.scala @@ -25,12 +25,12 @@ sealed abstract class LnCurrencyUnit toPicoBitcoinValue == ln.toPicoBitcoinValue override def equals(obj: Any): Boolean = { - //needed for cases like - //1BTC == 100,000,000 satoshis should be true - //weirdly enough, this worked in scala version < 2.13.4 - //but seems to be broken in 2.13.4 :/ - //try removing this and running code, you should see - //failures in the 'lnurl' module + // needed for cases like + // 1BTC == 100,000,000 satoshis should be true + // weirdly enough, this worked in scala version < 2.13.4 + // but seems to be broken in 2.13.4 :/ + // try removing this and running code, you should see + // failures in the 'lnurl' module obj match { case ln: LnCurrencyUnit => toPicoBitcoinValue == ln.toPicoBitcoinValue case ms: MilliSatoshis => toMSat == ms @@ -95,10 +95,9 @@ sealed abstract class LnCurrencyUnit def toMSat: MilliSatoshis = MilliSatoshis.fromPico(toPicoBitcoins) - /** This returns the string encoding defined in BOLT11 - * For instance, 100 - * [[org.bitcoins.core.protocol.ln.currency.PicoBitcoins PicoBitcoins]] - * would appear as "100p" + /** This returns the string encoding defined in BOLT11 For instance, 100 + * [[org.bitcoins.core.protocol.ln.currency.PicoBitcoins PicoBitcoins]] would + * appear as "100p" */ def toEncodedString: String = { toBigInt.toString + character.toString @@ -131,10 +130,14 @@ object MilliBitcoins private case class MilliBitcoinsImpl(underlying: BigInt) extends MilliBitcoins { - require(underlying >= LnPolicy.minMilliBitcoins, - "Number was too small for MilliBitcoins, got: " + underlying) - require(underlying <= LnPolicy.maxMilliBitcoins, - "Number was too big for MilliBitcoins, got: " + underlying) + require( + underlying >= LnPolicy.minMilliBitcoins, + "Number was too small for MilliBitcoins, got: " + underlying + ) + require( + underlying <= LnPolicy.maxMilliBitcoins, + "Number was too big for MilliBitcoins, got: " + underlying + ) } } @@ -163,10 +166,14 @@ object MicroBitcoins private case class MicroBitcoinsImpl(underlying: BigInt) extends MicroBitcoins { - require(underlying >= LnPolicy.minMicroBitcoins, - "Number was too small for MicroBitcoins, got: " + underlying) - require(underlying <= LnPolicy.maxMicroBitcoins, - "Number was too big for MicroBitcoins, got: " + underlying) + require( + underlying >= LnPolicy.minMicroBitcoins, + "Number was too small for MicroBitcoins, got: " + underlying + ) + require( + underlying <= LnPolicy.maxMicroBitcoins, + "Number was too big for MicroBitcoins, got: " + underlying + ) } } @@ -194,10 +201,14 @@ object NanoBitcoins def apply(underlying: BigInt): NanoBitcoins = NanoBitcoinsImpl(underlying) private case class NanoBitcoinsImpl(underlying: BigInt) extends NanoBitcoins { - require(underlying >= LnPolicy.minNanoBitcoins, - "Number was too small for NanoBitcoins, got: " + underlying) - require(underlying <= LnPolicy.maxNanoBitcoins, - "Number was too big for NanoBitcoins, got: " + underlying) + require( + underlying >= LnPolicy.minNanoBitcoins, + "Number was too small for NanoBitcoins, got: " + underlying + ) + require( + underlying <= LnPolicy.maxNanoBitcoins, + "Number was too big for NanoBitcoins, got: " + underlying + ) } } @@ -223,10 +234,14 @@ object PicoBitcoins def apply(underlying: BigInt): PicoBitcoins = PicoBitcoinsImpl(underlying) private case class PicoBitcoinsImpl(underlying: BigInt) extends PicoBitcoins { - require(underlying >= LnPolicy.minPicoBitcoins, - "Number was too small for PicoBitcoins, got: " + underlying) - require(underlying <= LnPolicy.maxPicoBitcoins, - "Number was too big for PicoBitcoins, got: " + underlying) + require( + underlying >= LnPolicy.minPicoBitcoins, + "Number was too small for PicoBitcoins, got: " + underlying + ) + require( + underlying <= LnPolicy.maxPicoBitcoins, + "Number was too big for PicoBitcoins, got: " + underlying + ) } } @@ -246,8 +261,8 @@ object LnCurrencyUnits { } def fromMSat(msat: MilliSatoshis): PicoBitcoins = { - //msat are technically 10^-11 - //while pico are 10^-12, so we need to convert + // msat are technically 10^-11 + // while pico are 10^-12, so we need to convert val underlying = msat.toBigInt * MSAT_TO_PICO PicoBitcoins(underlying) } @@ -262,13 +277,18 @@ object LnCurrencyUnits { case "n" => Try(NanoBitcoins(amount.get)) case "p" => Try(PicoBitcoins(amount.get)) case _: String => - Failure(new IllegalArgumentException( - s"LnCurrencyUnit not found. Expected MilliBitcoins (m), MicroBitcoins (u), NanoBitcoins (n), or PicoBitcoins (p), got: $unit")) + Failure( + new IllegalArgumentException( + s"LnCurrencyUnit not found. Expected MilliBitcoins (m), MicroBitcoins (u), NanoBitcoins (n), or PicoBitcoins (p), got: $unit" + ) + ) } } else { Failure( new IllegalArgumentException( - s"Could not convert amount to valid number, got: $amount")) + s"Could not convert amount to valid number, got: $amount" + ) + ) } } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnMultiplier.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnMultiplier.scala index 8833fe81eb..406de34504 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnMultiplier.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/LnMultiplier.scala @@ -1,7 +1,8 @@ package org.bitcoins.core.protocol.ln.currency -/** Used by [[org.bitcoins.core.protocol.ln.currency.LnCurrencyUnit LnCurrencyUnit]] - * to scale between values +/** Used by + * [[org.bitcoins.core.protocol.ln.currency.LnCurrencyUnit LnCurrencyUnit]] to + * scale between values */ sealed abstract class LnMultiplier { val multiplier: BigDecimal diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshis.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshis.scala index 5dfd3913c3..0f51415264 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshis.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/currency/MilliSatoshis.scala @@ -8,10 +8,10 @@ import scodec.bits.ByteVector import scala.math.BigDecimal.RoundingMode -/** The common currency unit used in the - * LN protocol for updating HTLCs. +/** The common currency unit used in the LN protocol for updating HTLCs. * - * @see [[https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#adding-an-htlc-update_add_htlc BOLT2]] + * @see + * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#adding-an-htlc-update_add_htlc BOLT2]] */ sealed abstract class MilliSatoshis extends NetworkElement @@ -52,12 +52,12 @@ sealed abstract class MilliSatoshis } override def equals(obj: Any): Boolean = { - //needed for cases like - //1BTC == 100,000,000 satoshis should be true - //weirdly enough, this worked in scala version < 2.13.4 - //but seems to be broken in 2.13.4 :/ - //try removing this and running code, you should see - //failures in the 'lnurl' module + // needed for cases like + // 1BTC == 100,000,000 satoshis should be true + // weirdly enough, this worked in scala version < 2.13.4 + // but seems to be broken in 2.13.4 :/ + // try removing this and running code, you should see + // failures in the 'lnurl' module obj match { case ln: LnCurrencyUnit => toLnCurrencyUnit == ln case ms: MilliSatoshis => this.toBigInt == ms.toBigInt @@ -136,9 +136,9 @@ object MilliSatoshis { // we need to divide by 10 to get to msat val msatDec = pico / LnCurrencyUnits.MSAT_TO_PICO - //now we need to round, we are going to round the same way round - //outputs when publishing txs to the blockchain - //https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#commitment-transaction-outputs + // now we need to round, we are going to round the same way round + // outputs when publishing txs to the blockchain + // https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#commitment-transaction-outputs val rounded = msatDec.setScale(0, RoundingMode.DOWN) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/fee/FeeBaseMSat.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/fee/FeeBaseMSat.scala index 9ae670731d..abd08c1cf4 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/fee/FeeBaseMSat.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/fee/FeeBaseMSat.scala @@ -6,25 +6,27 @@ import org.bitcoins.crypto.NetworkElement import scodec.bits.ByteVector /** Represents the fee we charge for forwarding an HTLC on the Lightning network - * This is used in the ChannelUpdate and Routing information of a [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] - * See + * This is used in the ChannelUpdate and Routing information of a + * [[org.bitcoins.core.protocol.ln.LnInvoice LnInvoice]] See * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#the-channel_update-message BOLT7]] * and * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#on-mainnet-with-fallback-address-1rustyrx2oai4eyydpqgwvel62bbgqn9t-with-extra-routing-info-to-go-via-nodes-029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255-then-039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 BOLT11]] */ case class FeeBaseMSat(msat: MilliSatoshis) extends NetworkElement { - require(msat.toLong <= UInt32.max.toLong, - s"Value too large for FeeBaseMSat $msat") + require( + msat.toLong <= UInt32.max.toLong, + s"Value too large for FeeBaseMSat $msat" + ) override def bytes: ByteVector = { - //note that the feebase msat is only 4 bytes + // note that the feebase msat is only 4 bytes UInt32(msat.toLong).bytes } } /** Represents the proportion of a satoshi we charge for forwarding an HTLC - * through our channel. I.e. if the forwarded payment is larger, this fee will be larger. - * See + * through our channel. I.e. if the forwarded payment is larger, this fee will + * be larger. See * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#the-channel_update-message BOLT7]] */ case class FeeProportionalMillionths(u32: UInt32) extends NetworkElement { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/node/Feature.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/node/Feature.scala index de88b78f1d..e254bb5138 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/node/Feature.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/node/Feature.scala @@ -39,15 +39,18 @@ trait NodeFeature extends Feature /** Feature that should be advertised in invoices. */ trait InvoiceFeature extends Feature -/** Feature negotiated when opening a channel that will apply for all of the channel's lifetime. - * This doesn't include features that can be safely activated/deactivated without impacting the channel's operation such - * as option_dataloss_protect or option_shutdown_anysegwit. +/** Feature negotiated when opening a channel that will apply for all of the + * channel's lifetime. This doesn't include features that can be safely + * activated/deactivated without impacting the channel's operation such as + * option_dataloss_protect or option_shutdown_anysegwit. */ trait PermanentChannelFeature extends InitFeature // <- not in the spec -/** Permanent channel feature negotiated in the channel type. Those features take precedence over permanent channel - * features negotiated in init messages. For example, if the channel type is option_static_remotekey, then even if - * the option_anchor_outputs feature is supported by both peers, it won't apply to the channel. +/** Permanent channel feature negotiated in the channel type. Those features + * take precedence over permanent channel features negotiated in init messages. + * For example, if the channel type is option_static_remotekey, then even if + * the option_anchor_outputs feature is supported by both peers, it won't apply + * to the channel. */ trait ChannelTypeFeature extends PermanentChannelFeature // @formatter:on @@ -56,7 +59,8 @@ case class UnknownFeature(bitIndex: Int) case class Features[T <: Feature]( activated: Map[T, FeatureSupport], - unknown: Set[UnknownFeature] = Set.empty) { + unknown: Set[UnknownFeature] = Set.empty +) { def isEmpty: Boolean = activated.isEmpty && unknown.isEmpty @@ -69,7 +73,9 @@ case class Features[T <: Feature]( def hasPluginFeature(feature: UnknownFeature): Boolean = unknown.contains(feature) - /** NB: this method is not reflexive, see [[Features.areCompatible]] if you want symmetric validation. */ + /** NB: this method is not reflexive, see [[Features.areCompatible]] if you + * want symmetric validation. + */ def areSupported(remoteFeatures: Features[T]): Boolean = { // we allow unknown odd features (it's ok to be odd) val unknownFeaturesOk = remoteFeatures.unknown.forall(_.bitIndex % 2 == 1) @@ -89,11 +95,13 @@ case class Features[T <: Feature]( def invoiceFeatures(): Features[InvoiceFeature] = Features( activated.collect { case (f: InvoiceFeature, s) => (f, s) }, - unknown) + unknown + ) def unscoped(): Features[Feature] = Features[Feature]( activated.collect { case (f, s) => (f: Feature, s) }, - unknown) + unknown + ) def toByteVector: ByteVector = { val activatedFeatureBytes = toByteVectorFromIndex(activated.map { @@ -102,7 +110,8 @@ case class Features[T <: Feature]( val unknownFeatureBytes = toByteVectorFromIndex(unknown.map(_.bitIndex)) val maxSize = activatedFeatureBytes.size.max(unknownFeatureBytes.size) activatedFeatureBytes.padLeft(maxSize) | unknownFeatureBytes.padLeft( - maxSize) + maxSize + ) } private def toByteVectorFromIndex(indexes: Set[Int]): ByteVector = { @@ -381,28 +390,32 @@ object Features { extends IllegalArgumentException(message) def validateFeatureGraph[T <: Feature]( - features: Features[T]): Option[FeatureException] = + features: Features[T] + ): Option[FeatureException] = featuresDependency.collectFirst { case (feature, dependencies) - if features.unscoped().hasFeature(feature) && dependencies.exists(d => - !features.unscoped().hasFeature(d)) => + if features.unscoped().hasFeature(feature) && dependencies + .exists(d => !features.unscoped().hasFeature(d)) => FeatureException( s"$feature is set but is missing a dependency (${dependencies - .filter(d => !features.unscoped().hasFeature(d)) - .mkString(" and ")})") + .filter(d => !features.unscoped().hasFeature(d)) + .mkString(" and ")})" + ) } /** Returns true if both feature sets are compatible. */ def areCompatible[T <: Feature]( ours: Features[T], - theirs: Features[T]): Boolean = + theirs: Features[T] + ): Boolean = ours.areSupported(theirs) && theirs.areSupported(ours) /** returns true if both have at least optional support */ def canUseFeature[T <: Feature]( localFeatures: Features[T], remoteFeatures: Features[T], - feature: T): Boolean = { + feature: T + ): Boolean = { localFeatures.hasFeature(feature) && remoteFeatures.hasFeature(feature) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/node/NodeId.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/node/NodeId.scala index 58e6a28e73..ac0832753f 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/node/NodeId.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/node/NodeId.scala @@ -4,9 +4,8 @@ import org.bitcoins.crypto.{ECPublicKey, Factory, NetworkElement} import scodec.bits.ByteVector /** `NodeId` is simply a wrapper for - * [[org.bitcoins.crypto.ECPublicKey ECPublicKey]]. - * This public key needs to be a - * 33 byte compressed secp256k1 public key. + * [[org.bitcoins.crypto.ECPublicKey ECPublicKey]]. This public key needs to be + * a 33 byte compressed secp256k1 public key. */ case class NodeId(pubKey: ECPublicKey) extends NetworkElement { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/node/NodeUri.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/node/NodeUri.scala index 93103a11b4..481c19c22f 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/node/NodeUri.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/node/NodeUri.scala @@ -26,7 +26,8 @@ object NodeUri extends StringFactory[NodeUri] { Success(parse(withPort)) case None => Failure( - new IllegalArgumentException(s"Failed to parse $uri to a NodeUri")) + new IllegalArgumentException(s"Failed to parse $uri to a NodeUri") + ) } nodeUriT } @@ -45,7 +46,7 @@ object NodeUri extends StringFactory[NodeUri] { /** Assumes format is [nodeId]@[host]:[port] */ private def parse(validUri: String): NodeUri = { - //key is 33 bytes in size + // key is 33 bytes in size val (key: String, rest: String) = validUri.splitAt(66) val (host, port) = rest.splitAt(rest.length - 5) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/routing/LnRoute.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/routing/LnRoute.scala index 7eede5bbf5..d34d7f2fb4 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/routing/LnRoute.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/routing/LnRoute.scala @@ -13,8 +13,8 @@ import scodec.bits.ByteVector import java.math.BigInteger -/** Indicates a node to route through with specific options on the Lightning Network - * For more details on these settings please see +/** Indicates a node to route through with specific options on the Lightning + * Network For more details on these settings please see * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md#cltv_expiry_delta-selection BOLT2]] */ case class LnRoute( @@ -22,8 +22,8 @@ case class LnRoute( shortChannelID: ShortChannelId, feeBaseMsat: FeeBaseMSat, feePropMilli: FeeProportionalMillionths, - cltvExpiryDelta: Short) - extends NetworkElement { + cltvExpiryDelta: Short +) extends NetworkElement { override def bytes: ByteVector = { @@ -54,7 +54,8 @@ object LnRoute { require( bytes.length >= TOTAL_LEN, - s"ByteVector must at least of length $TOTAL_LEN, got ${bytes.length}") + s"ByteVector must at least of length $TOTAL_LEN, got ${bytes.length}" + ) val (pubKeyBytes, rest0) = bytes.splitAt(PUBKEY_LEN) val pubKey = ECPublicKey.fromBytes(pubKeyBytes) @@ -79,10 +80,12 @@ object LnRoute { val cltvExpiryDelta = new BigInteger(cltvExpiryDeltaBytes.toArray).shortValue() - LnRoute(pubKey, - shortChannelId, - feeBaseMSat, - feeProportionalMillionths, - cltvExpiryDelta) + LnRoute( + pubKey, + shortChannelId, + feeBaseMSat, + feeProportionalMillionths, + cltvExpiryDelta + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/routing/Route.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/routing/Route.scala index 384a349199..1049245797 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/routing/Route.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/routing/Route.scala @@ -12,10 +12,10 @@ sealed trait Route { case class NodeRoute( override val amount: MilliSatoshis, - nodeIds: Vector[NodeId]) - extends Route + nodeIds: Vector[NodeId] +) extends Route case class ChannelRoute( override val amount: MilliSatoshis, - shortChannelIds: Vector[ShortChannelId]) - extends Route + shortChannelIds: Vector[ShortChannelId] +) extends Route diff --git a/core/src/main/scala/org/bitcoins/core/protocol/ln/util/LnUtil.scala b/core/src/main/scala/org/bitcoins/core/protocol/ln/util/LnUtil.scala index f805792fe9..1b3e760b1c 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/ln/util/LnUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/ln/util/LnUtil.scala @@ -8,11 +8,11 @@ import scala.annotation.tailrec /** Useful utility functions for the Lightning encoding / decoding */ abstract class LnUtil { - /** The formula for this calculation is as follows: - * Take the length of the Bech32 encoded input and divide it by 32. - * Take the quotient, and encode this value as Bech32. Take the remainder and encode this value as Bech32. - * Append these values to produce a valid Lighting Network `data_length` field. - * Please see + /** The formula for this calculation is as follows: Take the length of the + * Bech32 encoded input and divide it by 32. Take the quotient, and encode + * this value as Bech32. Take the remainder and encode this value as Bech32. + * Append these values to produce a valid Lighting Network `data_length` + * field. Please see * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/11-payment-encoding.md#examples Bolt11]] * for examples. */ @@ -41,8 +41,10 @@ abstract class LnUtil { } def decodeDataLength(u5s: List[UInt5]): Long = { - require(u5s.length == 2, - s"Data Length is required to be 10 bits, got ${u5s.length}") + require( + u5s.length == 2, + s"Data Length is required to be 10 bits, got ${u5s.length}" + ) decodeNumber(u5s).toLong } @@ -50,7 +52,8 @@ abstract class LnUtil { @tailrec final def encodeNumber( len: BigInt, - accum: List[UInt5] = List.empty): List[UInt5] = { + accum: List[UInt5] = List.empty + ): List[UInt5] = { val quotient = len / 32 val remainder = UInt5(len % 32) if (quotient >= 32) { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/ControlBlock.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/ControlBlock.scala index b603ac0e64..9d82717e62 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/ControlBlock.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/ControlBlock.scala @@ -5,15 +5,18 @@ import scodec.bits.ByteVector /** Control block as defined by BIP341 * - * The last stack element is called the control block c, and must have length 33 + 32m, - * for a value of m that is an integer between 0 and 128[6], inclusive. Fail if it does not have such a length. + * The last stack element is called the control block c, and must have length + * 33 + 32m, for a value of m that is an integer between 0 and 128[6], + * inclusive. Fail if it does not have such a length. * - * @see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#script-validation-rules + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#script-validation-rules */ sealed abstract class ControlBlock extends NetworkElement { require(ControlBlock.isValid(bytes), s"Bytes for control block are not valid") - /** Let p = c[1:33] and let P = lift_x(int(p)) where lift_x and [:] are defined as in BIP340. Fail if this point is not on the curve. + /** Let p = c[1:33] and let P = lift_x(int(p)) where lift_x and [:] are + * defined as in BIP340. Fail if this point is not on the curve. */ def p: XOnlyPubKey = { XOnlyPubKey.fromBytes(bytes.slice(1, 33)) @@ -33,13 +36,15 @@ sealed abstract class ControlBlock extends NetworkElement { } case class TapscriptControlBlock(bytes: ByteVector) extends ControlBlock { - require(TapscriptControlBlock.isValid(bytes), - s"Invalid leaf version for tapscript control block, got=$bytes") + require( + TapscriptControlBlock.isValid(bytes), + s"Invalid leaf version for tapscript control block, got=$bytes" + ) } -/** A control block that does not have a leaf version defined as per BIP342 - * This is needed for future soft fork compatability where we introduce new leaf versions - * to correspond to new spending rules +/** A control block that does not have a leaf version defined as per BIP342 This + * is needed for future soft fork compatability where we introduce new leaf + * versions to correspond to new spending rules */ case class UnknownControlBlock(bytes: ByteVector) extends ControlBlock @@ -49,7 +54,8 @@ object ControlBlock extends Factory[ControlBlock] { new TapscriptControlBlock(bytes) } - /** invariants from: https://github.com/bitcoin/bitcoin/blob/37633d2f61697fc719390767aae740ece978b074/src/script/interpreter.cpp#L1835 + /** invariants from: + * https://github.com/bitcoin/bitcoin/blob/37633d2f61697fc719390767aae740ece978b074/src/script/interpreter.cpp#L1835 */ def isValid(bytes: ByteVector): Boolean = { bytes.size >= TaprootScriptPath.TAPROOT_CONTROL_BASE_SIZE && @@ -60,7 +66,8 @@ object ControlBlock extends Factory[ControlBlock] { object TapscriptControlBlock extends Factory[TapscriptControlBlock] { - /** invariants from: https://github.com/bitcoin/bitcoin/blob/37633d2f61697fc719390767aae740ece978b074/src/script/interpreter.cpp#L1835 + /** invariants from: + * https://github.com/bitcoin/bitcoin/blob/37633d2f61697fc719390767aae740ece978b074/src/script/interpreter.cpp#L1835 */ def isValid(bytes: ByteVector): Boolean = { if (bytes.isEmpty) { @@ -83,7 +90,8 @@ object TapscriptControlBlock extends Factory[TapscriptControlBlock] { def apply( internalKey: XOnlyPubKey, - leafHashes: Vector[TapLeaf]): ControlBlock = { + leafHashes: Vector[TapLeaf] + ): ControlBlock = { val bytes = internalKey.bytes ++ ByteVector.concat(leafHashes.map(_.bytes)) ControlBlock(bytes) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/Script.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/Script.scala index e64bcfe90a..398091641e 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/Script.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/Script.scala @@ -6,21 +6,19 @@ import org.bitcoins.core.util.BytesUtil import org.bitcoins.crypto.NetworkElement import scodec.bits.ByteVector -/** This is meant to be a super type for - * scripts in the bitcoin protocol. This gives us - * access to the asm representation, and how to serialize the script +/** This is meant to be a super type for scripts in the bitcoin protocol. This + * gives us access to the asm representation, and how to serialize the script */ abstract class Script extends NetworkElement { - /** Representation of a script in a parsed assembly format - * this data structure can be run through the script interpreter to - * see if a script evaluates to true - * used to represent the size of the script serialization + /** Representation of a script in a parsed assembly format this data structure + * can be run through the script interpreter to see if a script evaluates to + * true used to represent the size of the script serialization */ def asm: Seq[ScriptToken] - /** The byte representation of [[asm]], this does NOT have the bytes - * for the [[org.bitcoins.core.protocol.CompactSizeUInt]] in the script + /** The byte representation of [[asm]], this does NOT have the bytes for the + * [[org.bitcoins.core.protocol.CompactSizeUInt]] in the script */ val asmBytes: ByteVector = { BytesUtil.toByteVector(asm) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptFactory.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptFactory.scala index 811c16f6fc..890320709e 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptFactory.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptFactory.scala @@ -10,27 +10,33 @@ import scodec.bits.ByteVector */ trait ScriptFactory[T <: Script] extends Factory[T] { - /** Builds a script from the given asm with the given constructor if the invariant holds true, else throws an error */ + /** Builds a script from the given asm with the given constructor if the + * invariant holds true, else throws an error + */ def buildScript( asm: Vector[ScriptToken], constructor: Vector[ScriptToken] => T, - errorMsg: String): T = { + errorMsg: String + ): T = { if (isValidAsm(asm)) { constructor(asm) } else throw new IllegalArgumentException(errorMsg) } - /** Creates a T from the given [[org.bitcoins.core.script.constant.ScriptToken ScriptToken]]s */ + /** Creates a T from the given + * [[org.bitcoins.core.script.constant.ScriptToken ScriptToken]]s + */ def fromAsm(asm: Seq[ScriptToken]): T def fromBytes(bytes: ByteVector): T = { BitcoinScriptUtil.parseScript(bytes = bytes, f = fromAsm) } - /** Scripts are serialized with a [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] at the beginning - * to indicate how long the Script is. This construct assumes the - * [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] - * is NOT passed into the constructor. Only the actual Script program bytes. + /** Scripts are serialized with a + * [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] at the + * beginning to indicate how long the Script is. This construct assumes the + * [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] is NOT + * passed into the constructor. Only the actual Script program bytes. */ def fromAsmBytes(bytes: ByteVector): T = { val cmpct = CompactSizeUInt.calc(bytes) @@ -38,10 +44,13 @@ trait ScriptFactory[T <: Script] extends Factory[T] { fromBytes(fullBytes) } - /** Scripts are serialized with a [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] at the beginning - * to indicate how long the [[org.bitcoins.core.protocol.script.ScriptSignature ScriptSignature]] is - * . This construct assumes the [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] - * is NOT passed into the constructor. Only the actual Script program hex is. + /** Scripts are serialized with a + * [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] at the + * beginning to indicate how long the + * [[org.bitcoins.core.protocol.script.ScriptSignature ScriptSignature]] is . + * This construct assumes the + * [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] is NOT + * passed into the constructor. Only the actual Script program hex is. */ def fromAsmHex(hex: String): T = { fromAsmBytes(BytesUtil.decodeHex(hex)) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala index fca2723ae6..0a10eb0936 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptPubKey.scala @@ -35,8 +35,8 @@ sealed trait NonWitnessScriptPubKey extends ScriptPubKey /** Trait for all raw, non-nested ScriptPubKeys (no P2SH) * - * Note that all WitnessScriptPubKeys including P2WPKH are not - * considered to be non-nested and hence not RawScriptPubKeys. + * Note that all WitnessScriptPubKeys including P2WPKH are not considered to be + * non-nested and hence not RawScriptPubKeys. */ sealed trait RawScriptPubKey extends NonWitnessScriptPubKey @@ -56,8 +56,8 @@ sealed trait P2PKHScriptPubKey extends RawScriptPubKey { object P2PKHScriptPubKey extends ScriptFactory[P2PKHScriptPubKey] { private case class P2PKHScriptPubKeyImpl( - override val asm: Vector[ScriptToken]) - extends P2PKHScriptPubKey { + override val asm: Vector[ScriptToken] + ) extends P2PKHScriptPubKey { override val scriptType: ScriptType = ScriptType.PUBKEYHASH override def toString = s"${DescriptorType.PKH.toString}(${pubKeyHash.hex})" @@ -71,16 +71,20 @@ object P2PKHScriptPubKey extends ScriptFactory[P2PKHScriptPubKey] { def apply(hash: Sha256Hash160Digest): P2PKHScriptPubKey = { val pushOps = BitcoinScriptUtil.calculatePushOp(hash.bytes) val asm = - Seq(OP_DUP, OP_HASH160) ++ pushOps ++ Seq(ScriptConstant(hash.bytes), - OP_EQUALVERIFY, - OP_CHECKSIG) + Seq(OP_DUP, OP_HASH160) ++ pushOps ++ Seq( + ScriptConstant(hash.bytes), + OP_EQUALVERIFY, + OP_CHECKSIG + ) P2PKHScriptPubKey(asm) } def fromAsm(asm: Seq[ScriptToken]): P2PKHScriptPubKey = { - buildScript(asm.toVector, - P2PKHScriptPubKeyImpl.apply, - "Given asm was not a p2pkh scriptPubKey, got: " + asm) + buildScript( + asm.toVector, + P2PKHScriptPubKeyImpl.apply, + "Given asm was not a p2pkh scriptPubKey, got: " + asm + ) } def apply(asm: Seq[ScriptToken]): P2PKHScriptPubKey = fromAsm(asm) @@ -90,12 +94,14 @@ object P2PKHScriptPubKey extends ScriptFactory[P2PKHScriptPubKey] { */ override def isValidAsm(asm: Seq[ScriptToken]): Boolean = { asm match { - case Seq(OP_DUP, - OP_HASH160, - _: BytesToPushOntoStack, - _: ScriptConstant, - OP_EQUALVERIFY, - OP_CHECKSIG) => + case Seq( + OP_DUP, + OP_HASH160, + _: BytesToPushOntoStack, + _: ScriptConstant, + OP_EQUALVERIFY, + OP_CHECKSIG + ) => true case _ => false } @@ -103,8 +109,8 @@ object P2PKHScriptPubKey extends ScriptFactory[P2PKHScriptPubKey] { } /** Represents a multisignature script public key - * https://bitcoin.org/en/developer-guide#multisig - * Format: [B pubkey] [C pubkey...] OP_CHECKMULTISIG + * https://bitcoin.org/en/developer-guide#multisig Format: [B + * pubkey] [C pubkey...] OP_CHECKMULTISIG */ sealed trait MultiSignatureScriptPubKey extends RawScriptPubKey { @@ -114,7 +120,7 @@ sealed trait MultiSignatureScriptPubKey extends RawScriptPubKey { if (asm.indexOf(OP_CHECKMULTISIG) != -1) asmWithoutPushOps.indexOf(OP_CHECKMULTISIG) else asmWithoutPushOps.indexOf(OP_CHECKMULTISIGVERIFY) - //magic number 2 represents the maxSig operation and the OP_CHECKMULTISIG operation at the end of the asm + // magic number 2 represents the maxSig operation and the OP_CHECKMULTISIG operation at the end of the asm val numSigsRequired = asmWithoutPushOps(opCheckMultiSigIndex - maxSigs - 2) numSigsRequired match { case x: ScriptNumber => x @@ -126,24 +132,28 @@ sealed trait MultiSignatureScriptPubKey extends RawScriptPubKey { sn } else { sys.error( - s"Negative numSignaturesRequired given for MultiSignatureSPK, got=$sn") + s"Negative numSignaturesRequired given for MultiSignatureSPK, got=$sn" + ) } case _ => throw new RuntimeException( "The first element of the multisignature pubkey must be a script number operation\n" + "operation: " + numSigsRequired + - "\nscriptPubKey: " + this) + "\nscriptPubKey: " + this + ) } } - /** Returns the amount of required signatures for this multisignature script pubkey output */ + /** Returns the amount of required signatures for this multisignature script + * pubkey output + */ def requiredSigs: Int = { requiredSigsScriptNumber.toInt } def maxSigsScriptNumber: ScriptNumber = { if (checkMultiSigIndex == -1 || checkMultiSigIndex == 0) { - //means that we do not have a max signature requirement + // means that we do not have a max signature requirement OP_0 } else { asm(checkMultiSigIndex - 1) match { @@ -156,21 +166,27 @@ sealed trait MultiSignatureScriptPubKey extends RawScriptPubKey { maxSigs } else { sys.error( - s"Negative maxSigs given for MultiSignatureSPK, got=$maxSigs") + s"Negative maxSigs given for MultiSignatureSPK, got=$maxSigs" + ) } case x => throw new RuntimeException( - "The element preceding a OP_CHECKMULTISIG operation in a multisignature pubkey must be a script number operation, got: " + x) + "The element preceding a OP_CHECKMULTISIG operation in a multisignature pubkey must be a script number operation, got: " + x + ) } } } - /** The maximum amount of signatures for this multisignature script pubkey output */ + /** The maximum amount of signatures for this multisignature script pubkey + * output + */ def maxSigs: Int = { maxSigsScriptNumber.toInt } - /** Gives the `OP_CHECKMULTISIG` or `OP_CHECKMULTISIGVERIFY` index inside of asm */ + /** Gives the `OP_CHECKMULTISIG` or `OP_CHECKMULTISIGVERIFY` index inside of + * asm + */ private def checkMultiSigIndex: Int = { if (asm.indexOf(OP_CHECKMULTISIG) != -1) asm.indexOf(OP_CHECKMULTISIG) else asm.indexOf(OP_CHECKMULTISIGVERIFY) @@ -189,8 +205,8 @@ object MultiSignatureScriptPubKey extends ScriptFactory[MultiSignatureScriptPubKey] { private case class MultiSignatureScriptPubKeyImpl( - override val asm: Vector[ScriptToken]) - extends MultiSignatureScriptPubKey { + override val asm: Vector[ScriptToken] + ) extends MultiSignatureScriptPubKey { override val scriptType: ScriptType = ScriptType.MULTISIG @@ -200,15 +216,18 @@ object MultiSignatureScriptPubKey def apply( requiredSigs: Int, - pubKeys: Seq[ECPublicKey]): MultiSignatureScriptPubKey = { + pubKeys: Seq[ECPublicKey] + ): MultiSignatureScriptPubKey = { require( requiredSigs <= Consensus.maxPublicKeysPerMultiSig, "We cannot have more required signatures than: " + Consensus.maxPublicKeysPerMultiSig + " got: " + requiredSigs ) - require(pubKeys.length <= Consensus.maxPublicKeysPerMultiSig, - "We cannot have more public keys than " + - Consensus.maxPublicKeysPerMultiSig + " got: " + pubKeys.length) + require( + pubKeys.length <= Consensus.maxPublicKeysPerMultiSig, + "We cannot have more public keys than " + + Consensus.maxPublicKeysPerMultiSig + " got: " + pubKeys.length + ) val required = ScriptNumberOperation.fromNumber(requiredSigs) match { case Some(scriptNumOp) => Seq(scriptNumOp) @@ -231,31 +250,35 @@ object MultiSignatureScriptPubKey } yield pushOps ++ Seq(constant) val asm: Seq[ScriptToken] = required ++ pubKeysWithPushOps.flatten ++ possible ++ Seq( - OP_CHECKMULTISIG) + OP_CHECKMULTISIG + ) MultiSignatureScriptPubKey(asm) } def fromAsm(asm: Seq[ScriptToken]): MultiSignatureScriptPubKey = { - buildScript(asm.toVector, - MultiSignatureScriptPubKeyImpl.apply, - "Given asm was not a MultSignatureScriptPubKey, got: " + asm) + buildScript( + asm.toVector, + MultiSignatureScriptPubKeyImpl.apply, + "Given asm was not a MultSignatureScriptPubKey, got: " + asm + ) } def apply(asm: Seq[ScriptToken]): MultiSignatureScriptPubKey = fromAsm(asm) private val opCmsOPs = Vector(OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY) - /** Determines if the given script tokens are a multisignature `scriptPubKey` */ + /** Determines if the given script tokens are a multisignature `scriptPubKey` + */ override def isValidAsm(asm: Seq[ScriptToken]): Boolean = { if (asm.nonEmpty && opCmsOPs.exists(_ == asm.last)) { val cmsIdx = asm.size - 1 - //we need either the first or second asm operation to indicate how many signatures are required + // we need either the first or second asm operation to indicate how many signatures are required val hasRequiredSignaturesOpt: Option[Int] = { asm.headOption match { case None => None case Some(token) => - //this is for the case that we have more than 16 public keys, the - //first operation will be a push op, the second operation being the actual number of keys + // this is for the case that we have more than 16 public keys, the + // first operation will be a push op, the second operation being the actual number of keys token match { case _: BytesToPushOntoStack => isValidPubKeyNumber(asm.tail.head) @@ -263,7 +286,7 @@ object MultiSignatureScriptPubKey } } } - //the second to last asm operation should be the maximum amount of public keys + // the second to last asm operation should be the maximum amount of public keys val hasMaximumSignaturesOpt: Option[Int] = { val maxSigsIdx = asm.length - 2 if (maxSigsIdx >= cmsIdx || maxSigsIdx <= 0) { @@ -298,7 +321,7 @@ object MultiSignatureScriptPubKey def parsePublicKeys(asm: Seq[ScriptToken]): Seq[ECPublicKeyBytes] = { val keys = asm - .dropRight(2) //drop maxSigs, OP_CMS op + .dropRight(2) // drop maxSigs, OP_CMS op .filter(_.isInstanceOf[ScriptConstant]) .slice(1, asm.length) // drop requiredSigs .map(t => ECPublicKeyBytes(t.bytes)) @@ -307,12 +330,13 @@ object MultiSignatureScriptPubKey private def hasMaximumSignatures( maxSigs: Int, - asm: Seq[ScriptToken]): Boolean = { + asm: Seq[ScriptToken] + ): Boolean = { parsePublicKeys(asm).size == maxSigs } - /** Checks that the given script token is with the range of the maximum amount of - * public keys we can have in a + /** Checks that the given script token is with the range of the maximum amount + * of public keys we can have in a * [[org.bitcoins.core.protocol.script.MultiSignatureScriptPubKey MultiSignatureScriptPubKey]] */ @tailrec private def isValidPubKeyNumber(token: ScriptToken): Option[Int] = { @@ -320,14 +344,15 @@ object MultiSignatureScriptPubKey case sn: ScriptNumber => if ( sn >= ScriptNumber.zero && sn <= ScriptNumber( - Consensus.maxPublicKeysPerMultiSig) + Consensus.maxPublicKeysPerMultiSig + ) ) { Some(sn.toInt) } else { None } case constant: ScriptConstant => - //Consensus.maxPublicKeysPerMultiSig is at most 20, which can be represented by 2 bytes + // Consensus.maxPublicKeysPerMultiSig is at most 20, which can be represented by 2 bytes if (constant.bytes.size <= 2) { val sn = ScriptNumber.fromBytes(constant.bytes) isValidPubKeyNumber(sn) @@ -339,12 +364,14 @@ object MultiSignatureScriptPubKey } } -/** Represents a [[https://bitcoin.org/en/developer-guide#pay-to-script-hash-p2sh pay-to-scripthash public key]] +/** Represents a + * [[https://bitcoin.org/en/developer-guide#pay-to-script-hash-p2sh pay-to-scripthash public key]] * Format: `OP_HASH160 OP_EQUAL` */ sealed trait P2SHScriptPubKey extends NonWitnessScriptPubKey { - /** The hash of the script for which this scriptPubKey is being created from */ + /** The hash of the script for which this scriptPubKey is being created from + */ def scriptHash: Sha256Hash160Digest = Sha256Hash160Digest(asm(asm.length - 2).bytes) @@ -359,8 +386,10 @@ object P2SHScriptPubKey extends ScriptFactory[P2SHScriptPubKey] { } def apply(scriptPubKey: ScriptPubKey): P2SHScriptPubKey = { - require(!scriptPubKey.isInstanceOf[P2SHScriptPubKey], - s"Cannot do p2sh(p2sh()), got=$scriptPubKey") + require( + !scriptPubKey.isInstanceOf[P2SHScriptPubKey], + s"Cannot do p2sh(p2sh()), got=$scriptPubKey" + ) val hash = CryptoUtil.sha256Hash160(scriptPubKey.asmBytes) P2SHScriptPubKey(hash) } @@ -377,24 +406,29 @@ object P2SHScriptPubKey extends ScriptFactory[P2SHScriptPubKey] { */ override def isValidAsm(asm: Seq[ScriptToken]): Boolean = asm match { - case Seq(OP_HASH160, - _: BytesToPushOntoStack, - _: ScriptConstant, - OP_EQUAL) => + case Seq( + OP_HASH160, + _: BytesToPushOntoStack, + _: ScriptConstant, + OP_EQUAL + ) => true case _ => false } def fromAsm(asm: Seq[ScriptToken]): P2SHScriptPubKey = { - buildScript(asm.toVector, - P2SHScriptPubKeyImpl.apply, - "Given asm was not a p2sh scriptPubkey, got: " + asm) + buildScript( + asm.toVector, + P2SHScriptPubKeyImpl.apply, + "Given asm was not a p2sh scriptPubkey, got: " + asm + ) } def apply(asm: Seq[ScriptToken]): P2SHScriptPubKey = fromAsm(asm) } -/** Represents a [[https://bitcoin.org/en/developer-guide#pubkey pay to public key script public key]] +/** Represents a + * [[https://bitcoin.org/en/developer-guide#pubkey pay to public key script public key]] * Format: ` OP_CHECKSIG` */ sealed trait P2PKScriptPubKey extends RawScriptPubKey { @@ -414,24 +448,27 @@ object P2PKScriptPubKey extends ScriptFactory[P2PKScriptPubKey] { } def apply(pubKey: PublicKey): P2PKScriptPubKey = { - //comeback and review the type on this constructor, - //depending on the output type, the key type isn't safe - //i.e xonly can't be used pre-taproot and vice versa + // comeback and review the type on this constructor, + // depending on the output type, the key type isn't safe + // i.e xonly can't be used pre-taproot and vice versa val pushOps = BitcoinScriptUtil.calculatePushOp(pubKey.bytes) val asm = pushOps ++ Seq(ScriptConstant(pubKey.bytes), OP_CHECKSIG) P2PKScriptPubKey(asm) } def fromAsm(asm: Seq[ScriptToken]): P2PKScriptPubKey = { - buildScript(asm.toVector, - P2PKScriptPubKeyImpl.apply, - "Given asm was not a p2pk scriptPubKey, got: " + asm) + buildScript( + asm.toVector, + P2PKScriptPubKeyImpl.apply, + "Given asm was not a p2pk scriptPubKey, got: " + asm + ) } def apply(asm: Seq[ScriptToken]): P2PKScriptPubKey = fromAsm(asm) /** Sees if the given asm matches the - * [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey P2PKHScriptPubKey]] pattern + * [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey P2PKHScriptPubKey]] + * pattern */ override def isValidAsm(asm: Seq[ScriptToken]): Boolean = asm match { @@ -444,7 +481,8 @@ object P2PKScriptPubKey extends ScriptFactory[P2PKScriptPubKey] { */ private[core] def fromP2PKWithTimeout( p2pkWithTimeout: P2PKWithTimeoutScriptPubKey, - timeoutBranch: Boolean): P2PKScriptPubKey = { + timeoutBranch: Boolean + ): P2PKScriptPubKey = { val pubKeyBytes = if (timeoutBranch) p2pkWithTimeout.timeoutPubKey else p2pkWithTimeout.pubKey @@ -466,7 +504,9 @@ sealed trait LockTimeScriptPubKey extends RawScriptPubKey { } } - /** The relative locktime value (i.e. the amount of time the output should remain unspendable) */ + /** The relative locktime value (i.e. the amount of time the output should + * remain unspendable) + */ def locktime: ScriptNumber = { asm.head match { case scriptNumOp: ScriptNumberOperation => @@ -476,7 +516,8 @@ sealed trait LockTimeScriptPubKey extends RawScriptPubKey { throw new IllegalArgumentException( "In a LockTimeScriptPubKey, " + "the first asm must be either a ScriptNumberOperation (i.e. OP_5), or the BytesToPushOntoStack " + - "for the proceeding ScriptConstant.") + "for the proceeding ScriptConstant." + ) } } } @@ -489,7 +530,8 @@ object LockTimeScriptPubKey extends ScriptFactory[LockTimeScriptPubKey] { else if (asm.contains(OP_CHECKSEQUENCEVERIFY)) CSVScriptPubKey(asm) else throw new IllegalArgumentException( - "Given asm was not a LockTimeScriptPubKey, got: " + asm) + "Given asm was not a LockTimeScriptPubKey, got: " + asm + ) } override def isValidAsm(asm: Seq[ScriptToken]): Boolean = { @@ -498,8 +540,8 @@ object LockTimeScriptPubKey extends ScriptFactory[LockTimeScriptPubKey] { } } -/** Represents a scriptPubKey that contains `OP_CHECKLOCKTIMEVERIFY.` - * Adds an absolute/defined locktime condition to any scriptPubKey. +/** Represents a scriptPubKey that contains `OP_CHECKLOCKTIMEVERIFY.` Adds an + * absolute/defined locktime condition to any scriptPubKey. * [[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki BIP65]] * Format: ` OP_CLTV OP_DROP ` */ @@ -515,16 +557,19 @@ object CLTVScriptPubKey extends ScriptFactory[CLTVScriptPubKey] { } def fromAsm(asm: Seq[ScriptToken]): CLTVScriptPubKey = { - buildScript(asm.toVector, - CLTVScriptPubKeyImpl.apply, - "Given asm was not a CLTVScriptPubKey, got: " + asm) + buildScript( + asm.toVector, + CLTVScriptPubKeyImpl.apply, + "Given asm was not a CLTVScriptPubKey, got: " + asm + ) } def apply(asm: Seq[ScriptToken]): CLTVScriptPubKey = fromAsm(asm) def apply( locktime: ScriptNumber, - scriptPubKey: ScriptPubKey): CLTVScriptPubKey = { + scriptPubKey: ScriptPubKey + ): CLTVScriptPubKey = { val scriptOp = BitcoinScriptUtil.minimalScriptNumberRepresentation(locktime) val scriptNum: Seq[ScriptToken] = @@ -553,11 +598,13 @@ object CLTVScriptPubKey extends ScriptFactory[CLTVScriptPubKey] { false } else { asm.slice(0, 4) match { - case Seq(_: BytesToPushOntoStack, - s: ScriptConstant, - OP_CHECKLOCKTIMEVERIFY, - OP_DROP) => - //can only have up to 5 byte numbers for CLTV + case Seq( + _: BytesToPushOntoStack, + s: ScriptConstant, + OP_CHECKLOCKTIMEVERIFY, + OP_DROP + ) => + // can only have up to 5 byte numbers for CLTV s.byteSize <= 5 && validScriptAfterLockTime(tailTokens) case _ => false } @@ -581,13 +628,14 @@ object CLTVScriptPubKey extends ScriptFactory[CLTVScriptPubKey] { } } - /** We need this check because sometimes we can get very lucky in having a non valid - * lock time script that has the first 4 bytes as a valid locktime script - * and then the bytes after the first 4 bytes gets lucky and is parsed by our - * [[org.bitcoins.core.serializers.script.ScriptParser ScriptParser]] - * A good way to see if this is _actually_ a valid script is by checking if we have any - * [[org.bitcoins.core.script.reserved.UndefinedOP_NOP UndefinedOP_NOP]] in the script, - * which means we definitely don't have a valid locktime script + /** We need this check because sometimes we can get very lucky in having a non + * valid lock time script that has the first 4 bytes as a valid locktime + * script and then the bytes after the first 4 bytes gets lucky and is parsed + * by our [[org.bitcoins.core.serializers.script.ScriptParser ScriptParser]] + * A good way to see if this is _actually_ a valid script is by checking if + * we have any + * [[org.bitcoins.core.script.reserved.UndefinedOP_NOP UndefinedOP_NOP]] in + * the script, which means we definitely don't have a valid locktime script * * See this example of what happened before we added this check: * [[https://travis-ci.org/bitcoin-s/bitcoin-s-core/builds/201652191#L2526 Travis CI]] @@ -615,16 +663,19 @@ object CSVScriptPubKey extends ScriptFactory[CSVScriptPubKey] { } def fromAsm(asm: Seq[ScriptToken]): CSVScriptPubKey = { - buildScript(asm.toVector, - CSVScriptPubKeyImpl.apply, - "Given asm was not a CSVScriptPubKey, got: " + asm) + buildScript( + asm.toVector, + CSVScriptPubKeyImpl.apply, + "Given asm was not a CSVScriptPubKey, got: " + asm + ) } def apply(asm: Seq[ScriptToken]): CSVScriptPubKey = fromAsm(asm) def apply( relativeLockTime: ScriptNumber, - scriptPubKey: ScriptPubKey): CSVScriptPubKey = { + scriptPubKey: ScriptPubKey + ): CSVScriptPubKey = { val scriptOp = BitcoinScriptUtil.minimalScriptNumberRepresentation(relativeLockTime) @@ -653,14 +704,16 @@ object CSVScriptPubKey extends ScriptFactory[CSVScriptPubKey] { false } else { asm.slice(0, 4) match { - case Seq(_: BytesToPushOntoStack, - s: ScriptConstant, - OP_CHECKSEQUENCEVERIFY, - OP_DROP) => - //check that the byteSize of the ScriptNum is less than or equal to 5 - //as per BIP112 + case Seq( + _: BytesToPushOntoStack, + s: ScriptConstant, + OP_CHECKSEQUENCEVERIFY, + OP_DROP + ) => + // check that the byteSize of the ScriptNum is less than or equal to 5 + // as per BIP112 s.byteSize <= 5 && - CLTVScriptPubKey.validScriptAfterLockTime(tailTokens) + CLTVScriptPubKey.validScriptAfterLockTime(tailTokens) case _ => false } } @@ -684,23 +737,32 @@ object CSVScriptPubKey extends ScriptFactory[CSVScriptPubKey] { } -/** Currently only supports a single OP_IF ... OP_ELSE ... OP_ENDIF ScriptPubKey */ +/** Currently only supports a single OP_IF ... OP_ELSE ... OP_ENDIF ScriptPubKey + */ sealed trait ConditionalScriptPubKey extends RawScriptPubKey { def conditional: ConditionalOperation - require(asm.headOption.contains(conditional), - s"ConditionalScriptPubKey must begin with $conditional") - require(asm.last.equals(OP_ENDIF), - "ConditionalScriptPubKey must end in OP_ENDIF") + require( + asm.headOption.contains(conditional), + s"ConditionalScriptPubKey must begin with $conditional" + ) + require( + asm.last.equals(OP_ENDIF), + "ConditionalScriptPubKey must end in OP_ENDIF" + ) val (isValidConditional: Boolean, opElseIndexOpt: Option[Int]) = { - ConditionalScriptPubKey.isConditionalScriptPubKeyWithElseIndex(asm, - conditional) + ConditionalScriptPubKey.isConditionalScriptPubKeyWithElseIndex( + asm, + conditional + ) } require(isValidConditional, "Must be valid ConditionalScriptPubKey syntax") - require(opElseIndexOpt.isDefined, - "ConditionalScriptPubKey has to contain OP_ELSE asm token") + require( + opElseIndexOpt.isDefined, + "ConditionalScriptPubKey has to contain OP_ELSE asm token" + ) val opElseIndex: Int = opElseIndexOpt.get @@ -738,12 +800,13 @@ sealed trait ConditionalScriptPubKey extends RawScriptPubKey { object ConditionalScriptPubKey { - /** Validates the correctness of the conditional syntax. - * If valid, also returns the index of the first outer-most OP_ELSE + /** Validates the correctness of the conditional syntax. If valid, also + * returns the index of the first outer-most OP_ELSE */ def isConditionalScriptPubKeyWithElseIndex( asm: Seq[ScriptToken], - conditional: ConditionalOperation): (Boolean, Option[Int]) = { + conditional: ConditionalOperation + ): (Boolean, Option[Int]) = { val headIsConditional = asm.headOption.contains(conditional) lazy val endsWithEndIf = asm.last == OP_ENDIF @@ -756,7 +819,8 @@ object ConditionalScriptPubKey { .foldLeft[Option[Vector[Boolean]]](Some(Vector(false))) { case (None, _) => // Invalid tree case, do no computation None - case (Some(Vector()), + case ( + Some(Vector()), _ ) => // Case of additional asm after final OP_ENDIF None @@ -775,7 +839,8 @@ object ConditionalScriptPubKey { } else { // Otherwise, set to found at this depth Some( - opElseFoundAtDepth.updated(opElseFoundAtDepth.length - 1, true)) + opElseFoundAtDepth.updated(opElseFoundAtDepth.length - 1, true) + ) } case (Some(opElseFoundAtDepth), (OP_ENDIF, _)) => if (opElseFoundAtDepth.last) { @@ -800,12 +865,15 @@ object ConditionalScriptPubKey { def apply( conditional: ConditionalOperation, trueSPK: RawScriptPubKey, - falseSPK: RawScriptPubKey): ConditionalScriptPubKey = { + falseSPK: RawScriptPubKey + ): ConditionalScriptPubKey = { conditional match { case OP_IF => (trueSPK, falseSPK) match { - case (multisig: MultiSignatureScriptPubKey, - timeout: CLTVScriptPubKey) => + case ( + multisig: MultiSignatureScriptPubKey, + timeout: CLTVScriptPubKey + ) => MultiSignatureWithTimeoutScriptPubKey(multisig, timeout) case _ => NonStandardIfConditionalScriptPubKey(trueSPK, falseSPK) @@ -824,8 +892,8 @@ object NonStandardIfConditionalScriptPubKey extends ScriptFactory[IfConditionalScriptPubKey] { private case class NonStandardIfConditionalScriptPubKeyImpl( - override val asm: Vector[ScriptToken]) - extends IfConditionalScriptPubKey { + override val asm: Vector[ScriptToken] + ) extends IfConditionalScriptPubKey { override val scriptType: ScriptType = ScriptType.NONSTANDARD_IF_CONDITIONAL override def toString: String = @@ -843,10 +911,12 @@ object NonStandardIfConditionalScriptPubKey def apply( trueSPK: RawScriptPubKey, - falseSPK: RawScriptPubKey): IfConditionalScriptPubKey = { + falseSPK: RawScriptPubKey + ): IfConditionalScriptPubKey = { val asm = Vector(OP_IF) ++ trueSPK.asm ++ Vector(OP_ELSE) ++ falseSPK.asm ++ Vector( - OP_ENDIF) + OP_ENDIF + ) fromAsm(asm) } @@ -865,10 +935,14 @@ object NonStandardIfConditionalScriptPubKey sealed trait MultiSignatureWithTimeoutScriptPubKey extends IfConditionalScriptPubKey { - require(MultiSignatureScriptPubKey.isValidAsm(super.firstSPK.asm), - "True case must be MultiSignatureSPK") - require(CLTVScriptPubKey.isValidAsm(super.secondSPK.asm), - "False case must be CLTVSPK") + require( + MultiSignatureScriptPubKey.isValidAsm(super.firstSPK.asm), + "True case must be MultiSignatureSPK" + ) + require( + CLTVScriptPubKey.isValidAsm(super.secondSPK.asm), + "False case must be CLTVSPK" + ) override def firstSPK: MultiSignatureScriptPubKey = { MultiSignatureScriptPubKey.fromAsm(asm.slice(1, opElseIndex)) @@ -893,8 +967,8 @@ object MultiSignatureWithTimeoutScriptPubKey extends ScriptFactory[MultiSignatureWithTimeoutScriptPubKey] { private case class MultiSignatureWithTimeoutScriptPubKeyImpl( - override val asm: Vector[ScriptToken]) - extends MultiSignatureWithTimeoutScriptPubKey { + override val asm: Vector[ScriptToken] + ) extends MultiSignatureWithTimeoutScriptPubKey { override val scriptType: ScriptType = ScriptType.MULTISIG_WITH_TIMEOUT override def toString: String = @@ -902,7 +976,8 @@ object MultiSignatureWithTimeoutScriptPubKey } override def fromAsm( - asm: Seq[ScriptToken]): MultiSignatureWithTimeoutScriptPubKey = { + asm: Seq[ScriptToken] + ): MultiSignatureWithTimeoutScriptPubKey = { buildScript( asm = asm.toVector, constructor = MultiSignatureWithTimeoutScriptPubKeyImpl.apply, @@ -913,9 +988,11 @@ object MultiSignatureWithTimeoutScriptPubKey def apply( multiSigSPK: MultiSignatureScriptPubKey, - cltvSPK: CLTVScriptPubKey): MultiSignatureWithTimeoutScriptPubKey = { + cltvSPK: CLTVScriptPubKey + ): MultiSignatureWithTimeoutScriptPubKey = { val asm = Vector(OP_IF) ++ multiSigSPK.asm ++ Vector( - OP_ELSE) ++ cltvSPK.asm ++ Vector(OP_ENDIF) + OP_ELSE + ) ++ cltvSPK.asm ++ Vector(OP_ENDIF) fromAsm(asm) } @@ -944,8 +1021,8 @@ object NonStandardNotIfConditionalScriptPubKey extends ScriptFactory[NotIfConditionalScriptPubKey] { private case class NonStandardNotIfConditionalScriptPubKeyImpl( - override val asm: Vector[ScriptToken]) - extends NotIfConditionalScriptPubKey { + override val asm: Vector[ScriptToken] + ) extends NotIfConditionalScriptPubKey { override val scriptType: ScriptType = ScriptType.NOT_IF_CONDITIONAL override def toString: String = @@ -962,9 +1039,11 @@ object NonStandardNotIfConditionalScriptPubKey def apply( falseSPK: RawScriptPubKey, - trueSPK: RawScriptPubKey): NotIfConditionalScriptPubKey = { + trueSPK: RawScriptPubKey + ): NotIfConditionalScriptPubKey = { val asm = Vector(OP_NOTIF) ++ falseSPK.asm ++ Vector( - OP_ELSE) ++ trueSPK.asm ++ Vector(OP_ENDIF) + OP_ELSE + ) ++ trueSPK.asm ++ Vector(OP_ENDIF) fromAsm(asm) } @@ -976,14 +1055,8 @@ object NonStandardNotIfConditionalScriptPubKey } } -/** The type for ScriptPubKeys of the form: - * OP_IF - * - * OP_ELSE - * OP_CHECKSEQUENCEVERIFY OP_DROP - * - * OP_ENDIF - * OP_CHECKSIG +/** The type for ScriptPubKeys of the form: OP_IF OP_ELSE + * OP_CHECKSEQUENCEVERIFY OP_DROP OP_ENDIF OP_CHECKSIG */ sealed trait P2PKWithTimeoutScriptPubKey extends RawScriptPubKey { @@ -1030,7 +1103,8 @@ object P2PKWithTimeoutScriptPubKey def apply( pubKey: ECPublicKey, lockTime: ScriptNumber, - timeoutPubKey: ECPublicKey): P2PKWithTimeoutScriptPubKey = { + timeoutPubKey: ECPublicKey + ): P2PKWithTimeoutScriptPubKey = { val timeoutAsm = CSVScriptPubKey(lockTime, EmptyScriptPubKey).asm.toVector val pubKeyAsm = BitcoinScriptUtil .calculatePushOp(pubKey.bytes) @@ -1040,12 +1114,14 @@ object P2PKWithTimeoutScriptPubKey .toVector ++ Vector(ScriptConstant(timeoutPubKey.bytes)) P2PKWithTimeoutScriptPubKeyImpl( - Vector(Vector(OP_IF), - pubKeyAsm, - Vector(OP_ELSE), - timeoutAsm, - timeoutPubKeyAsm, - Vector(OP_ENDIF, OP_CHECKSIG)).flatten + Vector( + Vector(OP_IF), + pubKeyAsm, + Vector(OP_ELSE), + timeoutAsm, + timeoutPubKeyAsm, + Vector(OP_ENDIF, OP_CHECKSIG) + ).flatten ) } @@ -1072,13 +1148,15 @@ object P2PKWithTimeoutScriptPubKey } if (timeoutPubKeyTry.isSuccess && lockTimeTry.isSuccess) { - //this check is expensive, so do it only if we need it + // this check is expensive, so do it only if we need it val pubKeyTry = Try(ECPublicKey.fromBytes(asm(2).bytes)) pubKeyTry match { case Success(pubKey) => - asm == P2PKWithTimeoutScriptPubKey(pubKey, - lockTimeTry.get, - timeoutPubKeyTry.get).asm + asm == P2PKWithTimeoutScriptPubKey( + pubKey, + lockTimeTry.get, + timeoutPubKeyTry.get + ).asm case Failure(_) => false } } else { @@ -1096,15 +1174,15 @@ sealed trait NonStandardScriptPubKey extends RawScriptPubKey object NonStandardScriptPubKey extends ScriptFactory[NonStandardScriptPubKey] { private case class NonStandardScriptPubKeyImpl( - override val asm: Vector[ScriptToken]) - extends NonStandardScriptPubKey { + override val asm: Vector[ScriptToken] + ) extends NonStandardScriptPubKey { override val scriptType: ScriptType = ScriptType.NONSTANDARD override def toString = s"NonStandardScriptPubKey($asm)" } def fromAsm(asm: Seq[ScriptToken]): NonStandardScriptPubKey = { - //everything can be a NonStandardScriptPubkey, thus the trivially true function + // everything can be a NonStandardScriptPubkey, thus the trivially true function buildScript(asm.toVector, NonStandardScriptPubKeyImpl.apply, "") } @@ -1206,8 +1284,8 @@ object ScriptPubKey extends ScriptFactory[ScriptPubKey] { } /** This type represents a - * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] to evaluate a - * [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] to evaluate + * a [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] */ sealed trait WitnessScriptPubKey extends ScriptPubKey { def witnessProgram: Seq[ScriptToken] @@ -1219,23 +1297,25 @@ object WitnessScriptPubKey extends ScriptFactory[WitnessScriptPubKey] { /** Witness scripts must begin with one of these operations, see * [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP141]] */ - val validWitVersions: Seq[ScriptNumberOperation] = Seq(OP_0, - OP_1, - OP_2, - OP_3, - OP_4, - OP_5, - OP_6, - OP_7, - OP_8, - OP_9, - OP_10, - OP_11, - OP_12, - OP_13, - OP_14, - OP_15, - OP_16) + val validWitVersions: Seq[ScriptNumberOperation] = Seq( + OP_0, + OP_1, + OP_2, + OP_3, + OP_4, + OP_5, + OP_6, + OP_7, + OP_8, + OP_9, + OP_10, + OP_11, + OP_12, + OP_13, + OP_14, + OP_15, + OP_16 + ) val unassignedWitVersions: Seq[ScriptNumberOperation] = validWitVersions.tail.tail @@ -1254,7 +1334,8 @@ object WitnessScriptPubKey extends ScriptFactory[WitnessScriptPubKey] { UnassignedWitnessScriptPubKey(asm) case _ => throw new IllegalArgumentException( - "Given asm was not a WitnessScriptPubKey, got: " + asm) + "Given asm was not a WitnessScriptPubKey, got: " + asm + ) } /** Checks if the given asm is a valid @@ -1265,18 +1346,18 @@ object WitnessScriptPubKey extends ScriptFactory[WitnessScriptPubKey] { */ override def isValidAsm(asm: Seq[ScriptToken]): Boolean = { - //multisig spk with zero public keys - //OP_0, BytesToPushOntoStackImpl(3), ScriptConstantImpl(ByteVector(3 bytes, 0x0000ae) + // multisig spk with zero public keys + // OP_0, BytesToPushOntoStackImpl(3), ScriptConstantImpl(ByteVector(3 bytes, 0x0000ae) - //multisig spk with one public key - //List(OP_0, BytesToPushOntoStackImpl(37), + // multisig spk with one public key + // List(OP_0, BytesToPushOntoStackImpl(37), // ScriptConstantImpl(ByteVector(37 bytes, 0x0021020afd6012af90835558c68365a370b7e6cd1c0d4664a8656c8c7847185cb5db6651ae))) - //we can also have a LockTimeScriptPubKey with a nested 0 public key multisig script, need to check that as well + // we can also have a LockTimeScriptPubKey with a nested 0 public key multisig script, need to check that as well - //it turns out this method gets called a lot when we attempt - //to type check spks, so let's do a cheap check before deserializing - //everything to a byte vector which is expensive + // it turns out this method gets called a lot when we attempt + // to type check spks, so let's do a cheap check before deserializing + // everything to a byte vector which is expensive val firstOp = asm.headOption if (!validWitVersions.contains(firstOp.getOrElse(OP_1NEGATE))) { false @@ -1301,10 +1382,10 @@ sealed abstract class WitnessScriptPubKeyV0 extends WitnessScriptPubKey { object WitnessScriptPubKeyV0 extends ScriptFactory[WitnessScriptPubKeyV0] { /** Mimics the function to determine if a - * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] contains a witness - * A witness program is any valid - * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] that consists of a 1 byte push op and then a data push - * between 2 and 40 bytes + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] contains a + * witness A witness program is any valid + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] that + * consists of a 1 byte push op and then a data push between 2 and 40 bytes * Verison 0 witness program need to have an OP_0 as the first operation * [[https://github.com/bitcoin/bitcoin/blob/449f9b8debcceb61a92043bc7031528a53627c47/src/script/script.cpp#L215-L229]] */ @@ -1322,7 +1403,8 @@ object WitnessScriptPubKeyV0 extends ScriptFactory[WitnessScriptPubKeyV0] { P2WSHWitnessSPKV0.fromAsm(asm) case _ => sys.error( - s"The given asm was not a valid WitnessScriptPubKeyV0, got asm=$asm") + s"The given asm was not a valid WitnessScriptPubKeyV0, got asm=$asm" + ) } } @@ -1337,15 +1419,17 @@ sealed abstract class P2WPKHWitnessSPKV0 extends WitnessScriptPubKeyV0 { object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] { private case class P2WPKHWitnessSPKV0Impl( - override val asm: Vector[ScriptToken]) - extends P2WPKHWitnessSPKV0 { + override val asm: Vector[ScriptToken] + ) extends P2WPKHWitnessSPKV0 { override val scriptType: ScriptType = ScriptType.WITNESS_V0_KEYHASH } override def fromAsm(asm: Seq[ScriptToken]): P2WPKHWitnessSPKV0 = { - buildScript(asm.toVector, - P2WPKHWitnessSPKV0Impl.apply, - s"Given asm was not a P2WPKHWitnessSPKV0, got $asm") + buildScript( + asm.toVector, + P2WPKHWitnessSPKV0Impl.apply, + s"Given asm was not a P2WPKHWitnessSPKV0, got $asm" + ) } def isValidAsm(asm: Seq[ScriptToken]): Boolean = { @@ -1360,10 +1444,11 @@ object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] { /** Builds a P2WPKH SPK from raw ECPublicKeyBytes (unsafe). */ private[core] def apply(pubKey: ECPublicKeyBytes): P2WPKHWitnessSPKV0 = { - //https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#restrictions-on-public-key-type + // https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#restrictions-on-public-key-type require( pubKey.isCompressed, - s"Public key must be compressed to be used in a segwit script, see BIP143") + s"Public key must be compressed to be used in a segwit script, see BIP143" + ) P2WPKHWitnessSPKV0(pubKey.toPublicKey) } @@ -1371,7 +1456,8 @@ object P2WPKHWitnessSPKV0 extends ScriptFactory[P2WPKHWitnessSPKV0] { def apply(pubKey: ECPublicKey): P2WPKHWitnessSPKV0 = { require( pubKey.isCompressed, - s"Public key must be compressed to be used in a segwit script, see BIP143") + s"Public key must be compressed to be used in a segwit script, see BIP143" + ) val hash = CryptoUtil.sha256Hash160(pubKey.bytes) val pushop = BitcoinScriptUtil.calculatePushOp(hash.bytes) fromAsm(Seq(OP_0) ++ pushop ++ Seq(ScriptConstant(hash.bytes))) @@ -1389,15 +1475,17 @@ sealed abstract class P2WSHWitnessSPKV0 extends WitnessScriptPubKeyV0 { object P2WSHWitnessSPKV0 extends ScriptFactory[P2WSHWitnessSPKV0] { private case class P2WSHWitnessSPKV0Impl( - override val asm: Vector[ScriptToken]) - extends P2WSHWitnessSPKV0 { + override val asm: Vector[ScriptToken] + ) extends P2WSHWitnessSPKV0 { override val scriptType: ScriptType = ScriptType.WITNESS_V0_SCRIPTHASH } override def fromAsm(asm: Seq[ScriptToken]): P2WSHWitnessSPKV0 = { - buildScript(asm.toVector, - P2WSHWitnessSPKV0Impl.apply, - s"Given asm was not a P2WSHWitnessSPKV0, got $asm") + buildScript( + asm.toVector, + P2WSHWitnessSPKV0Impl.apply, + s"Given asm was not a P2WSHWitnessSPKV0, got $asm" + ) } override def isValidAsm(asm: Seq[ScriptToken]): Boolean = { @@ -1414,7 +1502,8 @@ object P2WSHWitnessSPKV0 extends ScriptFactory[P2WSHWitnessSPKV0] { def apply(spk: RawScriptPubKey): P2WSHWitnessSPKV0 = { require( BitcoinScriptUtil.isOnlyCompressedPubKey(spk), - s"Public key must be compressed to be used in a segwit script, see BIP143") + s"Public key must be compressed to be used in a segwit script, see BIP143" + ) val hash = CryptoUtil.sha256(spk.asmBytes) val pushop = BitcoinScriptUtil.calculatePushOp(hash.bytes) fromAsm(Seq(OP_0) ++ pushop ++ Seq(ScriptConstant(hash.bytes))) @@ -1425,15 +1514,20 @@ case class TaprootScriptPubKey(override val asm: Vector[ScriptToken]) extends WitnessScriptPubKey { require( witnessVersion == WitnessVersion1, - s"Taproot scriptpubkeys must have witnessVersion OP_1, got=$witnessVersion") - require(bytes.length == 35, - s"Taproot spks must have length 35, got=${bytes.length}") + s"Taproot scriptpubkeys must have witnessVersion OP_1, got=$witnessVersion" + ) + require( + bytes.length == 35, + s"Taproot spks must have length 35, got=${bytes.length}" + ) override def witnessProgram: Seq[ScriptToken] = asm.tail.tail override val scriptType: ScriptType = ScriptType.WITNESS_V1_TAPROOT val pubKey: XOnlyPubKey = { - require(asm(2).bytes.length == 32, - s"pubKeyBytes must be 32 bytes in length, got=${asm(2).byteSize}") + require( + asm(2).bytes.length == 32, + s"pubKeyBytes must be 32 bytes in length, got=${asm(2).byteSize}" + ) XOnlyPubKey.fromBytes(asm(2).bytes) } @@ -1443,9 +1537,11 @@ case class TaprootScriptPubKey(override val asm: Vector[ScriptToken]) object TaprootScriptPubKey extends ScriptFactory[TaprootScriptPubKey] { override def fromAsm(asm: Seq[ScriptToken]): TaprootScriptPubKey = { - buildScript(asm.toVector, - TaprootScriptPubKey.apply, - s"Given asm was not a TaprootScriptPubKey, got $asm") + buildScript( + asm.toVector, + TaprootScriptPubKey.apply, + s"Given asm was not a TaprootScriptPubKey, got $asm" + ) } def apply(xOnlyPubKey: XOnlyPubKey): TaprootScriptPubKey = { @@ -1464,7 +1560,8 @@ object TaprootScriptPubKey extends ScriptFactory[TaprootScriptPubKey] { def fromInternalKeyTapscriptTree( internal: XOnlyPubKey, - tree: TapscriptTree): (KeyParity, TaprootScriptPubKey) = { + tree: TapscriptTree + ): (KeyParity, TaprootScriptPubKey) = { val merkleRoot = TaprootScriptPath.computeFullTreeMerkleRoot(tree) val (parity, tweak) = internal.createTapTweak(Some(merkleRoot)) (parity, fromPubKey(tweak)) @@ -1476,15 +1573,17 @@ object TaprootScriptPubKey extends ScriptFactory[TaprootScriptPubKey] { asm.headOption.contains(OP_1) && WitnessScriptPubKey.isValidAsm(asm) && asmBytes.size == 34 && - //have to make sure we have a valid xonly pubkey, not just 32 bytes + // have to make sure we have a valid xonly pubkey, not just 32 bytes XOnlyPubKey.fromBytesT(asm(2).bytes).isSuccess } - /** Computes a [[TaprootScriptPubKey]] from a given internal key with no [[TaprootScriptPath]] - * If the spending conditions do not require a script path, the output key should - * commit to an unspendable script path instead of having no script path. - * This can be achieved by computing the output key point as Q = P + int(hashTapTweak(bytes(P)))G. - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs]] + /** Computes a [[TaprootScriptPubKey]] from a given internal key with no + * [[TaprootScriptPath]] If the spending conditions do not require a script + * path, the output key should commit to an unspendable script path instead + * of having no script path. This can be achieved by computing the output key + * point as Q = P + int(hashTapTweak(bytes(P)))G. + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs]] */ def fromInternalKey(xOnlyPubKey: XOnlyPubKey): TaprootScriptPubKey = { val hash = CryptoUtil.tapTweakHash(xOnlyPubKey.bytes) @@ -1501,14 +1600,17 @@ object TaprootScriptPubKey extends ScriptFactory[TaprootScriptPubKey] { @tailrec private def computeMerkleRootHelper( - hashes: Vector[Sha256Digest]): Sha256Digest = { - require(hashes.length > 0, - s"Cannot computeMerkleRoot() with 0 hashes=$hashes") + hashes: Vector[Sha256Digest] + ): Sha256Digest = { + require( + hashes.length > 0, + s"Cannot computeMerkleRoot() with 0 hashes=$hashes" + ) if (hashes.length > 1) { val result: Vector[Sha256Digest] = hashes .grouped(2) .map { grouped => - //need to recurse? + // need to recurse? CryptoUtil.tapBranchHash(grouped(0).bytes ++ grouped(1).bytes) } .toVector @@ -1531,8 +1633,8 @@ object UnassignedWitnessScriptPubKey extends ScriptFactory[UnassignedWitnessScriptPubKey] { private case class UnassignedWitnessScriptPubKeyImpl( - override val asm: Vector[ScriptToken]) - extends UnassignedWitnessScriptPubKey { + override val asm: Vector[ScriptToken] + ) extends UnassignedWitnessScriptPubKey { override val scriptType: ScriptType = ScriptType.WITNESS_UNKNOWN override def toString = s"UnassignedWitnessScriptPubKey($asm)" @@ -1552,9 +1654,9 @@ object UnassignedWitnessScriptPubKey } } -/** This trait represents the witness commitment found in the coinbase transaction - * This is needed to commit to the wtxids of all of the witness transactions, since the merkle tree - * does not commit to the witnesses for all +/** This trait represents the witness commitment found in the coinbase + * transaction This is needed to commit to the wtxids of all of the witness + * transactions, since the merkle tree does not commit to the witnesses for all * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] * See BIP141 for more info * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure]] @@ -1562,8 +1664,8 @@ object UnassignedWitnessScriptPubKey sealed trait WitnessCommitment extends RawScriptPubKey { /** The commitment to the - * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]]s in the - * [[org.bitcoins.core.protocol.blockchain.Block Block]] + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]]s + * in the [[org.bitcoins.core.protocol.blockchain.Block Block]] */ def witnessRootHash: DoubleSha256Digest = DoubleSha256Digest(asm(2).bytes.splitAt(4)._2) @@ -1572,8 +1674,8 @@ sealed trait WitnessCommitment extends RawScriptPubKey { object WitnessCommitment extends ScriptFactory[WitnessCommitment] { private case class WitnessCommitmentImpl( - override val asm: Vector[ScriptToken]) - extends WitnessCommitment { + override val asm: Vector[ScriptToken] + ) extends WitnessCommitment { override val scriptType: ScriptType = ScriptType.WITNESS_COMMITMENT override def toString = s"WitnessCommitment(${witnessRootHash.hex})" @@ -1588,19 +1690,25 @@ object WitnessCommitment extends ScriptFactory[WitnessCommitment] { def apply(asm: Seq[ScriptToken]): WitnessCommitment = fromAsm(asm) override def fromAsm(asm: Seq[ScriptToken]): WitnessCommitment = { - buildScript(asm.toVector, - WitnessCommitmentImpl.apply, - "Given asm was not a valid witness commitment, got: " + asm) + buildScript( + asm.toVector, + WitnessCommitmentImpl.apply, + "Given asm was not a valid witness commitment, got: " + asm + ) } def apply(hash: DoubleSha256Digest): WitnessCommitment = { WitnessCommitment( - Seq(OP_RETURN, - BytesToPushOntoStack(36), - ScriptConstant(commitmentHeader + hash.hex))) + Seq( + OP_RETURN, + BytesToPushOntoStack(36), + ScriptConstant(commitmentHeader + hash.hex) + ) + ) } - /** This determines if the given asm has the correct witness structure according to + /** This determines if the given asm has the correct witness structure + * according to * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#commitment-structure BIP141]] */ override def isValidAsm(asm: Seq[ScriptToken]): Boolean = { @@ -1611,7 +1719,8 @@ object WitnessCommitment extends ScriptFactory[WitnessCommitment] { val Seq(opReturn, pushOp, constant) = asm.take(3) opReturn == OP_RETURN && pushOp == BytesToPushOntoStack(36) && constant.hex.take( - 8) == commitmentHeader && asmBytes.size >= minCommitmentSize + 8 + ) == commitmentHeader && asmBytes.size >= minCommitmentSize } } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala index f429c1fe3b..ec9b2c76b3 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptSignature.scala @@ -11,21 +11,20 @@ import scala.util.Try /** Created by chris on 12/26/15. * - * We only give standard types to ScriptSignatures that are Policy - * compliant. This is because if we wanted to be closer to Consensus - * compliant then it would be near impossible to type things. + * We only give standard types to ScriptSignatures that are Policy compliant. + * This is because if we wanted to be closer to Consensus compliant then it + * would be near impossible to type things. * - * For example almost anything could be a ConditionalScriptSignature - * since in consensus logic almost any ScriptToken is interpreted as True, - * while under Policy only OP_TRUE is True. + * For example almost anything could be a ConditionalScriptSignature since in + * consensus logic almost any ScriptToken is interpreted as True, while under + * Policy only OP_TRUE is True. */ sealed abstract class ScriptSignature extends Script { - /** The digital signatures contained inside of the script signature - * p2pkh script signatures only have one sig - * p2pk script signatures only have one sigs - * p2sh script signatures can have m sigs - * multisignature scripts can have m sigs + /** The digital signatures contained inside of the script signature p2pkh + * script signatures only have one sig p2pk script signatures only have one + * sigs p2sh script signatures can have m sigs multisignature scripts can + * have m sigs */ def signatures: Seq[ECDigitalSignature] @@ -40,13 +39,15 @@ object NonStandardScriptSignature extends ScriptFactory[NonStandardScriptSignature] { private case class NonStandardScriptSignatureImpl( - override val asm: Vector[ScriptToken]) - extends NonStandardScriptSignature + override val asm: Vector[ScriptToken] + ) extends NonStandardScriptSignature def fromAsm(asm: Seq[ScriptToken]): NonStandardScriptSignature = { - buildScript(asm = asm.toVector, - constructor = NonStandardScriptSignatureImpl(_), - errorMsg = "") + buildScript( + asm = asm.toVector, + constructor = NonStandardScriptSignatureImpl(_), + errorMsg = "" + ) } override def isValidAsm(asm: Seq[ScriptToken]): Boolean = { @@ -54,8 +55,8 @@ object NonStandardScriptSignature } } -/** A script signature to be used in tests for signing EmptyScriptPubKey. - * This script pushes a true onto the stack, causing a successful spend. +/** A script signature to be used in tests for signing EmptyScriptPubKey. This + * script pushes a true onto the stack, causing a successful spend. */ case object TrivialTrueScriptSignature extends ScriptSignature { override lazy val signatures: Seq[ECDigitalSignature] = Nil @@ -69,9 +70,8 @@ case object TrivialTrueScriptSignature extends ScriptSignature { } /** P2PKH script signatures have only one public key - * https://bitcoin.org/en/developer-guide#pay-to-public-key-hash-p2pkh - * P2PKH scriptSigs follow this format - * + * https://bitcoin.org/en/developer-guide#pay-to-public-key-hash-p2pkh P2PKH + * scriptSigs follow this format */ sealed trait P2PKHScriptSignature extends ScriptSignature { @@ -92,8 +92,8 @@ sealed trait P2PKHScriptSignature extends ScriptSignature { object P2PKHScriptSignature extends ScriptFactory[P2PKHScriptSignature] { private case class P2PKHScriptSignatureImpl( - override val asm: Vector[ScriptToken]) - extends P2PKHScriptSignature + override val asm: Vector[ScriptToken] + ) extends P2PKHScriptSignature def fromAsm(asm: Seq[ScriptToken]): P2PKHScriptSignature = { buildScript( @@ -103,10 +103,13 @@ object P2PKHScriptSignature extends ScriptFactory[P2PKHScriptSignature] { ) } - /** Builds a P2PKH ScriptSig from a signature and raw ECPublicKeyBytes (may be invalid). */ + /** Builds a P2PKH ScriptSig from a signature and raw ECPublicKeyBytes (may be + * invalid). + */ private[core] def apply( signature: ECDigitalSignature, - pubKeyBytes: ECPublicKeyBytes): P2PKHScriptSignature = { + pubKeyBytes: ECPublicKeyBytes + ): P2PKHScriptSignature = { val signatureBytesToPushOntoStack = BitcoinScriptUtil.calculatePushOp(signature.bytes) val pubKeyBytesToPushOntoStack = @@ -117,22 +120,25 @@ object P2PKHScriptSignature extends ScriptFactory[P2PKHScriptSignature] { fromAsm(asm) } - /** Builds a script signature from a digital signature and a public key - * this is a pay to public key hash script sig + /** Builds a script signature from a digital signature and a public key this + * is a pay to public key hash script sig */ def apply( signature: ECDigitalSignature, - pubKey: ECPublicKey): P2PKHScriptSignature = { + pubKey: ECPublicKey + ): P2PKHScriptSignature = { P2PKHScriptSignature(signature, pubKey.toPublicKeyBytes()) } /** Determines if the given asm matches a [[P2PKHScriptSignature]] */ override def isValidAsm(asm: Seq[ScriptToken]): Boolean = asm match { - case Seq(_: BytesToPushOntoStack, - maybeSig: ScriptConstant, - _: BytesToPushOntoStack, - maybeKey: ScriptConstant) => + case Seq( + _: BytesToPushOntoStack, + maybeSig: ScriptConstant, + _: BytesToPushOntoStack, + maybeKey: ScriptConstant + ) => if ( (maybeKey.bytes.length == 33 || maybeKey.bytes.length == 65) && (maybeSig.bytes.length > 68 && maybeSig.bytes.length < 73) @@ -143,13 +149,14 @@ object P2PKHScriptSignature extends ScriptFactory[P2PKHScriptSignature] { } /** Represents a pay-to-script-hash script signature - * https://bitcoin.org/en/developer-guide#pay-to-script-hash-p2sh - * P2SH scriptSigs have the following format - * [sig] [sig...] + * https://bitcoin.org/en/developer-guide#pay-to-script-hash-p2sh P2SH + * scriptSigs have the following format [sig] [sig...] */ sealed trait P2SHScriptSignature extends ScriptSignature { - /** The redeemScript represents the conditions that must be satisfied to spend the output */ + /** The redeemScript represents the conditions that must be satisfied to spend + * the output + */ def redeemScript: ScriptPubKey = { val scriptSig = scriptSignatureNoRedeemScript if (asm.isEmpty) { @@ -158,9 +165,9 @@ sealed trait P2SHScriptSignature extends ScriptSignature { scriptSig == EmptyScriptSignature && WitnessScriptPubKey.isValidAsm(asm.tail) ) { - //if we have an EmptyScriptSignature, we need to check if the rest of the asm - //is a Witness script. It is not necessarily a witness script, since this code - //path might be used for signing a normal p2sh spk in TransactionSignatureSerializer + // if we have an EmptyScriptSignature, we need to check if the rest of the asm + // is a Witness script. It is not necessarily a witness script, since this code + // path might be used for signing a normal p2sh spk in TransactionSignatureSerializer WitnessScriptPubKey(asm.tail) } else { ScriptPubKey.fromAsmBytes(asm.last.bytes) @@ -168,9 +175,11 @@ sealed trait P2SHScriptSignature extends ScriptSignature { } - /** Returns the script signature of this p2shScriptSig with no serialized redeemScript */ + /** Returns the script signature of this p2shScriptSig with no serialized + * redeemScript + */ def scriptSignatureNoRedeemScript: ScriptSignature = { - //witness scriptPubKeys always have EmptyScriptSigs + // witness scriptPubKeys always have EmptyScriptSigs if (WitnessScriptPubKey.isValidAsm(asm)) { EmptyScriptSignature } else { @@ -212,13 +221,14 @@ sealed trait P2SHScriptSignature extends ScriptSignature { object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] { private case class P2SHScriptSignatureImpl( - override val asm: Vector[ScriptToken]) - extends P2SHScriptSignature + override val asm: Vector[ScriptToken] + ) extends P2SHScriptSignature def apply( scriptSig: ScriptSignature, - redeemScript: ScriptPubKey): P2SHScriptSignature = { - //we need to calculate the size of the redeemScript and add the corresponding push op + redeemScript: ScriptPubKey + ): P2SHScriptSignature = { + // we need to calculate the size of the redeemScript and add the corresponding push op val serializedRedeemScript = ScriptConstant(redeemScript.asmBytes) val pushOps = BitcoinScriptUtil.calculatePushOp(serializedRedeemScript) val asm: Seq[ScriptToken] = @@ -233,30 +243,32 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] { override def buildScript( asm: Vector[ScriptToken], constructor: Vector[ScriptToken] => P2SHScriptSignature, - errorMsg: String): P2SHScriptSignature = { - //everything can be a P2SHScriptSignature, thus passing the trivially true function - //the most important thing to note is we cannot have a P2SHScriptSignature unless - //we have a P2SHScriptPubKey - //previously P2SHScriptSignature's redeem script had to be standard scriptPubKey's, this - //was removed in 0.11 or 0.12 of Bitcoin Core + errorMsg: String + ): P2SHScriptSignature = { + // everything can be a P2SHScriptSignature, thus passing the trivially true function + // the most important thing to note is we cannot have a P2SHScriptSignature unless + // we have a P2SHScriptPubKey + // previously P2SHScriptSignature's redeem script had to be standard scriptPubKey's, this + // was removed in 0.11 or 0.12 of Bitcoin Core constructor(asm) } override def fromAsm(asm: Seq[ScriptToken]): P2SHScriptSignature = { - buildScript(asm = asm.toVector, - constructor = P2SHScriptSignatureImpl(_), - errorMsg = - s"Given asm tokens are not a p2sh scriptSig, got: $asm") + buildScript( + asm = asm.toVector, + constructor = P2SHScriptSignatureImpl(_), + errorMsg = s"Given asm tokens are not a p2sh scriptSig, got: $asm" + ) } /** Tests if the given asm tokens are a [[P2SHScriptSignature]] */ override def isValidAsm(asm: Seq[ScriptToken]): Boolean = { - //as noted above, technically _anything_ can be a p2sh scriptsig - //this applies basic checks to see if it's a standard redeemScript - //rather than a non standard redeeScript. + // as noted above, technically _anything_ can be a p2sh scriptsig + // this applies basic checks to see if it's a standard redeemScript + // rather than a non standard redeeScript. - //this will return false if the redeemScript is not a - //supported scriptpubkey type in our library + // this will return false if the redeemScript is not a + // supported scriptpubkey type in our library asm.size > 1 && isRedeemScript(asm.last) } @@ -264,8 +276,8 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] { def isRedeemScript(token: ScriptToken): Boolean = { token match { case _: ScriptNumberOperation | _: ScriptOperation => - //more cheap checks, we can't have a redeemScript - //if the token is OP_0/OP_1/OP_CHECKSIG etc + // more cheap checks, we can't have a redeemScript + // if the token is OP_0/OP_1/OP_CHECKSIG etc false case constant: ScriptConstant => val redeemScript: ScriptPubKey = parseRedeemScript(constant) @@ -276,7 +288,8 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] { @tailrec private def isStandardNonP2SH( spk: ScriptPubKey, - isRecursiveCall: Boolean): Boolean = { + isRecursiveCall: Boolean + ): Boolean = { spk match { case _: P2PKHScriptPubKey | _: MultiSignatureScriptPubKey | _: P2PKScriptPubKey | _: P2PKWithTimeoutScriptPubKey | @@ -306,9 +319,8 @@ object P2SHScriptSignature extends ScriptFactory[P2SHScriptSignature] { } /** Represents a multisignature script signature - * https://bitcoin.org/en/developer-guide#multisig - * Multisig script sigs have the following format - * OP_0 [B sig] [C sig...] + * https://bitcoin.org/en/developer-guide#multisig Multisig script sigs have + * the following format OP_0 [B sig] [C sig...] */ sealed trait MultiSignatureScriptSignature extends ScriptSignature { @@ -327,18 +339,19 @@ object MultiSignatureScriptSignature extends ScriptFactory[MultiSignatureScriptSignature] { private case class MultiSignatureScriptSignatureImpl( - override val asm: Vector[ScriptToken]) - extends MultiSignatureScriptSignature + override val asm: Vector[ScriptToken] + ) extends MultiSignatureScriptSignature def apply( - signatures: Seq[ECDigitalSignature]): MultiSignatureScriptSignature = { + signatures: Seq[ECDigitalSignature] + ): MultiSignatureScriptSignature = { val sigsPushOpsPairs: Seq[Seq[ScriptToken]] = for { sig <- signatures constant = ScriptConstant(sig.bytes) pushOps = BitcoinScriptUtil.calculatePushOp(sig.bytes) } yield pushOps ++ Seq(constant) val sigsWithPushOps = sigsPushOpsPairs.flatten - //OP_0 is for the dummy input required by OP_CHECKMULTISIG + // OP_0 is for the dummy input required by OP_CHECKMULTISIG val asm = OP_0 +: sigsWithPushOps MultiSignatureScriptSignature.fromAsm(asm) } @@ -352,30 +365,33 @@ object MultiSignatureScriptSignature ) } - /** Checks if the given script tokens are a multisignature script sig - * format: OP_0 [B sig] [C sig...] + /** Checks if the given script tokens are a multisignature script sig format: + * OP_0 [B sig] [C sig...] * - * @param asm the asm to check if it falls in the multisignature script sig format - * @return boolean indicating if the scriptsignature is a multisignature script signature + * @param asm + * the asm to check if it falls in the multisignature script sig format + * @return + * boolean indicating if the scriptsignature is a multisignature script + * signature */ override def isValidAsm(asm: Seq[ScriptToken]): Boolean = asm.isEmpty match { case true => false - //case false if (asm.size == 1) => false + // case false if (asm.size == 1) => false case false => val firstTokenIsScriptNumberOperation = asm.head.isInstanceOf[ScriptNumberOperation] if (firstTokenIsScriptNumberOperation) { - //avoid doing this computation unless we think it need to be done - //fail fast + // avoid doing this computation unless we think it need to be done + // fail fast isPushOpsOrScriptConstants(asm.tail) } else { false } } - /** Iterates through the given given script tokens and return false if - * one of the elements is NOT [[ScriptConstant]] or a push operation + /** Iterates through the given given script tokens and return false if one of + * the elements is NOT [[ScriptConstant]] or a push operation */ private def isPushOpsOrScriptConstants(asm: Seq[ScriptToken]): Boolean = { asm.forall(token => @@ -385,8 +401,7 @@ object MultiSignatureScriptSignature } /** Represents a pay to public key script signature - * https://bitcoin.org/en/developer-guide#pubkey - * Signature script: + * https://bitcoin.org/en/developer-guide#pubkey Signature script: */ sealed trait P2PKScriptSignature extends ScriptSignature { @@ -404,8 +419,8 @@ sealed trait P2PKScriptSignature extends ScriptSignature { object P2PKScriptSignature extends ScriptFactory[P2PKScriptSignature] { private case class P2PKScriptSignatureImpl( - override val asm: Vector[ScriptToken]) - extends P2PKScriptSignature + override val asm: Vector[ScriptToken] + ) extends P2PKScriptSignature def apply(signature: ECDigitalSignature): P2PKScriptSignature = { val pushOps = BitcoinScriptUtil.calculatePushOp(signature.bytes) @@ -415,9 +430,11 @@ object P2PKScriptSignature extends ScriptFactory[P2PKScriptSignature] { } def fromAsm(asm: Seq[ScriptToken]): P2PKScriptSignature = { - buildScript(asm.toVector, - P2PKScriptSignatureImpl(_), - "The given asm tokens were not a p2pk script sig: " + asm) + buildScript( + asm.toVector, + P2PKScriptSignatureImpl(_), + "The given asm tokens were not a p2pk script sig: " + asm + ) } /** P2PK scriptSigs always have the pattern [pushop, digitalSignature] */ @@ -441,18 +458,22 @@ object P2PKWithTimeoutScriptSignature def apply( beforeTimeout: Boolean, - signature: ECDigitalSignature): ConditionalScriptSignature = { + signature: ECDigitalSignature + ): ConditionalScriptSignature = { ConditionalScriptSignature(P2PKScriptSignature(signature), beforeTimeout) } override def isValidAsm(asm: Seq[ScriptToken]): Boolean = { P2PKScriptSignature.isValidAsm( - asm.dropRight(1)) && ConditionalScriptSignature + asm.dropRight(1) + ) && ConditionalScriptSignature .isValidAsm(asm) } } -/** Parent type for all lock time script signatures, these spend [[LockTimeScriptPubKey]] */ +/** Parent type for all lock time script signatures, these spend + * [[LockTimeScriptPubKey]] + */ sealed trait LockTimeScriptSignature extends ScriptSignature { def scriptSig: ScriptSignature = ScriptSignature(hex) @@ -470,13 +491,15 @@ sealed trait CLTVScriptSignature extends LockTimeScriptSignature { object CLTVScriptSignature extends ScriptFactory[CLTVScriptSignature] { private case class CLTVScriptSignatureImpl( - override val asm: Vector[ScriptToken]) - extends CLTVScriptSignature + override val asm: Vector[ScriptToken] + ) extends CLTVScriptSignature override def fromAsm(asm: Seq[ScriptToken]): CLTVScriptSignature = { - buildScript(asm = asm.toVector, - constructor = CLTVScriptSignatureImpl(_), - errorMsg = s"Given asm was not a CLTVScriptSignature $asm") + buildScript( + asm = asm.toVector, + constructor = CLTVScriptSignatureImpl(_), + errorMsg = s"Given asm was not a CLTVScriptSignature $asm" + ) } override def fromHex(hex: String): CLTVScriptSignature = { @@ -499,13 +522,15 @@ sealed trait CSVScriptSignature extends LockTimeScriptSignature { object CSVScriptSignature extends ScriptFactory[CSVScriptSignature] { private case class CSVScriptSignatureImpl( - override val asm: Vector[ScriptToken]) - extends CSVScriptSignature + override val asm: Vector[ScriptToken] + ) extends CSVScriptSignature override def fromAsm(asm: Seq[ScriptToken]): CSVScriptSignature = { - buildScript(asm = asm.toVector, - constructor = CSVScriptSignatureImpl(_), - errorMsg = s"Given asm was not a CLTVScriptSignature $asm") + buildScript( + asm = asm.toVector, + constructor = CSVScriptSignatureImpl(_), + errorMsg = s"Given asm was not a CLTVScriptSignature $asm" + ) } override def fromHex(hex: String): CSVScriptSignature = { @@ -521,8 +546,10 @@ object CSVScriptSignature extends ScriptFactory[CSVScriptSignature] { /** ScriptSignature for both OP_IF and OP_NOTIF ScriptPubKeys */ sealed trait ConditionalScriptSignature extends ScriptSignature { - require(ConditionalScriptSignature.isValidAsm(asm), - "ConditionalScriptSignature must end in true or false") + require( + ConditionalScriptSignature.isValidAsm(asm), + "ConditionalScriptSignature must end in true or false" + ) def isTrue: Boolean = { BitcoinScriptUtil.castToBool(asm.last) @@ -546,22 +573,25 @@ object ConditionalScriptSignature extends ScriptFactory[ConditionalScriptSignature] { private case class ConditionalScriptSignatureImpl( - override val asm: Vector[ScriptToken]) - extends ConditionalScriptSignature { + override val asm: Vector[ScriptToken] + ) extends ConditionalScriptSignature { override def toString: String = s"ConditionalScriptSignature($isTrue, $nestedScriptSig)" } override def fromAsm(asm: Seq[ScriptToken]): ConditionalScriptSignature = { - buildScript(asm.toVector, - ConditionalScriptSignatureImpl.apply, - s"Given asm was not a ConditionalScriptSignature: $asm") + buildScript( + asm.toVector, + ConditionalScriptSignatureImpl.apply, + s"Given asm was not a ConditionalScriptSignature: $asm" + ) } def apply( nestedScriptSig: ScriptSignature, - condition: Boolean): ConditionalScriptSignature = { + condition: Boolean + ): ConditionalScriptSignature = { val conditionAsm = if (condition) { OP_TRUE } else { @@ -574,7 +604,8 @@ object ConditionalScriptSignature @scala.annotation.tailrec def fromNestedScriptSig( nestedScriptSig: ScriptSignature, - conditionalPath: ConditionalPath): ConditionalScriptSignature = { + conditionalPath: ConditionalPath + ): ConditionalScriptSignature = { conditionalPath match { case ConditionalPath.NoCondition => throw new IllegalArgumentException("ConditionalPath cannot be empty") @@ -585,11 +616,13 @@ object ConditionalScriptSignature case ConditionalPath.ConditionTrue(nextCondition) => ConditionalScriptSignature.fromNestedScriptSig( ConditionalScriptSignature(nestedScriptSig, condition = true), - nextCondition) + nextCondition + ) case ConditionalPath.ConditionFalse(nextCondition) => ConditionalScriptSignature.fromNestedScriptSig( ConditionalScriptSignature(nestedScriptSig, condition = false), - nextCondition) + nextCondition + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala index 2309078e3d..dc22025fa9 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/ScriptWitness.scala @@ -10,13 +10,15 @@ import org.bitcoins.core.util.{BitcoinScriptUtil, BytesUtil} import org.bitcoins.crypto._ import scodec.bits.ByteVector -/** Created by chris on 11/10/16. - * The witness used to evaluate a [[RawScriptPubKey]] inside of Bitcoin +/** Created by chris on 11/10/16. The witness used to evaluate a + * [[RawScriptPubKey]] inside of Bitcoin * [[https://github.com/bitcoin/bitcoin/blob/57b34599b2deb179ff1bd97ffeab91ec9f904d85/src/script/script.h#L648-L660]] */ sealed abstract class ScriptWitness extends NetworkElement { - /** The byte vectors that are placed on to the stack when evaluating a witness program */ + /** The byte vectors that are placed on to the stack when evaluating a witness + * program + */ val stack: Seq[ByteVector] // When comparing two witnesses we should compare the @@ -39,8 +41,8 @@ sealed abstract class ScriptWitnessV0 extends ScriptWitness { override val bytes: ByteVector = RawScriptWitnessParser.write(this) } -/** Represents a [[org.bitcoins.core.protocol.script.ScriptWitness]] that is needed to spend a - * [[P2WPKHWitnessV0]] scriptPubKey +/** Represents a [[org.bitcoins.core.protocol.script.ScriptWitness]] that is + * needed to spend a [[P2WPKHWitnessV0]] scriptPubKey * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh-nested-in-bip16-p2sh]] * Format: */ @@ -66,7 +68,8 @@ object P2WPKHWitnessV0 { P2WPKHWitnessV0Impl(stack) private[bitcoins] def apply( - pubKeyBytes: ECPublicKeyBytes): P2WPKHWitnessV0 = { + pubKeyBytes: ECPublicKeyBytes + ): P2WPKHWitnessV0 = { P2WPKHWitnessV0(pubKeyBytes, EmptyDigitalSignature) } @@ -76,13 +79,15 @@ object P2WPKHWitnessV0 { private[bitcoins] def apply( publicKeyBytes: ECPublicKeyBytes, - signature: ECDigitalSignature): P2WPKHWitnessV0 = { + signature: ECDigitalSignature + ): P2WPKHWitnessV0 = { P2WPKHWitnessV0(Seq(publicKeyBytes.bytes, signature.bytes)) } def apply( publicKey: ECPublicKey, - signature: ECDigitalSignature): P2WPKHWitnessV0 = { + signature: ECDigitalSignature + ): P2WPKHWitnessV0 = { P2WPKHWitnessV0(publicKey.toPublicKeyBytes(), signature) } @@ -95,14 +100,16 @@ object P2WPKHWitnessV0 { _: P2PKScriptSignature | _: P2SHScriptSignature | TrivialTrueScriptSignature | EmptyScriptSignature) => throw new IllegalArgumentException( - s"Expected P2PKHScriptSignature, got $x") + s"Expected P2PKHScriptSignature, got $x" + ) } } -/** Represents a [[ScriptWitness]] that is needed to spend a - * [[P2WSHWitnessV0]] scriptPubKey +/** Represents a [[ScriptWitness]] that is needed to spend a [[P2WSHWitnessV0]] + * scriptPubKey * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh]] - * Format: ... + * Format: ... */ sealed abstract class P2WSHWitnessV0 extends ScriptWitnessV0 { @@ -151,9 +158,10 @@ object P2WSHWitnessV0 { def apply( spk: RawScriptPubKey, - scriptSig: ScriptSignature): P2WSHWitnessV0 = { - //need to remove the OP_0 or OP_1 and replace it with ScriptNumber.zero / ScriptNumber.one since witnesses are *not* run through the interpreter - //remove pushops from scriptSig + scriptSig: ScriptSignature + ): P2WSHWitnessV0 = { + // need to remove the OP_0 or OP_1 and replace it with ScriptNumber.zero / ScriptNumber.one since witnesses are *not* run through the interpreter + // remove pushops from scriptSig val minimalIf = BitcoinScriptUtil.minimalIfOp(scriptSig.asm) val noPushOps = BitcoinScriptUtil.filterPushOps(minimalIf) val minimalDummy = BitcoinScriptUtil.minimalDummy(noPushOps).reverse @@ -180,8 +188,8 @@ object ScriptWitness extends Factory[ScriptWitness] { } def apply(stack: Seq[ByteVector]): ScriptWitness = { - //TODO: eventually only compressed public keys will be allowed in v0 scripts - //https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#restrictions-on-public-key-type + // TODO: eventually only compressed public keys will be allowed in v0 scripts + // https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#restrictions-on-public-key-type val isPubKey = { stack.nonEmpty && (stack.head.size == 33 && (stack.head.head == 0x02 || stack.head.head == 0x03) || (stack.head.size == 65 && stack.head.head == 0x04 && CryptoUtil @@ -191,7 +199,7 @@ object ScriptWitness extends Factory[ScriptWitness] { if (stack.isEmpty) { EmptyScriptWitness } else if (TaprootKeyPath.isValid(stack.toVector)) { - //taproot key path spend + // taproot key path spend TaprootKeyPath.fromStack(stack.toVector) } else if (isPubKey && stack.size == 1) { val pubKey = ECPublicKeyBytes(stack.head) @@ -203,7 +211,7 @@ object ScriptWitness extends Factory[ScriptWitness] { val sig = ECDigitalSignature(stack(1)) P2WPKHWitnessV0(pubKey, sig) } else { - //wont match a Vector if I don't convert to list + // wont match a Vector if I don't convert to list val s = stack.toList s match { case Nil => @@ -222,9 +230,10 @@ sealed trait TaprootWitness extends ScriptWitness { def annexOpt: Option[ByteVector] - /** As per bip341 - * the SHA256 of (compact_size(size of annex) || annex), where annex includes the mandatory 0x50 prefix. - * @see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#signature-validation-rules + /** As per bip341 the SHA256 of (compact_size(size of annex) || annex), where + * annex includes the mandatory 0x50 prefix. + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#signature-validation-rules */ def annexHashOpt: Option[Sha256Digest] = { annexOpt.map { annex => @@ -260,8 +269,8 @@ object TaprootWitness extends Factory[TaprootWitness] { case class TaprootKeyPath private ( signature: SchnorrDigitalSignature, hashTypeOpt: Option[HashType], - annexOpt: Option[ByteVector]) - extends TaprootWitness { + annexOpt: Option[ByteVector] +) extends TaprootWitness { val hashType: HashType = hashTypeOpt.getOrElse(HashType.sigHashDefault) @@ -293,7 +302,8 @@ object TaprootKeyPath extends Factory[TaprootKeyPath] { def apply( signature: SchnorrDigitalSignature, hashType: HashType, - annexOpt: Option[ByteVector]): TaprootKeyPath = { + annexOpt: Option[ByteVector] + ): TaprootKeyPath = { if (hashType == HashType.sigHashDefault) { new TaprootKeyPath(signature, None, annexOpt) } else { @@ -304,7 +314,8 @@ object TaprootKeyPath extends Factory[TaprootKeyPath] { def apply( signature: SchnorrDigitalSignature, hashTypeOpt: Option[HashType], - annexOpt: Option[ByteVector]): TaprootKeyPath = { + annexOpt: Option[ByteVector] + ): TaprootKeyPath = { if (hashTypeOpt.contains(HashType.sigHashDefault)) { new TaprootKeyPath(signature, None, annexOpt) } else { @@ -314,7 +325,8 @@ object TaprootKeyPath extends Factory[TaprootKeyPath] { def apply( signature: SchnorrDigitalSignature, - annexOpt: Option[ByteVector]): TaprootKeyPath = { + annexOpt: Option[ByteVector] + ): TaprootKeyPath = { TaprootKeyPath(signature, None, annexOpt) } @@ -326,7 +338,8 @@ object TaprootKeyPath extends Factory[TaprootKeyPath] { val hasAnnex = TaprootScriptPath.hasAnnex(vec) require( vec.length == 1 || (hasAnnex && vec.length == 2), - s"Taproot keypath can only have at most 2 stack elements, got=${vec.length}") + s"Taproot keypath can only have at most 2 stack elements, got=${vec.length}" + ) val annexOpt = { if (hasAnnex) { @@ -344,8 +357,8 @@ object TaprootKeyPath extends Factory[TaprootKeyPath] { } val keyPath = if (sigBytes.length == 64) { - //means SIGHASH_DEFAULT is implicitly encoded - //see: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#Common_signature_message + // means SIGHASH_DEFAULT is implicitly encoded + // see: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#Common_signature_message val sig = SchnorrDigitalSignature.fromBytes(sigBytes) new TaprootKeyPath(sig, None, annexOpt) } else if (sigBytes.length == 65) { @@ -354,7 +367,8 @@ object TaprootKeyPath extends Factory[TaprootKeyPath] { new TaprootKeyPath(sig, Some(hashType), annexOpt) } else { sys.error( - s"Unknown sig bytes length, should be 64 or 65, got=${sigBytes.length}") + s"Unknown sig bytes length, should be 64 or 65, got=${sigBytes.length}" + ) } keyPath @@ -374,26 +388,29 @@ object TaprootKeyPath extends Factory[TaprootKeyPath] { /** Spending a taproot output via the script path */ case class TaprootScriptPath(stack: Vector[ByteVector]) extends TaprootWitness { - require(TaprootScriptPath.isValid(stack), - s"Invalid witness stack for TaprootScriptPath, got=$stack") + require( + TaprootScriptPath.isValid(stack), + s"Invalid witness stack for TaprootScriptPath, got=$stack" + ) val controlBlock: TapscriptControlBlock = { if (TaprootScriptPath.hasAnnex(stack)) { - //If there are at least two witness elements, and the first byte of the last element is 0x50[4], + // If there are at least two witness elements, and the first byte of the last element is 0x50[4], // this last element is called annex a[5] and is removed from the witness stack. // The annex (or the lack of thereof) is always covered by the signature and contributes to transaction weight, // but is otherwise ignored during taproot validation. - //see: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#script-validation-rules + // see: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#script-validation-rules TapscriptControlBlock.fromBytes(stack(1)) } else { TapscriptControlBlock.fromBytes(stack.head) } } - /** If there are at least two witness elements, and the first byte of the last element is 0x50[4], - * this last element is called annex a[5] and is removed from the witness stack. - * The annex (or the lack of thereof) is always covered by the signature and contributes to transaction weight, - * but is otherwise ignored during taproot validation. + /** If there are at least two witness elements, and the first byte of the last + * element is 0x50[4], this last element is called annex a[5] and is removed + * from the witness stack. The annex (or the lack of thereof) is always + * covered by the signature and contributes to transaction weight, but is + * otherwise ignored during taproot validation. */ override def annexOpt: Option[ByteVector] = { if (TaprootScriptPath.hasAnnex(stack)) { @@ -415,7 +432,8 @@ case class TaprootScriptPath(stack: Vector[ByteVector]) extends TaprootWitness { } } - /** Let p = c[1:33] and let P = lift_x(int(p)) where lift_x and [:] are defined as in BIP340. Fail if this point is not on the curve. + /** Let p = c[1:33] and let P = lift_x(int(p)) where lift_x and [:] are + * defined as in BIP340. Fail if this point is not on the curve. */ def p: XOnlyPubKey = controlBlock.p } @@ -440,7 +458,7 @@ object TaprootScriptPath extends Factory[TaprootScriptPath] { override def fromBytes(bytes: ByteVector): TaprootScriptPath = { RawScriptWitnessParser.read(bytes) match { case t: TaprootScriptPath => t - case x => sys.error(s"Could not parse taproot scriptpath, got=$x") + case x => sys.error(s"Could not parse taproot scriptpath, got=$x") } } @@ -449,11 +467,11 @@ object TaprootScriptPath extends Factory[TaprootScriptPath] { if (stack.length >= 2) { val controlBlock = { if (TaprootScriptPath.hasAnnex(stack)) { - //If there are at least two witness elements, and the first byte of the last element is 0x50[4], + // If there are at least two witness elements, and the first byte of the last element is 0x50[4], // this last element is called annex a[5] and is removed from the witness stack. // The annex (or the lack of thereof) is always covered by the signature and contributes to transaction weight, // but is otherwise ignored during taproot validation. - //see: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#script-validation-rules + // see: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#script-validation-rules stack(1) } else { stack.head @@ -471,7 +489,8 @@ object TaprootScriptPath extends Factory[TaprootScriptPath] { def apply( controlBlock: TapscriptControlBlock, annexOpt: Option[ByteVector], - spk: RawScriptPubKey): TaprootScriptPath = { + spk: RawScriptPubKey + ): TaprootScriptPath = { annexOpt match { case Some(annex) => fromStack(Vector(annex, controlBlock.bytes, spk.asmBytes)) @@ -483,20 +502,24 @@ object TaprootScriptPath extends Factory[TaprootScriptPath] { def verifyTaprootCommitment( controlBlock: ControlBlock, program: TaprootScriptPubKey, - tapLeafHash: Sha256Digest): Boolean = { + tapLeafHash: Sha256Digest + ): Boolean = { val internalPubKey = controlBlock.p val merkleRoot = computeTaprootMerkleRoot(controlBlock, tapLeafHash) val parity = (controlBlock.bytes.head & 1) == 1 - program.pubKey.checkTapTweak(internal = internalPubKey, - merkleRootOpt = Some(merkleRoot), - parity = parity) + program.pubKey.checkTapTweak( + internal = internalPubKey, + merkleRootOpt = Some(merkleRoot), + parity = parity + ) } /** Computes the hash of the script that is a leaf in the tapscript tree * @param leafVersion * @param spk - * @see https://github.com/bitcoin/bitcoin/blob/37633d2f61697fc719390767aae740ece978b074/src/script/interpreter.cpp#L1828 + * @see + * https://github.com/bitcoin/bitcoin/blob/37633d2f61697fc719390767aae740ece978b074/src/script/interpreter.cpp#L1828 * @return */ def computeTapleafHash(leaf: TapLeaf): Sha256Digest = { @@ -508,12 +531,14 @@ object TaprootScriptPath extends Factory[TaprootScriptPath] { /** Computes the merkle root of a tapscript tree * @param controlBlock * @param tapLeafHash - * @see https://github.com/bitcoin/bitcoin/blob/37633d2f61697fc719390767aae740ece978b074/src/script/interpreter.cpp#L1833 + * @see + * https://github.com/bitcoin/bitcoin/blob/37633d2f61697fc719390767aae740ece978b074/src/script/interpreter.cpp#L1833 * @return */ def computeTaprootMerkleRoot( controlBlock: ControlBlock, - tapLeafHash: Sha256Digest): Sha256Digest = { + tapLeafHash: Sha256Digest + ): Sha256Digest = { val pathLen = (controlBlock.bytes.size - TaprootScriptPath.TAPROOT_CONTROL_BASE_SIZE) / TaprootScriptPath.TAPROOT_CONTROL_NODE_SIZE var k = tapLeafHash @@ -567,11 +592,11 @@ case class TaprootUnknownPath(stack: Vector[ByteVector]) val controlBlock: UnknownControlBlock = { if (TaprootScriptPath.hasAnnex(stack)) { - //If there are at least two witness elements, and the first byte of the last element is 0x50[4], + // If there are at least two witness elements, and the first byte of the last element is 0x50[4], // this last element is called annex a[5] and is removed from the witness stack. // The annex (or the lack of thereof) is always covered by the signature and contributes to transaction weight, // but is otherwise ignored during taproot validation. - //see: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#script-validation-rules + // see: https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#script-validation-rules UnknownControlBlock.fromBytes(stack(1)) } else { UnknownControlBlock.fromBytes(stack.head) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/SignatureVersion.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/SignatureVersion.scala index 083e17ddc1..1cd09b76fb 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/SignatureVersion.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/SignatureVersion.scala @@ -1,7 +1,8 @@ package org.bitcoins.core.protocol.script -/** Represents the transaction digest algorithm for signature verification in Bitcoin Core - * With the implementation of segwit, we have added different algorithm, the first alternative being BIP143 +/** Represents the transaction digest algorithm for signature verification in + * Bitcoin Core With the implementation of segwit, we have added different + * algorithm, the first alternative being BIP143 * [[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki]] * [[https://github.com/bitcoin/bitcoin/blob/53133c1c041d113c2a480a18e6ff38681d135dca/src/script/interpreter.h#L120-L124]] */ @@ -10,17 +11,21 @@ sealed trait SignatureVersion /** The original digest algorithm created by Satoshi */ case object SigVersionBase extends SignatureVersion -/** The digest algorithm implemented by BIP143 [[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki]] */ +/** The digest algorithm implemented by BIP143 + * [[https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki]] + */ case object SigVersionWitnessV0 extends SignatureVersion sealed trait SigVersionTaproot extends SignatureVersion /** For keypath spends - * @see https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L191 + * @see + * https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L191 */ case object SigVersionTaprootKeySpend extends SigVersionTaproot /** For script path spends - * @see https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L192 + * @see + * https://github.com/bitcoin/bitcoin/blob/e826b22da252e0599c61d21c98ff89f366b3120f/src/script/interpreter.h#L192 */ case object SigVersionTapscript extends SigVersionTaproot diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/TapLeaf.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/TapLeaf.scala index da6efd46a8..2f408722a7 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/TapLeaf.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/TapLeaf.scala @@ -44,10 +44,11 @@ case class TapLeaf(leafVersion: Byte, spk: ScriptPubKey) extends TapscriptTree { object TapLeaf { val leafVersion: Byte = 0xc0.toByte - /** BIP342 specifies validity rules that apply for leaf version 0xc0, - * but future proposals can introduce rules for other leaf versions. + /** BIP342 specifies validity rules that apply for leaf version 0xc0, but + * future proposals can introduce rules for other leaf versions. * - * @see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#rationale + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#rationale */ val knownLeafVersions: Vector[Byte] = Vector(leafVersion, 0xc1.toByte) } @@ -63,7 +64,7 @@ object TapscriptTree { if (x.length == 2) { TapBranch(x(0), x(1)) } else { - x(0) //odd number of leafs + x(0) // odd number of leafs } } loop(branches.toVector) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/WitnessVersion.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/WitnessVersion.scala index 2ee5f3c76b..0f2d428056 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/WitnessVersion.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/WitnessVersion.scala @@ -6,21 +6,26 @@ import org.bitcoins.core.script.result._ import org.bitcoins.core.util.BytesUtil import org.bitcoins.crypto.{CryptoUtil, Sha256Digest, Sha256Hash160Digest} -/** Created by chris on 11/10/16. - * The version of the [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]], - * this indicates how a [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] is rebuilt. +/** Created by chris on 11/10/16. The version of the + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]], + * this indicates how a + * [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] is + * rebuilt. * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program BIP141]] */ sealed trait WitnessVersion { - /** Rebuilds the full script from the given witness and [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] - * Either returns the [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] - * it needs to be executed against or the [[ScriptError]] that was encountered when + /** Rebuilds the full script from the given witness and + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] Either + * returns the + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] it needs + * to be executed against or the [[ScriptError]] that was encountered when * building the rebuild the scriptpubkey from the witness */ def rebuild( scriptWitness: ScriptWitness, - witnessSPK: WitnessScriptPubKey): Either[ScriptError, ScriptPubKey] + witnessSPK: WitnessScriptPubKey + ): Either[ScriptError, ScriptPubKey] def version: ScriptNumberOperation } @@ -30,20 +35,21 @@ case object WitnessVersion0 extends WitnessVersion { /** Rebuilds a witness version 0 SPK program, see BIP141 */ override def rebuild( scriptWitness: ScriptWitness, - witnessSPK: WitnessScriptPubKey): Either[ScriptError, ScriptPubKey] = { + witnessSPK: WitnessScriptPubKey + ): Either[ScriptError, ScriptPubKey] = { val witnessProgram = witnessSPK.witnessProgram val programBytes = BytesUtil.toByteVector(witnessProgram) programBytes.size match { case 20 => - //p2wpkh + // p2wpkh val hash = Sha256Hash160Digest(programBytes) Right(P2PKHScriptPubKey(hash)) case 32 => - //p2wsh + // p2wsh if (scriptWitness.stack.isEmpty) { Left(ScriptErrorWitnessProgramWitnessEmpty) } else { - //need to check if the hashes match + // need to check if the hashes match val stackTop = scriptWitness.stack.head val stackHash = CryptoUtil.sha256(stackTop) val witnessHash = Sha256Digest(witnessProgram.head.bytes) @@ -57,7 +63,7 @@ case object WitnessVersion0 extends WitnessVersion { } } case _ => - //witness version 0 programs need to be 20 bytes or 32 bytes in size + // witness version 0 programs need to be 20 bytes or 32 bytes in size Left(ScriptErrorWitnessProgramWrongLength) } } @@ -69,15 +75,18 @@ case object WitnessVersion1 extends WitnessVersion { override def rebuild( scriptWitness: ScriptWitness, - witnessSPK: WitnessScriptPubKey): Either[ScriptError, ScriptPubKey] = { - require(witnessSPK.isInstanceOf[TaprootScriptPubKey], - s"WitnessScriptPubKey must be a taproot spk, got=${witnessSPK}") + witnessSPK: WitnessScriptPubKey + ): Either[ScriptError, ScriptPubKey] = { + require( + witnessSPK.isInstanceOf[TaprootScriptPubKey], + s"WitnessScriptPubKey must be a taproot spk, got=${witnessSPK}" + ) val taprootSPK = witnessSPK.asInstanceOf[TaprootScriptPubKey] val witnessProgram = taprootSPK.witnessProgram val programBytes = BytesUtil.toByteVector(witnessProgram) programBytes.size match { case 32 => - //p2tr + // p2tr if (scriptWitness.stack.isEmpty) { Left(ScriptErrorWitnessProgramWitnessEmpty) } else { @@ -91,17 +100,18 @@ case object WitnessVersion1 extends WitnessVersion { case w @ (EmptyScriptWitness | _: P2WPKHWitnessV0 | _: P2WSHWitnessV0) => sys.error( - s"Cannot rebuild witnessv1 with a non v1 witness, got=$w") + s"Cannot rebuild witnessv1 with a non v1 witness, got=$w" + ) } rebuiltSPK } case _ => - //witness version 1 programs need to be 32 bytes in size - //this is technically wrong as this is dependent on a policy flag - //this should only error when the DISCOURAGE_UPGRADABLE_WITNESS policy flag is set - //else it should succeed as to maintain future soft fork compatability - //this will get addressed on a future PR as I implement test cases - //in the interpreter + // witness version 1 programs need to be 32 bytes in size + // this is technically wrong as this is dependent on a policy flag + // this should only error when the DISCOURAGE_UPGRADABLE_WITNESS policy flag is set + // else it should succeed as to maintain future soft fork compatability + // this will get addressed on a future PR as I implement test cases + // in the interpreter Left(ScriptErrorDiscourageUpgradeableWitnessProgram) } } @@ -109,7 +119,9 @@ case object WitnessVersion1 extends WitnessVersion { override val version: OP_1.type = OP_1 } -/** The witness version that represents all witnesses that have not been allocated yet */ +/** The witness version that represents all witnesses that have not been + * allocated yet + */ case class UnassignedWitness(version: ScriptNumberOperation) extends WitnessVersion { require( @@ -119,7 +131,8 @@ case class UnassignedWitness(version: ScriptNumberOperation) override def rebuild( scriptWitness: ScriptWitness, - witnessSPK: WitnessScriptPubKey): Either[ScriptError, ScriptPubKey] = { + witnessSPK: WitnessScriptPubKey + ): Either[ScriptError, ScriptPubKey] = { Left(ScriptErrorDiscourageUpgradeableWitnessProgram) } } @@ -135,7 +148,8 @@ object WitnessVersion { UnassignedWitness(x) case OP_1NEGATE => throw new IllegalArgumentException( - "OP_1NEGATE is not a valid witness version") + "OP_1NEGATE is not a valid witness version" + ) } def apply(token: ScriptToken): WitnessVersion = @@ -144,7 +158,8 @@ object WitnessVersion { WitnessVersion(scriptNumberOp) case _: ScriptConstant | _: ScriptNumber | _: ScriptOperation => throw new IllegalArgumentException( - "We can only have witness version that is a script number operation, i.e OP_0 through OP_16") + "We can only have witness version that is a script number operation, i.e OP_0 through OP_16" + ) } def apply(int: Int): Option[WitnessVersion] = diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/Descriptor.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/Descriptor.scala index a55cdd2aa1..27d1c17b39 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/Descriptor.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/Descriptor.scala @@ -9,7 +9,8 @@ import org.bitcoins.crypto.{ECPrivateKey, PublicKey, StringFactory} import scala.util.Try -/** @see [[https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md]] +/** @see + * [[https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md]] */ sealed abstract class Descriptor { @@ -34,15 +35,15 @@ sealed abstract class ScriptDescriptor extends Descriptor { case class RawDescriptor( expression: RawScriptExpression, - checksum: Option[String]) - extends ScriptDescriptor { + checksum: Option[String] +) extends ScriptDescriptor { override val scriptPubKey: RawScriptPubKey = expression.scriptPubKey } case class P2WPKHDescriptor( expression: P2WPKHExpression, - checksum: Option[String]) - extends ScriptDescriptor { + checksum: Option[String] +) extends ScriptDescriptor { override val scriptPubKey: P2WPKHWitnessSPKV0 = expression.scriptPubKey def address(np: NetworkParameters): Bech32Address = { @@ -52,29 +53,29 @@ case class P2WPKHDescriptor( case class P2WSHDescriptor( expression: P2WSHExpression, - checksum: Option[String]) - extends ScriptDescriptor { + checksum: Option[String] +) extends ScriptDescriptor { override val scriptPubKey: P2WSHWitnessSPKV0 = expression.scriptPubKey } case class P2PKDescriptor[T <: PublicKey]( expression: P2PKScriptExpression[T], - checksum: Option[String]) - extends ScriptDescriptor { + checksum: Option[String] +) extends ScriptDescriptor { override val scriptPubKey: P2PKScriptPubKey = expression.scriptPubKey } case class P2PKHDescriptor( expression: P2PKHScriptExpression, - checksum: Option[String]) - extends ScriptDescriptor { + checksum: Option[String] +) extends ScriptDescriptor { override val scriptPubKey: P2PKHScriptPubKey = expression.scriptPubKey } case class MultisigDescriptor( expression: MultisigExpression, - checksum: Option[String]) - extends ScriptDescriptor { + checksum: Option[String] +) extends ScriptDescriptor { override val scriptPubKey: MultiSignatureScriptPubKey = expression.scriptPubKey @@ -82,8 +83,8 @@ case class MultisigDescriptor( case class SortedMultisigDescriptor( expression: SortedMultisigExpression, - checksum: Option[String]) - extends ScriptDescriptor { + checksum: Option[String] +) extends ScriptDescriptor { override val scriptPubKey: MultiSignatureScriptPubKey = expression.scriptPubKey @@ -96,8 +97,8 @@ case class P2SHDescriptor(expression: P2SHExpression, checksum: Option[String]) case class TaprootDescriptor( expression: TreeExpression, - checksum: Option[String]) - extends ScriptDescriptor { + checksum: Option[String] +) extends ScriptDescriptor { override val scriptPubKey: TaprootScriptPubKey = expression.scriptPubKey } @@ -111,16 +112,17 @@ sealed abstract class ComboDescriptor extends ScriptDescriptor { case class ComboDescriptorUncompressed( expression: ComboExpression, - checksum: Option[String]) - extends ComboDescriptor + checksum: Option[String] +) extends ComboDescriptor case class ComboDescriptorCompressed( expression: ComboExpression, - checksum: Option[String]) - extends ComboDescriptor { + checksum: Option[String] +) extends ComboDescriptor { require( expression.source.pubKey.isCompressed, - s"ComboDescriptorCompressed must have compressed pubkey, got=$expression") + s"ComboDescriptorCompressed must have compressed pubkey, got=$expression" + ) val p2wpkh: P2WPKHWitnessSPKV0 = P2WPKHWitnessSPKV0(pubKey = expression.source.pubKey) @@ -130,8 +132,8 @@ case class ComboDescriptorCompressed( sealed abstract class DescriptorFactory[ T <: Descriptor, E <: DescriptorExpression, - U <: DescriptorType] - extends StringFactory[T] { + U <: DescriptorType +] extends StringFactory[T] { def descriptorType: U override def fromString(string: String): T = { @@ -139,17 +141,19 @@ sealed abstract class DescriptorFactory[ val t = iter.takeDescriptorType() if (t != descriptorType) { sys.error( - s"Incorrect type for descriptor, got=$t expected=$descriptorType") + s"Incorrect type for descriptor, got=$t expected=$descriptorType" + ) } else { val (payload, checksum) = iter.current.span(_ != '#') - val expressionIter = DescriptorIterator(payload.dropRight(1)) //drop ')' + val expressionIter = DescriptorIterator(payload.dropRight(1)) // drop ')' val expression = parseValidExpression(expressionIter) - //now check for a valid checksum + // now check for a valid checksum val checksumOpt = - if (checksum.nonEmpty) Some(checksum.tail) else None //drop '#' + if (checksum.nonEmpty) Some(checksum.tail) else None // drop '#' val isValidChecksum = Descriptor.isValidChecksum( createDescriptor(expression, None), - checksumOpt) + checksumOpt + ) if (isValidChecksum) { createDescriptor(expression, checksumOpt) } else { @@ -167,19 +171,22 @@ object RawDescriptor extends DescriptorFactory[ RawDescriptor, RawScriptExpression, - DescriptorType.Raw.type] { + DescriptorType.Raw.type + ] { override val descriptorType: DescriptorType.Raw.type = DescriptorType.Raw override protected def parseValidExpression( - iter: DescriptorIterator): RawScriptExpression = { + iter: DescriptorIterator + ): RawScriptExpression = { val raw = RawScriptPubKey.fromAsmHex(iter.current) RawScriptExpression(raw) } override protected def createDescriptor( e: RawScriptExpression, - checksum: Option[String]): RawDescriptor = { + checksum: Option[String] + ): RawDescriptor = { RawDescriptor(e, checksum) } } @@ -188,28 +195,33 @@ object P2WPKHDescriptor extends DescriptorFactory[ P2WPKHDescriptor, P2WPKHExpression, - DescriptorType.WPKH.type] { + DescriptorType.WPKH.type + ] { override val descriptorType: DescriptorType.WPKH.type = DescriptorType.WPKH override def parseValidExpression( - iter: DescriptorIterator): P2WPKHExpression = { + iter: DescriptorIterator + ): P2WPKHExpression = { val keyExpression = iter.takeSingleECKeyExpression() P2WPKHExpression(keyExpression) } override protected def createDescriptor( e: P2WPKHExpression, - checksum: Option[String]): P2WPKHDescriptor = { + checksum: Option[String] + ): P2WPKHDescriptor = { P2WPKHDescriptor(e, checksum) } def apply( privKey: ECPrivateKey, - network: NetworkParameters): P2WPKHDescriptor = { + network: NetworkParameters + ): P2WPKHDescriptor = { val keyExpression = RawPrivateECPublicKeyExpression( key = privKey.toPrivateKeyBytes(), network = network, - originOpt = None) + originOpt = None + ) val p2wpkhExpression = P2WPKHExpression(keyExpression) val noChecksum = P2WPKHDescriptor(p2wpkhExpression, None) val checksum = Descriptor.createChecksum(noChecksum) @@ -221,38 +233,44 @@ object P2WSHDescriptor extends DescriptorFactory[ P2WSHDescriptor, P2WSHExpression, - DescriptorType.WSH.type] { + DescriptorType.WSH.type + ] { override val descriptorType: DescriptorType.WSH.type = DescriptorType.WSH override protected def parseValidExpression( - iter: DescriptorIterator): P2WSHExpression = { + iter: DescriptorIterator + ): P2WSHExpression = { val scriptExpression = iter.takeRawSPKScriptExpression() P2WSHExpression(scriptExpression) } override protected def createDescriptor( e: P2WSHExpression, - checksum: Option[String]): P2WSHDescriptor = { + checksum: Option[String] + ): P2WSHDescriptor = { P2WSHDescriptor(e, checksum) } } object P2PKDescriptor - extends DescriptorFactory[ - P2PKDescriptor[PublicKey], - P2PKScriptExpression[PublicKey], - DescriptorType.PK.type] { + extends DescriptorFactory[P2PKDescriptor[PublicKey], + P2PKScriptExpression[ + PublicKey + ], + DescriptorType.PK.type] { override val descriptorType: DescriptorType.PK.type = DescriptorType.PK override protected def parseValidExpression( - iter: DescriptorIterator): P2PKScriptExpression[PublicKey] = { + iter: DescriptorIterator + ): P2PKScriptExpression[PublicKey] = { val keyExpression = iter.takeSingleKeyExpression() P2PKScriptExpression[PublicKey](keyExpression) } override protected def createDescriptor( e: P2PKScriptExpression[PublicKey], - checksum: Option[String]): P2PKDescriptor[PublicKey] = { + checksum: Option[String] + ): P2PKDescriptor[PublicKey] = { P2PKDescriptor(e, checksum) } } @@ -261,18 +279,21 @@ object P2PKHDescriptor extends DescriptorFactory[ P2PKHDescriptor, P2PKHScriptExpression, - DescriptorType.PKH.type] { + DescriptorType.PKH.type + ] { override val descriptorType: DescriptorType.PKH.type = DescriptorType.PKH override protected def parseValidExpression( - iter: DescriptorIterator): P2PKHScriptExpression = { + iter: DescriptorIterator + ): P2PKHScriptExpression = { val keyExpression = iter.takeSingleECKeyExpression() P2PKHScriptExpression(keyExpression) } override protected def createDescriptor( e: P2PKHScriptExpression, - checksum: Option[String]): P2PKHDescriptor = { + checksum: Option[String] + ): P2PKHDescriptor = { P2PKHDescriptor(e, checksum) } } @@ -281,18 +302,21 @@ object MultisigDescriptor extends DescriptorFactory[ MultisigDescriptor, MultisigExpression, - DescriptorType.Multi.type] { + DescriptorType.Multi.type + ] { override val descriptorType: DescriptorType.Multi.type = DescriptorType.Multi override protected def parseValidExpression( - iter: DescriptorIterator): MultisigExpression = { + iter: DescriptorIterator + ): MultisigExpression = { val keyExpression = iter.takeMultisigKeyExpression() MultisigExpression(keyExpression) } override protected def createDescriptor( e: MultisigExpression, - checksum: Option[String]): MultisigDescriptor = { + checksum: Option[String] + ): MultisigDescriptor = { MultisigDescriptor(e, checksum) } } @@ -301,20 +325,23 @@ object SortedMultisigDescriptor extends DescriptorFactory[ SortedMultisigDescriptor, SortedMultisigExpression, - DescriptorType.SortedMulti.type] { + DescriptorType.SortedMulti.type + ] { override val descriptorType: DescriptorType.SortedMulti.type = DescriptorType.SortedMulti override protected def parseValidExpression( - iter: DescriptorIterator): SortedMultisigExpression = { + iter: DescriptorIterator + ): SortedMultisigExpression = { val expr = iter.takeMultisigKeyExpression() SortedMultisigExpression(expr) } override protected def createDescriptor( e: SortedMultisigExpression, - checksum: Option[String]): SortedMultisigDescriptor = { + checksum: Option[String] + ): SortedMultisigDescriptor = { SortedMultisigDescriptor(e, checksum) } } @@ -323,21 +350,25 @@ object P2SHDescriptor extends DescriptorFactory[ P2SHDescriptor, P2SHExpression, - DescriptorType.SH.type] { + DescriptorType.SH.type + ] { override val descriptorType: DescriptorType.SH.type = DescriptorType.SH override protected def parseValidExpression( - iter: DescriptorIterator): P2SHExpression = { + iter: DescriptorIterator + ): P2SHExpression = { val scriptExpression = iter.takeScriptExpressionECKey() require( !scriptExpression.isInstanceOf[ComboExpression], - s"Cannot have ComboExpression in P2SHDescriptor, got=$scriptExpression") + s"Cannot have ComboExpression in P2SHDescriptor, got=$scriptExpression" + ) P2SHExpression(scriptExpression) } override protected def createDescriptor( e: P2SHExpression, - checksum: Option[String]): P2SHDescriptor = { + checksum: Option[String] + ): P2SHDescriptor = { P2SHDescriptor(e, checksum) } } @@ -346,18 +377,21 @@ object ComboDescriptor extends DescriptorFactory[ ComboDescriptor, ComboExpression, - DescriptorType.Combo.type] { + DescriptorType.Combo.type + ] { override val descriptorType: DescriptorType.Combo.type = DescriptorType.Combo override protected def parseValidExpression( - iter: DescriptorIterator): ComboExpression = { + iter: DescriptorIterator + ): ComboExpression = { val keyExpr = iter.takeSingleECKeyExpression() ComboExpression(keyExpr) } override protected def createDescriptor( e: ComboExpression, - checksum: Option[String]): ComboDescriptor = { + checksum: Option[String] + ): ComboDescriptor = { if (e.source.pubKey.isCompressed) ComboDescriptorCompressed(e, checksum) else ComboDescriptorUncompressed(e, checksum) } @@ -367,30 +401,33 @@ object TaprootDescriptor extends DescriptorFactory[ TaprootDescriptor, TreeExpression, - DescriptorType.TR.type] { + DescriptorType.TR.type + ] { override val descriptorType: DescriptorType.TR.type = DescriptorType.TR override protected def parseValidExpression( - iter: DescriptorIterator): TreeExpression = { + iter: DescriptorIterator + ): TreeExpression = { val treeExpression = iter.takeTreeExpression() treeExpression } override protected def createDescriptor( e: TreeExpression, - checksum: Option[String]): TaprootDescriptor = { + checksum: Option[String] + ): TaprootDescriptor = { TaprootDescriptor(e, checksum) } } object ScriptDescriptor extends StringFactory[ScriptDescriptor] { - private val map: Map[ - DescriptorType, - DescriptorFactory[ - _ <: ScriptDescriptor, - _ <: ScriptExpression, - _ <: DescriptorType]] = { + private val map: Map[DescriptorType, + DescriptorFactory[ + _ <: ScriptDescriptor, + _ <: ScriptExpression, + _ <: DescriptorType + ]] = { Map( DescriptorType.Raw -> RawDescriptor, DescriptorType.WPKH -> P2WPKHDescriptor, @@ -414,7 +451,8 @@ object ScriptDescriptor extends StringFactory[ScriptDescriptor] { .get(s) .map(_.fromString(string)) .getOrElse( - sys.error(s"Cannot find parse t=$t to ScriptDescriptor s=$s")) + sys.error(s"Cannot find parse t=$t to ScriptDescriptor s=$s") + ) } } } @@ -441,11 +479,14 @@ object Descriptor extends StringFactory[Descriptor] { } /** Implements checksum algorithm specified by BIP380 for descriptors - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki#checksum]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki#checksum]] */ def createChecksum(string: String): String = { - require(!string.exists(_ == '#'), - s"String already contains checksum, got=$string") + require( + !string.exists(_ == '#'), + s"String already contains checksum, got=$string" + ) var c = UInt64.one var cls = 0 var clsCount = 0 @@ -480,7 +521,7 @@ object Descriptor extends StringFactory[Descriptor] { val builder = new StringBuilder(8) 0.until(8).foreach { j => - //ret[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31] + // ret[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31] val idx = (c.toLong >> (5 * (7 - j))) & 31 val char = Bech32.charset(idx.toInt) builder.append(char) @@ -495,9 +536,10 @@ object Descriptor extends StringFactory[Descriptor] { def isValidChecksum( descriptor: Descriptor, - checksumOpt: Option[String]): Boolean = { + checksumOpt: Option[String] + ): Boolean = { checksumOpt match { - case None => true //trivially true if we have no checksum + case None => true // trivially true if we have no checksum case Some(checksum) => val t = Try(createChecksum(descriptor.toString)) if (t.isFailure) false @@ -506,8 +548,10 @@ object Descriptor extends StringFactory[Descriptor] { } /** Implement polynomial algorithm for descriptors - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki#checksum]] - * @see [[https://github.com/bitcoin/bitcoin/blob/d1e9a02126634f9e2ca0b916b69b173a8646524d/src/script/descriptor.cpp#L90]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki#checksum]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/d1e9a02126634f9e2ca0b916b69b173a8646524d/src/script/descriptor.cpp#L90]] */ private def polyMod(c: UInt64, idx: Int): UInt64 = { var res = c diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorExpression.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorExpression.scala index ceb5b64653..9d47c17129 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorExpression.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorExpression.scala @@ -57,8 +57,8 @@ sealed abstract class SingleXOnlyPubKeyExpression } } -/** A trait that allows us to parameterize by [[PublicKey]] type. - * This is needed for re-using descriptors across [[ECPublicKey]] and [[XOnlyPubKey]] +/** A trait that allows us to parameterize by [[PublicKey]] type. This is needed + * for re-using descriptors across [[ECPublicKey]] and [[XOnlyPubKey]] */ sealed trait PubKeyTypeExpression[T <: PublicKey] @@ -85,9 +85,8 @@ sealed abstract class PrivateXOnlyPublicKeyExpression override def key: ECPrivateKeyBytes } -/** A private key descriptor expression - * Examples of what this data structure can represent - * 5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss +/** A private key descriptor expression Examples of what this data structure can + * represent 5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss * L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1 * * Its unclear to me at this point if private keys can have key origin @@ -98,8 +97,8 @@ sealed abstract class PrivateXOnlyPublicKeyExpression case class RawPrivateECPublicKeyExpression( key: ECPrivateKeyBytes, network: NetworkParameters, - originOpt: Option[KeyOriginExpression]) - extends PrivateECPublicKeyExpression + originOpt: Option[KeyOriginExpression] +) extends PrivateECPublicKeyExpression with ECPublicKeyExpression { override def toString(): String = { @@ -108,13 +107,13 @@ case class RawPrivateECPublicKeyExpression( } } -/** A private key expression that produces an [[XOnlyPubKey]] - * Example: tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1) +/** A private key expression that produces an [[XOnlyPubKey]] Example: + * tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1) * @param raw */ case class RawPrivateXOnlyPublicKeyExpression( - raw: RawPrivateECPublicKeyExpression) - extends PrivateXOnlyPublicKeyExpression + raw: RawPrivateECPublicKeyExpression +) extends PrivateXOnlyPublicKeyExpression with XOnlyPublicKeyExpression { override val originOpt: Option[KeyOriginExpression] = raw.originOpt override val key: ECPrivateKeyBytes = raw.key @@ -135,8 +134,8 @@ sealed abstract class PublicECPublicKeyExpression */ case class RawPublicECPublicKeyExpression( key: ECPublicKeyBytes, - originOpt: Option[KeyOriginExpression]) - extends PublicECPublicKeyExpression + originOpt: Option[KeyOriginExpression] +) extends PublicECPublicKeyExpression with ECPublicKeyExpression { override def toString(): String = { @@ -145,14 +144,13 @@ case class RawPublicECPublicKeyExpression( } } -/** A single [[XOnlyPubKey]] in a descriptor - * Example: +/** A single [[XOnlyPubKey]] in a descriptor Example: * tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd) */ case class RawPublicXOnlyPublicKeyExpression( originOpt: Option[KeyOriginExpression], - override val pubKey: XOnlyPubKey) - extends SingleXOnlyPubKeyExpression + override val pubKey: XOnlyPubKey +) extends SingleXOnlyPubKeyExpression with XOnlyPublicKeyExpression { override def key: ECKeyBytes = pubKey.publicKey.toPublicKeyBytes() @@ -162,8 +160,7 @@ case class RawPublicXOnlyPublicKeyExpression( } } -/** Represents key expressions that are BIP32 keys - * Examples: +/** Represents key expressions that are BIP32 keys Examples: * xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc * [deadbeef/0'/1'/2']xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3/4/5 * [deadbeef/0'/1'/2']xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/3/4/5/\* @@ -175,9 +172,9 @@ sealed abstract class ExtECPublicKeyExpression def pathOpt: Option[BIP32Path] - /** Outer Option represents if we use this key or derive children - * Inner option represents whether child keys are hardened or not - * if they are hardedned, return the specifi [[HardenedType]] + /** Outer Option represents if we use this key or derive children Inner option + * represents whether child keys are hardened or not if they are hardedned, + * return the specifi [[HardenedType]] */ def childrenHardenedOpt: Option[Option[HardenedType]] @@ -200,8 +197,8 @@ sealed abstract class ExtECPublicKeyExpression sealed abstract class ExtXOnlyPublicKeyExpression extends SingleXOnlyPubKeyExpression { _: XOnlyPublicKeyExpression => - /** Since implementations are so similar, just piggy back off of the ExtECPublicKeyExpression - * implementation rather than duplicating everything + /** Since implementations are so similar, just piggy back off of the + * ExtECPublicKeyExpression implementation rather than duplicating everything */ def ecPublicKeyExpression: ExtECPublicKeyExpression @@ -226,8 +223,8 @@ case class XprvECPublicKeyExpression( override val extKey: ExtPrivateKey, originOpt: Option[KeyOriginExpression], pathOpt: Option[BIP32Path], - childrenHardenedOpt: Option[Option[HardenedType]]) - extends ExtECPublicKeyExpression + childrenHardenedOpt: Option[Option[HardenedType]] +) extends ExtECPublicKeyExpression with ECPublicKeyExpression { override val key: ECPrivateKeyBytes = { @@ -245,7 +242,8 @@ case class XprvECPublicKeyExpression( override def deriveChild(idx: Int): ECPrivateKey = { require( childrenHardenedOpt.isDefined, - s"Cannot derive child keys from descriptor that does not allow children, got=${toString}") + s"Cannot derive child keys from descriptor that does not allow children, got=${toString}" + ) val node = BIP32Node(index = idx, hardenedOpt = childrenHardenedOpt.get) val fullPath: BIP32Path = pathOpt match { @@ -257,8 +255,8 @@ case class XprvECPublicKeyExpression( } case class XprvXOnlyPublicKeyExpression( - ecPublicKeyExpression: XprvECPublicKeyExpression) - extends ExtXOnlyPublicKeyExpression + ecPublicKeyExpression: XprvECPublicKeyExpression +) extends ExtXOnlyPublicKeyExpression with XOnlyPublicKeyExpression { override val originOpt: Option[KeyOriginExpression] = @@ -275,8 +273,8 @@ case class XpubECPublicKeyExpression( override val extKey: ExtPublicKey, originOpt: Option[KeyOriginExpression], pathOpt: Option[BIP32Path], - childrenHardenedOpt: Option[Option[HardenedType]]) - extends ExtECPublicKeyExpression + childrenHardenedOpt: Option[Option[HardenedType]] +) extends ExtECPublicKeyExpression with ECPublicKeyExpression { override val key: ECPublicKeyBytes = { @@ -294,7 +292,8 @@ case class XpubECPublicKeyExpression( override def deriveChild(idx: Int): ECPublicKey = { require( childrenHardenedOpt.isDefined, - s"Cannot derive child keys from descriptor that does not allow children, got=${toString}") + s"Cannot derive child keys from descriptor that does not allow children, got=${toString}" + ) val node = BIP32Node(index = idx, hardenedOpt = childrenHardenedOpt.get) val fullPath: BIP32Path = pathOpt match { case Some(p) => BIP32Path(p.path.appended(node)) @@ -311,8 +310,8 @@ case class XpubECPublicKeyExpression( * @param ecPublicKeyExpression */ case class XpubXOnlyPublicKeyExpression( - ecPublicKeyExpression: ExtECPublicKeyExpression) - extends ExtXOnlyPublicKeyExpression + ecPublicKeyExpression: ExtECPublicKeyExpression +) extends ExtXOnlyPublicKeyExpression with XOnlyPublicKeyExpression { override val originOpt: Option[KeyOriginExpression] = @@ -321,10 +320,10 @@ case class XpubXOnlyPublicKeyExpression( case class MultisigKeyExpression( numSigsRequired: Int, - keyExpressions: Vector[SingleECPublicKeyExpression]) - extends KeyExpression[ECPublicKey] - //cannot directly mixin ECPublicKeyExpression - //because we don't have a single pubKey to represent multisig + keyExpressions: Vector[SingleECPublicKeyExpression] +) extends KeyExpression[ECPublicKey] + // cannot directly mixin ECPublicKeyExpression + // because we don't have a single pubKey to represent multisig with PubKeyTypeExpression[ECPublicKey] { override val originOpt = None @@ -345,13 +344,11 @@ case class MultisigKeyExpression( } /** Example: { - * pk(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0), - * { - * { - * pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL), - * pk(02df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076)},pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1) - * } - * } + * pk(xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334/0), + * { { + * pk(xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL), + * pk(02df12b7035bdac8e3bab862a3a83d06ea6b17b6753d52edecba9be46f5d09e076)},pk(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1) + * } } * @param scriptExpressions */ sealed abstract class TapscriptTreeExpression extends DescriptorExpression { @@ -360,11 +357,12 @@ sealed abstract class TapscriptTreeExpression extends DescriptorExpression { def tree: TapscriptTree } -/** Branches in a [[TapscriptTreeExpression]]. This corresponds to [[TapBranch]] */ +/** Branches in a [[TapscriptTreeExpression]]. This corresponds to [[TapBranch]] + */ case class TapscriptBranchExpression( left: TapscriptTreeExpression, - right: TapscriptTreeExpression) - extends TapscriptTreeExpression { + right: TapscriptTreeExpression +) extends TapscriptTreeExpression { def leafs: Vector[TapscriptLeafExpression] = { left.leafs ++ right.leafs @@ -405,15 +403,19 @@ object SingleECPublicKeyExpression val childrenHardenedOpt = iter.takeChildrenHardenedOpt() extKey match { case xprv: ExtPrivateKey => - XprvECPublicKeyExpression(xprv, - keyOriginOpt, - pathOpt, - childrenHardenedOpt) + XprvECPublicKeyExpression( + xprv, + keyOriginOpt, + pathOpt, + childrenHardenedOpt + ) case xpub: ExtPublicKey => - XpubECPublicKeyExpression(xpub, - keyOriginOpt, - pathOpt, - childrenHardenedOpt) + XpubECPublicKeyExpression( + xpub, + keyOriginOpt, + pathOpt, + childrenHardenedOpt + ) } } else { // needed to parse network info in case of WIF private key @@ -424,9 +426,11 @@ object SingleECPublicKeyExpression val networkT = ECPrivateKeyUtil.parseNetworkFromWIF(cp) networkT match { case Success(network) => - RawPrivateECPublicKeyExpression(key = priv, - network = network, - originOpt = keyOriginOpt) + RawPrivateECPublicKeyExpression( + key = priv, + network = network, + originOpt = keyOriginOpt + ) case Failure(err) => throw err } case pub: ECPublicKeyBytes => @@ -446,7 +450,7 @@ object SingleXOnlyPubKeyExpression case rawPriv: RawPrivateECPublicKeyExpression => RawPrivateXOnlyPublicKeyExpression(rawPriv) case _: RawPublicECPublicKeyExpression => - //cannot convert correctly, so just re-parse + // cannot convert correctly, so just re-parse val iter = DescriptorIterator(string) iter.takeInternalPublicKeyExpression() } @@ -459,7 +463,7 @@ object MultisigKeyExpression extends StringFactory[MultisigKeyExpression] { val (requiredSigsStr, keyExpressionsStr) = string.span(_ != ',') val split = keyExpressionsStr - .drop(1) //drop ',' + .drop(1) // drop ',' .split(',') .toVector val keyExpressions = split.map(SingleECPublicKeyExpression.fromString(_)) @@ -507,8 +511,7 @@ sealed trait ExpressionSource { _: ScriptExpression => } } -/** A script expression derived from a key expression - * Example: +/** A script expression derived from a key expression Example: * tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd) * tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1) * pkh([bd16bee5/2147483647']xpub69H7F5dQzmVd3vPuLKtcXJziMEQByuDidnX3YdwgtNsecY5HRGtAAQC5mXTt4dsv9RzyjgDjAQs9VGVV6ydYCHnprc9vvaA5YtqWyL6hyds/0) @@ -519,8 +522,7 @@ sealed trait KeyExpressionScriptExpression[T <: PublicKey] override def source: KeyExpression[T] } -/** A script expression nested inside of another script expression - * Example: +/** A script expression nested inside of another script expression Example: * sh(wsh(pkh(03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd))) */ sealed trait NestedScriptExpression extends ExpressionSource { @@ -533,9 +535,7 @@ sealed trait TapscriptTreeExpressionSource extends ExpressionSource { override def source: TapscriptTreeExpression } -/** Examples: - * raw(deadbeef) - * raw(a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87) +/** Examples: raw(deadbeef) raw(a9149a4d9901d6af519b2a23d4a2f51650fcba87ce7b87) */ case class RawScriptExpression(scriptPubKey: RawScriptPubKey) extends RawSPKScriptExpression { @@ -612,8 +612,10 @@ case class P2SHExpression(source: ScriptExpression) override val scriptPubKey: P2SHScriptPubKey = { source.scriptPubKey match { case m: MultiSignatureScriptPubKey => - require(m.requiredSigs <= 15, - s"P2SHExpressions required <= 15 sigs, got=${m.requiredSigs}") + require( + m.requiredSigs <= 15, + s"P2SHExpressions required <= 15 sigs, got=${m.requiredSigs}" + ) P2SHScriptPubKey(m) case _ => P2SHScriptPubKey(source.scriptPubKey) } @@ -621,8 +623,7 @@ case class P2SHExpression(source: ScriptExpression) } } -/** A multisig expression - * Example: +/** A multisig expression Example: * multi(1,L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss) * @param source */ @@ -637,7 +638,8 @@ case class MultisigExpression(source: MultisigKeyExpression) require( scriptPubKey.requiredSigs > 0, - s"Must have positive requiredSigs in MultisigScriptExpression, got=${scriptPubKey.requiredSigs}") + s"Must have positive requiredSigs in MultisigScriptExpression, got=${scriptPubKey.requiredSigs}" + ) require( scriptPubKey.requiredSigs <= scriptPubKey.maxSigs, @@ -645,8 +647,7 @@ case class MultisigExpression(source: MultisigKeyExpression) ) } -/** Multisig expressions with lexographically sorted public keys - * Example: +/** Multisig expressions with lexographically sorted public keys Example: * sortedmulti(2,xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/\*,xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y/0/0/\*) */ case class SortedMultisigExpression(source: MultisigKeyExpression) @@ -661,15 +662,15 @@ case class SortedMultisigExpression(source: MultisigKeyExpression) } require( scriptPubKey.requiredSigs > 0, - s"Must have positive requiredSigs in MultisigScriptExpression, got=${scriptPubKey.requiredSigs}") + s"Must have positive requiredSigs in MultisigScriptExpression, got=${scriptPubKey.requiredSigs}" + ) require( scriptPubKey.requiredSigs <= scriptPubKey.maxSigs, s"Required sigs greater than max sigs, got requiredSigs=${scriptPubKey.requiredSigs} maxSigs=${scriptPubKey.maxSigs}" ) } -/** An expression that can produce multiple types of scripts - * Example: +/** An expression that can produce multiple types of scripts Example: * combo(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1) * combo([01234567]xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL) * @param source @@ -677,8 +678,8 @@ case class SortedMultisigExpression(source: MultisigKeyExpression) */ case class ComboExpression( source: SingleECPublicKeyExpression, - scriptType: ScriptType = ScriptType.PUBKEYHASH) - extends ScriptExpression + scriptType: ScriptType = ScriptType.PUBKEYHASH +) extends ScriptExpression with KeyExpressionScriptExpression[ECPublicKey] { override val descriptorType: DescriptorType = DescriptorType.Combo @@ -713,7 +714,7 @@ object ScriptExpressionECKey extends StringFactory[ScriptExpression] { P2WPKHExpression(iter.takeSingleECKeyExpression()) case DescriptorType.WSH => P2WSHExpression(iter.takeRawSPKScriptExpression()) - case DescriptorType.SH => P2SHExpression(iter.takeScriptExpressionECKey()) + case DescriptorType.SH => P2SHExpression(iter.takeScriptExpressionECKey()) case DescriptorType.Raw => RawScriptExpression(iter.takeRawScriptPubKey()) case DescriptorType.PK => P2PKScriptExpression(iter.takeSingleECKeyExpression()) @@ -725,7 +726,8 @@ object ScriptExpressionECKey extends StringFactory[ScriptExpression] { ComboExpression(iter.takeSingleECKeyExpression()) case DescriptorType.TR => sys.error( - s"Cannot create tapscript expression's with ECPublicKey, got=$string") + s"Cannot create tapscript expression's with ECPublicKey, got=$string" + ) } expression } @@ -747,7 +749,8 @@ object ScriptExpressionXOnlyKey extends StringFactory[ScriptExpression] { case x @ (DescriptorType.Combo | DescriptorType.TR | DescriptorType.SH | DescriptorType.WSH | DescriptorType.WPKH | DescriptorType.PKH) => sys.error( - s"Cannot create tapscript descriptor for descriptorType=$x, got=$string") + s"Cannot create tapscript descriptor for descriptorType=$x, got=$string" + ) } expression } @@ -761,8 +764,7 @@ sealed abstract class TreeExpression extends ScriptExpression { override def scriptPubKey: TaprootScriptPubKey } -/** A tapscript tree expression with ONLY the keypath. - * Example: +/** A tapscript tree expression with ONLY the keypath. Example: * tr(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1) * tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd) */ @@ -774,13 +776,13 @@ case class KeyPathOnlyTreeExpression(source: SingleXOnlyPubKeyExpression) TaprootScriptPubKey.fromInternalKey(source.pubKey) } -/** Tapscript tree with BOTH keypath and script path cases. - * Example: tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0)) +/** Tapscript tree with BOTH keypath and script path cases. Example: + * tr(a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd,pk(669b8afcec803a0d323e9a17f3ea8e68e8abe5a278020a929adbec52421adbd0)) */ case class ScriptPathTreeExpression( keyPath: KeyPathOnlyTreeExpression, - source: TapscriptTreeExpression) - extends TreeExpression + source: TapscriptTreeExpression +) extends TreeExpression with TapscriptTreeExpressionSource { override def scriptPubKey: TaprootScriptPubKey = { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorIterator.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorIterator.scala index e0dbb480e8..969be3d11c 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorIterator.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorIterator.scala @@ -23,16 +23,16 @@ case class DescriptorIterator(descriptor: String) { def takeDescriptorType(): DescriptorType = { val t = DescriptorType.fromString(current) skip(t.toString.length) - skip(1) //skip the '(' in 'wpkh(' + skip(1) // skip the '(' in 'wpkh(' t } def takeBIP32PathOpt(): Option[BIP32Path] = { if (current.nonEmpty && current.charAt(0) == '/') { val (stripped, _) = if (current.exists(_ == '*')) { - current.span(_ != '*') //remove indicator if all children are hardened + current.span(_ != '*') // remove indicator if all children are hardened } else { - current.span(_ != ')') //else if no hardened indcator, drop last ')' + current.span(_ != ')') // else if no hardened indcator, drop last ')' } val hdPath = BIP32Path.fromString("m" + stripped) skip(hdPath.toString.length) @@ -63,7 +63,7 @@ case class DescriptorIterator(descriptor: String) { def takeChecksumOpt(): Option[String] = { if (current.isEmpty || !(current.take(1) == '#')) { - //means we do not have a checksum + // means we do not have a checksum None } else { Some(current.take(8)) @@ -74,7 +74,7 @@ case class DescriptorIterator(descriptor: String) { val (originStr, _) = current.span(_ != ']') if (originStr.startsWith("[") && originStr.nonEmpty) { val origin = KeyOriginExpression - .fromString(originStr + "]") //span drops the last ']', so re-add + .fromString(originStr + "]") // span drops the last ']', so re-add skip(origin.toString.length) Some(origin) } else None @@ -109,7 +109,7 @@ case class DescriptorIterator(descriptor: String) { def takeSingleKeyExpression(): SingleKeyExpression[PublicKey] = { if (current.exists(_ == ',')) { - //must be xonly, the + // must be xonly, the takeSingleXOnlyPubKeyExpression() .asInstanceOf[SingleKeyExpression[PublicKey]] } else { @@ -133,10 +133,10 @@ case class DescriptorIterator(descriptor: String) { def takeSingleXOnlyPubKeyExpression(): SingleXOnlyPubKeyExpression = { val keyExpr = { if (current.exists(_ == ',')) { - //we have a script path + // we have a script path current.span(_ != ',')._1 } else { - //no script path, just internal key + // no script path, just internal key current.takeWhile(_ != ')') } } @@ -144,8 +144,10 @@ case class DescriptorIterator(descriptor: String) { val single = SingleXOnlyPubKeyExpression.fromString(keyExpr) skip(single.toString().length) if (current.nonEmpty) { - require(current.head == ',' || current.head == ')', - s"Key was not 32 bytes, got=$descriptor current=$current") + require( + current.head == ',' || current.head == ')', + s"Key was not 32 bytes, got=$descriptor current=$current" + ) } skip(1) // ',' single @@ -183,7 +185,8 @@ case class DescriptorIterator(descriptor: String) { case raw: RawSPKScriptExpression => raw case x => sys.error( - s"Unexpected expression=$x when expecting RawSPKScriptExpression") + s"Unexpected expression=$x when expecting RawSPKScriptExpression" + ) } } @@ -200,7 +203,8 @@ case class DescriptorIterator(descriptor: String) { case raw: RawSPKScriptExpression => raw case x => sys.error( - s"Unexpected expression=$x when expecting RawSPKScriptExpression") + s"Unexpected expression=$x when expecting RawSPKScriptExpression" + ) } } @@ -233,13 +237,13 @@ case class DescriptorIterator(descriptor: String) { def takeTapscriptTreeExpression(): TapscriptTreeExpression = { val expression = if (current.charAt(0) == '{' && current.last == '}') { - skip(1) //{ + skip(1) // { val tree1 = takeTapscriptTreeExpression() - skip(1) //, + skip(1) // , val tree2 = takeTapscriptTreeExpression() val branch = TapscriptBranchExpression(tree1, tree2) - skip(1) //} + skip(1) // } branch } else { val expression = takeRawScriptExpressionXOnlyKey() diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorType.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorType.scala index fb3922e767..e6a5bf5009 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorType.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/DescriptorType.scala @@ -3,7 +3,9 @@ package org.bitcoins.core.protocol.script.descriptor import org.bitcoins.core.script.ScriptType import org.bitcoins.crypto.StringFactory -/** @see [[https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md#features]] */ +/** @see + * [[https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md#features]] + */ sealed abstract class DescriptorType sealed abstract class ScriptDescriptorType extends DescriptorType { @@ -58,7 +60,7 @@ object DescriptorType extends StringFactory[DescriptorType] { } case object Combo extends ScriptDescriptorType { - //this is wrong, combo doesn't have a specific script type? + // this is wrong, combo doesn't have a specific script type? override val scriptType: ScriptType = ScriptType.PUBKEYHASH override val toString: String = "combo" } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/KeyOriginExpression.scala b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/KeyOriginExpression.scala index b63f0125ca..817ce1979b 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/KeyOriginExpression.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/script/descriptor/KeyOriginExpression.scala @@ -13,8 +13,10 @@ case class KeyOriginExpression(fingerprint: String, path: BIP32Path) { object KeyOriginExpression extends StringFactory[KeyOriginExpression] { override def fromString(string: String): KeyOriginExpression = { - require(string.head == '[' && string.last == ']', - s"KeyOriginDescriptor must start and end with [], got=$string") + require( + string.head == '[' && string.last == ']', + s"KeyOriginDescriptor must start and end with [], got=$string" + ) val payload = string.drop(1).dropRight(1) val fingerprint = payload.take(8) val pathElements = payload.drop(8) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/tlv/DLCOutcomeType.scala b/core/src/main/scala/org/bitcoins/core/protocol/tlv/DLCOutcomeType.scala index 5435d5130c..7fe2373397 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/tlv/DLCOutcomeType.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/tlv/DLCOutcomeType.scala @@ -21,9 +21,9 @@ sealed trait NumericDLCOutcomeType extends DLCOutcomeType /** An outcome from a multi-nonce unsigned numeric event type. * - * If digits.length is less than the the total number of digits to be - * signed by the oracle then this outcome represents all outcomes prefixed - * by the given digits. + * If digits.length is less than the the total number of digits to be signed by + * the oracle then this outcome represents all outcomes prefixed by the given + * digits. * * I.e. the Vector[Int] is always the most significant digits. */ @@ -36,9 +36,9 @@ case class UnsignedNumericOutcome(digits: Vector[Int]) /** An outcome from a multi-nonce signed numeric event type. * - * If digits.length is less than the the total number of digits to be - * signed by the oracle then this outcome represents all outcomes prefixed - * by the given digits. + * If digits.length is less than the the total number of digits to be signed by + * the oracle then this outcome represents all outcomes prefixed by the given + * digits. * * I.e. the Vector[Int] is always the most significant digits. */ diff --git a/core/src/main/scala/org/bitcoins/core/protocol/tlv/DLCSerializationVersion.scala b/core/src/main/scala/org/bitcoins/core/protocol/tlv/DLCSerializationVersion.scala index 3ce8d8de2a..4eb8222a5b 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/tlv/DLCSerializationVersion.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/tlv/DLCSerializationVersion.scala @@ -2,10 +2,10 @@ package org.bitcoins.core.protocol.tlv import org.bitcoins.crypto.StringFactory -/** We have various binary serializations in our codebase currently. - * This is a product of trying to release a DLC wallet before the - * spec was finalized. Some of the binary level serialization for DLCs - * has changed since we initiallly deployed wallets. +/** We have various binary serializations in our codebase currently. This is a + * product of trying to release a DLC wallet before the spec was finalized. + * Some of the binary level serialization for DLCs has changed since we + * initiallly deployed wallets. */ sealed trait DLCSerializationVersion @@ -13,15 +13,17 @@ object DLCSerializationVersion extends StringFactory[DLCSerializationVersion] { val current: DLCSerializationVersion = Beta - /** This format existed in our wallet before we merged support for this PR - * on the DLC spec repo. See the diff below - * @see [[https://github.com/discreetlogcontracts/dlcspecs/pull/144]] + /** This format existed in our wallet before we merged support for this PR on + * the DLC spec repo. See the diff below + * @see + * [[https://github.com/discreetlogcontracts/dlcspecs/pull/144]] */ case object Alpha extends DLCSerializationVersion - /** This represents binary serialization for the case where we have - * included support for 144, but not included support for 163 yet - * @see [[https://github.com/discreetlogcontracts/dlcspecs/pull/144]] + /** This represents binary serialization for the case where we have included + * support for 144, but not included support for 163 yet + * @see + * [[https://github.com/discreetlogcontracts/dlcspecs/pull/144]] */ case object Beta extends DLCSerializationVersion @@ -32,7 +34,8 @@ object DLCSerializationVersion extends StringFactory[DLCSerializationVersion] { case Some(version) => version case None => sys.error( - s"Could not find DLC serialization version associated with str=$str") + s"Could not find DLC serialization version associated with str=$str" + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/tlv/LnMessage.scala b/core/src/main/scala/org/bitcoins/core/protocol/tlv/LnMessage.scala index 84f08de27d..8c10d8408f 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/tlv/LnMessage.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/tlv/LnMessage.scala @@ -5,16 +5,16 @@ import org.bitcoins.core.protocol.BigSizeUInt import org.bitcoins.crypto.{Factory, NetworkElement} import scodec.bits.ByteVector -/** Lightning Network message serialization is the same as TLV - * serialization except that the type is represented with a - * UInt16 instead of BigSizeUInt and length is omitted. +/** Lightning Network message serialization is the same as TLV serialization + * except that the type is represented with a UInt16 instead of BigSizeUInt and + * length is omitted. * - * The reason for the omission is that the message is expected to - * be encrypted by the LN transport layer and the length is included - * there in the unencrypted part of the packet. + * The reason for the omission is that the message is expected to be encrypted + * by the LN transport layer and the length is included there in the + * unencrypted part of the packet. * - * The reason that LnMessage doesn't just do what TLV does (which is better) - * is because TLVs are newer and so we're stuck with the legacy format. + * The reason that LnMessage doesn't just do what TLV does (which is better) is + * because TLVs are newer and so we're stuck with the legacy format. */ case class LnMessage[+T <: TLV](tlv: T) extends NetworkElement { require(tlv.tpe.toLong <= 65535L, s"LN Message format requires UInt16 types") diff --git a/core/src/main/scala/org/bitcoins/core/protocol/tlv/TLV.scala b/core/src/main/scala/org/bitcoins/core/protocol/tlv/TLV.scala index 0648aca8f7..7305fd06be 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/tlv/TLV.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/tlv/TLV.scala @@ -78,14 +78,16 @@ trait TLVUtil { protected def u16PrefixedList[T]( vec: Vector[T], - serialize: T => ByteVector): ByteVector = { + serialize: T => ByteVector + ): ByteVector = { vec.foldLeft(UInt16(vec.length).bytes) { case (accum, elem) => accum ++ serialize(elem) } } protected def u16PrefixedList[T <: NetworkElement]( - vec: Vector[T]): ByteVector = { + vec: Vector[T] + ): ByteVector = { u16PrefixedList[T](vec, { elem: NetworkElement => elem.bytes }) } @@ -95,14 +97,16 @@ trait TLVUtil { protected def bigSizePrefixedList[T]( vec: Vector[T], - serialize: T => ByteVector): ByteVector = { + serialize: T => ByteVector + ): ByteVector = { vec.foldLeft(BigSizeUInt(vec.length).bytes) { case (accum, elem) => accum ++ serialize(elem) } } protected def bigSizePrefixedList[T <: NetworkElement]( - vec: Vector[T]): ByteVector = { + vec: Vector[T] + ): ByteVector = { bigSizePrefixedList[T](vec, { elem: NetworkElement => elem.bytes }) } } @@ -114,8 +118,8 @@ trait TLVSerializable[+T <: TLV] extends NetworkElement { } abstract class TLVDeserializable[T <: TLV, +U <: TLVSerializable[T]]( - tlvFactory: Factory[T]) - extends Factory[U] { + tlvFactory: Factory[T] +) extends Factory[U] { def fromTLV(tlv: T): U override def fromBytes(bytes: ByteVector): U = @@ -137,7 +141,8 @@ sealed trait TLVParentFactory[T <: TLV] extends Factory[T] { case Some(tlvFactory) => tlvFactory.fromTLVValue(value) case None => throw new IllegalArgumentException( - s"Unknown $typeName type got $tpe (${TLV.getTypeName(tpe)})") + s"Unknown $typeName type got $tpe (${TLV.getTypeName(tpe)})" + ) } } } @@ -150,7 +155,8 @@ object TLV extends TLVParentFactory[TLV] { case class DecodeTLVResult( tpe: BigSizeUInt, length: BigSizeUInt, - value: ByteVector) + value: ByteVector + ) def decodeTLV(bytes: ByteVector): DecodeTLVResult = { val tpe = BigSizeUInt(bytes) @@ -159,7 +165,8 @@ object TLV extends TLVParentFactory[TLV] { require( bytes.length >= prefixSize + length.num.toLong, - s"Length specified was $length but not enough bytes in ${bytes.drop(prefixSize)}") + s"Length specified was $length but not enough bytes in ${bytes.drop(prefixSize)}" + ) val value = bytes.drop(prefixSize).take(length.num.toLong) DecodeTLVResult(tpe, length, value) @@ -242,8 +249,10 @@ sealed trait TLVFactory[+T <: TLV] extends Factory[T] { override def fromBytes(bytes: ByteVector): T = { val DecodeTLVResult(tpe, _, value) = TLV.decodeTLV(bytes) - require(tpe == this.tpe, - s"Got ${TLV.getTypeName(tpe)} type when expecting ${typeName}") + require( + tpe == this.tpe, + s"Got ${TLV.getTypeName(tpe)} type when expecting ${typeName}" + ) fromTLVValue(value) } @@ -285,11 +294,13 @@ object NormalizedString extends StringFactory[NormalizedString] { // If other kinds of Iterables are needed, there's a fancy thing to do // that is done all over the Seq code using params and an implicit CanBuildFrom implicit def stringVecToNormalized( - strs: Vector[String]): Vector[NormalizedString] = + strs: Vector[String] + ): Vector[NormalizedString] = strs.map(apply) implicit def normalizedVecToString( - strs: Vector[NormalizedString]): Vector[String] = + strs: Vector[NormalizedString] + ): Vector[String] = strs.map(_.normStr) override def fromString(string: String): NormalizedString = @@ -397,19 +408,25 @@ object PaymentDataTLV extends TLVFactory[PaymentDataTLV] { override val typeName: String = "PaymentDataTLV" } -/** @see https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#the-init-message */ +/** @see + * https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#the-init-message + */ case class InitTLV( globalFeatureBytes: ByteVector, featureBytes: ByteVector, - initTLVs: Vector[TLV]) - extends TLV { + initTLVs: Vector[TLV] +) extends TLV { initTLVs.collect { case UnknownTLV(tpe, _) => - require(tpe.toBigInt % 2 != 0, - s"Cannot have unknown even initTLVs, got $initTLVs") + require( + tpe.toBigInt % 2 != 0, + s"Cannot have unknown even initTLVs, got $initTLVs" + ) } - require(initTLVs.map(_.tpe).distinct.size == initTLVs.size, - s"Cannot have duplicate TLV types in initTLVs, got $initTLVs") + require( + initTLVs.map(_.tpe).distinct.size == initTLVs.size, + s"Cannot have duplicate TLV types in initTLVs, got $initTLVs" + ) override val tpe: BigSizeUInt = InitTLV.tpe @@ -445,7 +462,9 @@ object InitTLV extends TLVFactory[InitTLV] { override val typeName: String = "InitTLV" } -/** @see [[https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#the-error-message]] */ +/** @see + * [[https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#the-error-message]] + */ case class ErrorTLV(id: ByteVector, data: ByteVector) extends TLV { require(id.length == 32, s"ID associated with error is incorrect length: $id") @@ -526,7 +545,8 @@ sealed trait EventDescriptorTLV extends DLCOracleTLV { def noncesNeeded: Int /** Event descriptors all use the same signing version as of now. - * @see https://github.com/discreetlogcontracts/dlcspecs/pull/113 + * @see + * https://github.com/discreetlogcontracts/dlcspecs/pull/113 */ def signingVersion: SigningVersion = DLCOracleV0SigningVersion } @@ -540,8 +560,10 @@ object EventDescriptorTLV extends TLVParentFactory[EventDescriptorTLV] { } /** Describes an event over an enumerated set of outcomes - * @param outcomes The set of possible outcomes - * @see https://github.com/discreetlogcontracts/dlcspecs/blob/master/Oracle.md#simple-enumeration + * @param outcomes + * The set of possible outcomes + * @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/master/Oracle.md#simple-enumeration */ case class EnumEventDescriptorV0TLV(outcomes: Vector[NormalizedString]) extends EventDescriptorTLV { @@ -567,7 +589,8 @@ object EnumEventDescriptorV0TLV extends TLVFactory[EnumEventDescriptorV0TLV] { } val dummy: EnumEventDescriptorV0TLV = EnumEventDescriptorV0TLV( - Vector("dummy")) + Vector("dummy") + ) override val typeName: String = "EnumEventDescriptorV0TLV" } @@ -598,9 +621,9 @@ sealed trait NumericEventDescriptorTLV extends EventDescriptorTLV { /** The unit of the outcome value */ def unit: NormalizedString - /** The precision of the outcome representing the base exponent - * by which to multiply the number represented by the composition - * of the digits to obtain the actual outcome value. + /** The precision of the outcome representing the base exponent by which to + * multiply the number represented by the composition of the digits to obtain + * the actual outcome value. * * Modifies unit. */ @@ -614,10 +637,10 @@ sealed trait NumericEventDescriptorTLV extends EventDescriptorTLV { def maxToPrecision: BigDecimal = precisionModifier * BigDecimal(maxNum) - /** Checks if a outcome is contained in the set of outcomes when adjusted for precision - * If you have precision=-1 and oracle outcomes [0,1,2,3...,10] - * This would return true if passed a value [0, 0.1, 0.2,...,1.0] - * If passed in the not precision adjusted outcomes [0,1,2,...10] it will return false + /** Checks if a outcome is contained in the set of outcomes when adjusted for + * precision If you have precision=-1 and oracle outcomes [0,1,2,3...,10] + * This would return true if passed a value [0, 0.1, 0.2,...,1.0] If passed + * in the not precision adjusted outcomes [0,1,2,...10] it will return false */ def containsPreciseOutcome(outcome: BigDecimal): Boolean = { (outcome / precisionModifier).toBigIntExact match { @@ -633,8 +656,10 @@ sealed trait NumericEventDescriptorTLV extends EventDescriptorTLV { /** Describes a large range event using numerical decomposition */ sealed trait DigitDecompositionEventDescriptorV0TLV extends NumericEventDescriptorTLV { - require(numDigits > UInt16.zero, - s"Number of digits must be positive, got $numDigits") + require( + numDigits > UInt16.zero, + s"Number of digits must be positive, got $numDigits" + ) /** The number of digits that the oracle will sign */ def numDigits: UInt16 @@ -705,8 +730,8 @@ case class SignedDigitDecompositionEventDescriptor( base: UInt16, numDigits: UInt16, unit: NormalizedString, - precision: Int32) - extends DigitDecompositionEventDescriptorV0TLV { + precision: Int32 +) extends DigitDecompositionEventDescriptorV0TLV { override val isSigned: Boolean = true } @@ -716,8 +741,8 @@ case class UnsignedDigitDecompositionEventDescriptor( base: UInt16, numDigits: UInt16, unit: NormalizedString, - precision: Int32) - extends DigitDecompositionEventDescriptorV0TLV { + precision: Int32 +) extends DigitDecompositionEventDescriptorV0TLV { override val isSigned: Boolean = false } @@ -727,7 +752,8 @@ object DigitDecompositionEventDescriptorV0TLV override val tpe: BigSizeUInt = BigSizeUInt(55306) override def fromTLVValue( - value: ByteVector): DigitDecompositionEventDescriptorV0TLV = { + value: ByteVector + ): DigitDecompositionEventDescriptorV0TLV = { val iter = ValueIterator(value) val base = iter.takeU16() @@ -736,11 +762,13 @@ object DigitDecompositionEventDescriptorV0TLV val precision = iter.takeI32() val numDigits = iter.takeU16() - DigitDecompositionEventDescriptorV0TLV(base, - isSigned, - numDigits.toInt, - unit, - precision) + DigitDecompositionEventDescriptorV0TLV( + base, + isSigned, + numDigits.toInt, + unit, + precision + ) } def apply( @@ -748,17 +776,22 @@ object DigitDecompositionEventDescriptorV0TLV isSigned: Boolean, numDigits: Int, unit: NormalizedString, - precision: Int32): DigitDecompositionEventDescriptorV0TLV = { + precision: Int32 + ): DigitDecompositionEventDescriptorV0TLV = { if (isSigned) { - SignedDigitDecompositionEventDescriptor(base, - UInt16(numDigits), - unit, - precision) + SignedDigitDecompositionEventDescriptor( + base, + UInt16(numDigits), + unit, + precision + ) } else { - UnsignedDigitDecompositionEventDescriptor(base, - UInt16(numDigits), - unit, - precision) + UnsignedDigitDecompositionEventDescriptor( + base, + UInt16(numDigits), + unit, + precision + ) } } @@ -834,18 +867,20 @@ object OracleAnnouncementTLV extends TLVParentFactory[OracleAnnouncementTLV] { case class OracleAnnouncementV0TLV( announcementSignature: SchnorrDigitalSignature, publicKey: SchnorrPublicKey, - eventTLV: OracleEventV0TLV) - extends OracleAnnouncementTLV { + eventTLV: OracleEventV0TLV +) extends OracleAnnouncementTLV { override def tpe: BigSizeUInt = OracleAnnouncementV0TLV.tpe override val value: ByteVector = announcementSignature.bytes ++ publicKey.bytes ++ eventTLV.bytes override def validateSignature: Boolean = { - publicKey.verify(CryptoUtil - .sha256DLCAnnouncement(eventTLV.bytes) - .bytes, - announcementSignature) + publicKey.verify( + CryptoUtil + .sha256DLCAnnouncement(eventTLV.bytes) + .bytes, + announcementSignature + ) } } @@ -864,14 +899,18 @@ object OracleAnnouncementV0TLV extends TLVFactory[OracleAnnouncementV0TLV] { lazy val dummy: OracleAnnouncementV0TLV = { val dummyPrivKey: ECPrivateKey = ECPrivateKey.fromHex( - "f04671ab68f3fefbeaa344c49149748f722287a81b19cd956b2332d07b8f6853") - val event = OracleEventV0TLV(Vector(dummyPrivKey.schnorrNonce), - UInt32.zero, - EnumEventDescriptorV0TLV.dummy, - "dummy") + "f04671ab68f3fefbeaa344c49149748f722287a81b19cd956b2332d07b8f6853" + ) + val event = OracleEventV0TLV( + Vector(dummyPrivKey.schnorrNonce), + UInt32.zero, + EnumEventDescriptorV0TLV.dummy, + "dummy" + ) val sig = dummyPrivKey.schnorrSign( - CryptoUtil.sha256DLCAnnouncement(event.bytes).bytes) + CryptoUtil.sha256DLCAnnouncement(event.bytes).bytes + ) OracleAnnouncementV0TLV(sig, dummyPrivKey.schnorrPublicKey, event) } @@ -879,12 +918,14 @@ object OracleAnnouncementV0TLV extends TLVFactory[OracleAnnouncementV0TLV] { def dummyForEventsAndKeys( privKey: ECPrivateKey, nonce: SchnorrNonce, - events: Vector[EnumOutcome]): OracleAnnouncementTLV = { + events: Vector[EnumOutcome] + ): OracleAnnouncementTLV = { val event = OracleEventV0TLV( Vector(nonce), UInt32.zero, EnumEventDescriptorV0TLV(events.map(outcome => outcome.outcome)), - "dummy") + "dummy" + ) val sig = privKey.schnorrSign(CryptoUtil.sha256DLCAnnouncement(event.bytes).bytes) @@ -893,13 +934,15 @@ object OracleAnnouncementV0TLV extends TLVFactory[OracleAnnouncementV0TLV] { def dummyForKeys( privKey: ECPrivateKey, - nonces: OrderedNonces): OracleAnnouncementTLV = { - val eventDescriptor = DigitDecompositionEventDescriptorV0TLV(UInt16(2), - isSigned = - false, - nonces.length, - "dummy", - Int32.zero) + nonces: OrderedNonces + ): OracleAnnouncementTLV = { + val eventDescriptor = DigitDecompositionEventDescriptorV0TLV( + UInt16(2), + isSigned = false, + nonces.length, + "dummy", + Int32.zero + ) val event = OracleEventV0TLV(nonces.toVector, UInt32.zero, eventDescriptor, "dummy") val sig = @@ -931,17 +974,19 @@ case class OracleAttestmentV0TLV( eventId: NormalizedString, publicKey: SchnorrPublicKey, unsortedSignatures: Vector[SchnorrDigitalSignature], - outcomes: Vector[NormalizedString]) - extends OracleAttestmentTLV { + outcomes: Vector[NormalizedString] +) extends OracleAttestmentTLV { require(unsortedSignatures.nonEmpty, "Cannot have 0 signatures") require( outcomes.size == unsortedSignatures.size, - s"Number of outcomes must match number of signatures, ${outcomes.size} != ${sigs.size}") + s"Number of outcomes must match number of signatures, ${outcomes.size} != ${sigs.size}" + ) override val tpe: BigSizeUInt = OracleAttestmentV0TLV.tpe - /** This should be used very carefully with v0 attestments. We do not have a requirement in the - * in the original protocol that signatures are sorted. If you are seeing signature verification - * failing you probably need to be using [[unsortedSignatures]] rather than [[sigs]] + /** This should be used very carefully with v0 attestments. We do not have a + * requirement in the in the original protocol that signatures are sorted. If + * you are seeing signature verification failing you probably need to be + * using [[unsortedSignatures]] rather than [[sigs]] */ override val sigs: OrderedSchnorrSignatures = OrderedSchnorrSignatures.fromUnsorted(unsortedSignatures) @@ -982,10 +1027,12 @@ object OracleAttestmentV0TLV extends TLVFactory[OracleAttestmentV0TLV] { val outcome = NormalizedString("outcome") val sig = key.schnorrSign(CryptoUtil.sha256DLCAttestation(outcome).bytes) - OracleAttestmentV0TLV(eventId, - key.schnorrPublicKey, - Vector(sig), - Vector(outcome)) + OracleAttestmentV0TLV( + eventId, + key.schnorrPublicKey, + Vector(sig), + Vector(outcome) + ) } override val typeName: String = "OracleAttestmentV0TLV" @@ -1005,7 +1052,9 @@ object ContractDescriptorTLV extends TLVParentFactory[ContractDescriptorTLV] { val empty: ContractDescriptorTLV = ContractDescriptorV0TLV(Vector.empty) } -/** @see https://github.com/discreetlogcontracts/dlcspecs/blob/master/Messaging.md#version-0-contract_info */ +/** @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/master/Messaging.md#version-0-contract_info + */ case class ContractDescriptorV0TLV(outcomes: Vector[(String, Satoshis)]) extends ContractDescriptorTLV { override val tpe: BigSizeUInt = ContractDescriptorV0TLV.tpe @@ -1016,7 +1065,8 @@ case class ContractDescriptorV0TLV(outcomes: Vector[(String, Satoshis)]) { case (outcome, amt) => val outcomeBytes = CryptoUtil.serializeForHash(outcome) bigSizePrefix(outcomeBytes) ++ satBytes(amt) - }) + } + ) } } @@ -1051,7 +1101,8 @@ case class RoundingIntervalsV0TLV(intervalStarts: Vector[(Long, Satoshis)]) { case (outcome, roundingModSats) => BigSizeUInt(outcome).bytes ++ BigSizeUInt(roundingModSats.toLong).bytes - }) + } + ) } } @@ -1101,11 +1152,14 @@ object TLVPoint extends Factory[TLVPoint] { val outcome = BigSizeUInt(bytes) val value = BigSizeUInt(bytes.drop(outcome.byteSize)) val extraPrecision = UInt16( - bytes.drop(outcome.byteSize + value.byteSize).take(2)).toInt + bytes.drop(outcome.byteSize + value.byteSize).take(2) + ).toInt - TLVPoint(outcome = outcome.toLong, - value = Satoshis(value.toLong), - extraPrecision = extraPrecision) + TLVPoint( + outcome = outcome.toLong, + value = Satoshis(value.toLong), + extraPrecision = extraPrecision + ) } } @@ -1113,8 +1167,8 @@ case class OldTLVPoint( outcome: Long, value: Satoshis, extraPrecision: Int, - isEndpoint: Boolean) - extends NetworkElement { + isEndpoint: Boolean +) extends NetworkElement { lazy val leadingByte: Byte = if (isEndpoint) { 1.toByte @@ -1138,17 +1192,20 @@ object OldTLVPoint extends Factory[OldTLVPoint] { case 1 => true case b: Byte => throw new IllegalArgumentException( - s"Did not recognize leading byte: $b") + s"Did not recognize leading byte: $b" + ) } val outcome = BigSizeUInt(bytes.tail) val value = UInt64(bytes.drop(1 + outcome.byteSize).take(8)) val extraPrecision = UInt16(bytes.drop(9 + outcome.byteSize).take(2)).toInt - OldTLVPoint(outcome = outcome.toLong, - value = Satoshis(value.toLong), - extraPrecision = extraPrecision, - isEndpoint = isEndpoint) + OldTLVPoint( + outcome = outcome.toLong, + value = Satoshis(value.toLong), + extraPrecision = extraPrecision, + isEndpoint = isEndpoint + ) } } @@ -1176,7 +1233,8 @@ object PolynomialPayoutCurvePieceTLV override val tpe: BigSizeUInt = BigSizeUInt(42792) override def fromTLVValue( - value: ByteVector): PolynomialPayoutCurvePieceTLV = { + value: ByteVector + ): PolynomialPayoutCurvePieceTLV = { val iter = ValueIterator(value) val points = iter.takeU16PrefixedList(() => iter.take(TLVPoint)) @@ -1190,8 +1248,8 @@ object PolynomialPayoutCurvePieceTLV case class Signed16PTLVNumber( sign: Boolean, withoutPrecision: Long, - extraPrecision: Int) - extends NetworkElement { + extraPrecision: Int +) extends NetworkElement { lazy val toBigDecimal: BigDecimal = { val absVal = withoutPrecision + (BigDecimal(extraPrecision) / (1 << 16)) @@ -1243,8 +1301,8 @@ case class HyperbolaPayoutCurvePieceTLV( a: Signed16PTLVNumber, b: Signed16PTLVNumber, c: Signed16PTLVNumber, - d: Signed16PTLVNumber) - extends PayoutCurvePieceTLV { + d: Signed16PTLVNumber +) extends PayoutCurvePieceTLV { override val tpe: BigSizeUInt = HyperbolaPayoutCurvePieceTLV.tpe override val value: ByteVector = { @@ -1273,13 +1331,15 @@ object HyperbolaPayoutCurvePieceTLV val c = iter.take(Signed16PTLVNumber) val d = iter.take(Signed16PTLVNumber) - HyperbolaPayoutCurvePieceTLV(usePositivePiece, - translateOutcome, - translatePayout, - a, - b, - c, - d) + HyperbolaPayoutCurvePieceTLV( + usePositivePiece, + translateOutcome, + translatePayout, + a, + b, + c, + d + ) } override def typeName: String = "HyperbolaPayoutCurvePieceTLV" @@ -1292,15 +1352,18 @@ case class OldPayoutFunctionV0TLV(points: Vector[OldTLVPoint]) override val value: ByteVector = u16PrefixedList(points) } -/** @see https://github.com/discreetlogcontracts/dlcspecs/blob/8ee4bbe816c9881c832b1ce320b9f14c72e3506f/NumericOutcome.md#curve-serialization */ +/** @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/8ee4bbe816c9881c832b1ce320b9f14c72e3506f/NumericOutcome.md#curve-serialization + */ case class PayoutFunctionV0TLV( endpoints: OrderedTLVPoints, pieces: Vector[PayoutCurvePieceTLV], - serializationVersion: DLCSerializationVersion) - extends DLCSetupPieceTLV { + serializationVersion: DLCSerializationVersion +) extends DLCSetupPieceTLV { require( endpoints.length == pieces.length + 1, - s"Number of endpoints (${endpoints.length}) does not match number of pieces (${pieces.length}).") + s"Number of endpoints (${endpoints.length}) does not match number of pieces (${pieces.length})." + ) override val tpe: BigSizeUInt = PayoutFunctionV0TLV.tpe @@ -1309,7 +1372,8 @@ case class PayoutFunctionV0TLV( endpoints.toVector.init.zip(pieces), { case (leftEndpoint: TLVPoint, piece: PayoutCurvePieceTLV) => leftEndpoint.bytes ++ piece.bytes - }) ++ endpoints.toVector.last.bytes + } + ) ++ endpoints.toVector.last.bytes } def piecewisePolynomialEndpoints: Vector[PiecewisePolynomialEndpoint] = { @@ -1319,8 +1383,10 @@ case class PayoutFunctionV0TLV( override val byteSize: Long = { serializationVersion match { case DLCSerializationVersion.Alpha => - val old = OldPayoutFunctionV0TLV(endpoints.toVector.map(p => - OldTLVPoint(p.outcome, p.value, p.extraPrecision, true))) + val old = OldPayoutFunctionV0TLV( + endpoints.toVector.map(p => + OldTLVPoint(p.outcome, p.value, p.extraPrecision, true)) + ) old.byteSize case DLCSerializationVersion.Beta => super.byteSize @@ -1341,16 +1407,18 @@ object PayoutFunctionV0TLV extends TLVFactory[PayoutFunctionV0TLV] { (leftEndpoint, piece) } val rightEndpoint = iter.take(TLVPoint) - //we assume that points are in ordered when they are serialized - //if they are not, the person that serialized them is not following - //the spec + // we assume that points are in ordered when they are serialized + // if they are not, the person that serialized them is not following + // the spec val endpoints = endpointsAndPieces.map(_._1).:+(rightEndpoint) val orderedEndpoints = OrderedTLVPoints(endpoints) val pieces = endpointsAndPieces.map(_._2) - PayoutFunctionV0TLV(orderedEndpoints, - pieces, - serializationVersion = DLCSerializationVersion.Beta) + PayoutFunctionV0TLV( + orderedEndpoints, + pieces, + serializationVersion = DLCSerializationVersion.Beta + ) } t.getOrElse(oldfromTLVValue(value)) @@ -1368,8 +1436,8 @@ object PayoutFunctionV0TLV extends TLVFactory[PayoutFunctionV0TLV] { case class ContractDescriptorV1TLV( numDigits: Int, payoutFunction: PayoutFunctionV0TLV, - roundingIntervals: RoundingIntervalsV0TLV) - extends ContractDescriptorTLV { + roundingIntervals: RoundingIntervalsV0TLV +) extends ContractDescriptorTLV { override val tpe: BigSizeUInt = ContractDescriptorV1TLV.tpe val numDigitsU16: UInt16 = UInt16(numDigits) @@ -1488,8 +1556,8 @@ sealed trait OracleParamsTLV extends DLCSetupPieceTLV case class OracleParamsV0TLV( maxErrorExp: Int, minFailExp: Int, - maximizeCoverage: Boolean) - extends OracleParamsTLV { + maximizeCoverage: Boolean +) extends OracleParamsTLV { override val tpe: BigSizeUInt = OracleParamsV0TLV.tpe override val value: ByteVector = { @@ -1518,8 +1586,8 @@ object OracleParamsV0TLV extends TLVFactory[OracleParamsV0TLV] { case class OracleInfoV2TLV( threshold: Int, oracles: OrderedAnnouncements, - params: OracleParamsTLV) - extends MultiOracleInfoTLV { + params: OracleParamsTLV +) extends MultiOracleInfoTLV { override val tpe: BigSizeUInt = OracleInfoV2TLV.tpe override val value: ByteVector = { @@ -1561,8 +1629,8 @@ object ContractInfoTLV extends TLVParentFactory[ContractInfoTLV] { case class ContractInfoV0TLV( totalCollateral: Satoshis, contractDescriptor: ContractDescriptorTLV, - oracleInfo: OracleInfoTLV) - extends ContractInfoTLV { + oracleInfo: OracleInfoTLV +) extends ContractInfoTLV { override val tpe: BigSizeUInt = ContractInfoV0TLV.tpe override val value: ByteVector = { @@ -1579,7 +1647,8 @@ object ContractInfoV0TLV extends TLVFactory[ContractInfoV0TLV] { ContractInfoV0TLV( Satoshis.zero, ContractDescriptorV0TLV(Vector("dummy" -> Satoshis(10000))), - OracleInfoV0TLV(OracleAnnouncementV0TLV.dummy)) + OracleInfoV0TLV(OracleAnnouncementV0TLV.dummy) + ) } override def fromTLVValue(value: ByteVector): ContractInfoV0TLV = { @@ -1599,8 +1668,8 @@ object ContractInfoV0TLV extends TLVFactory[ContractInfoV0TLV] { case class ContractInfoV1TLV( totalCollateral: Satoshis, - contractOraclePairs: Vector[(ContractDescriptorTLV, OracleInfoTLV)]) - extends ContractInfoTLV { + contractOraclePairs: Vector[(ContractDescriptorTLV, OracleInfoTLV)] +) extends ContractInfoTLV { override val tpe: BigSizeUInt = ContractInfoV0TLV.tpe @@ -1645,8 +1714,8 @@ case class FundingInputV0TLV( prevTxVout: UInt32, sequence: UInt32, maxWitnessLen: UInt16, - redeemScriptOpt: Option[WitnessScriptPubKey]) - extends FundingInputTLV { + redeemScriptOpt: Option[WitnessScriptPubKey] +) extends FundingInputTLV { override val tpe: BigSizeUInt = FundingInputV0TLV.tpe lazy val output: TransactionOutput = prevTx.outputs(prevTxVout.toInt) @@ -1695,25 +1764,30 @@ object FundingInputV0TLV extends TLVFactory[FundingInputV0TLV] { case wspk: WitnessScriptPubKey => Some(wspk) case _: NonWitnessScriptPubKey => throw new IllegalArgumentException( - s"Redeem Script must be Segwit SPK: $redeemScript") + s"Redeem Script must be Segwit SPK: $redeemScript" + ) } - FundingInputV0TLV(serialId, - prevTx, - prevTxVout, - sequence, - maxWitnessLen, - redeemScriptOpt) + FundingInputV0TLV( + serialId, + prevTx, + prevTxVout, + sequence, + maxWitnessLen, + redeemScriptOpt + ) } override val typeName: String = "FundingInputV0TLV" - val dummy: FundingInputV0TLV = FundingInputV0TLV(UInt64.zero, - EmptyTransaction, - prevTxVout = UInt32.zero, - UInt32.zero, - UInt16.zero, - None) + val dummy: FundingInputV0TLV = FundingInputV0TLV( + UInt64.zero, + EmptyTransaction, + prevTxVout = UInt32.zero, + UInt32.zero, + UInt16.zero, + None + ) } sealed trait CETSignaturesTLV extends DLCSetupPieceTLV @@ -1732,7 +1806,7 @@ case class CETSignaturesV0TLV(sigs: Vector[ECAdaptorSignature]) super.toString } else { s"CETSignaturesV0TLV(sigs=${sigs.take( - 2)}..., omitting remainingSigs of length=${sigs.length - 2})" + 2)}..., omitting remainingSigs of length=${sigs.length - 2})" } } } @@ -1763,7 +1837,8 @@ case class FundingSignaturesV0TLV(witnesses: Vector[ScriptWitnessV0]) witnesses, { witness: ScriptWitnessV0 => u16PrefixedList[ByteVector](witness.stack.toVector.reverse, u16Prefix) - }) + } + ) } } @@ -1783,7 +1858,8 @@ object FundingSignaturesV0TLV extends TLVFactory[FundingSignaturesV0TLV] { case witness: ScriptWitnessV0 => witness case taprootWitness: TaprootWitness => throw new IllegalArgumentException( - s"Invalid witness, taproot not supported in DLC spec, got=$taprootWitness") + s"Invalid witness, taproot not supported in DLC spec, got=$taprootWitness" + ) } } @@ -1798,12 +1874,14 @@ sealed trait DLCSetupTLV extends TLV case class SendOfferTLV( peer: NormalizedString, message: NormalizedString, - offer: DLCOfferTLV) - extends DLCSetupTLV { + offer: DLCOfferTLV +) extends DLCSetupTLV { require(peer.length <= 1024, "peer length must not exceed 1024 characters") - require(message.length <= 1024, - "message length must not exceed 1024 characters") + require( + message.length <= 1024, + "message length must not exceed 1024 characters" + ) override val tpe: BigSizeUInt = SendOfferTLV.tpe @@ -1842,11 +1920,12 @@ case class DLCOfferTLV( fundOutputSerialId: UInt64, feeRate: SatoshisPerVirtualByte, contractMaturityBound: BlockTimeStamp, - contractTimeout: BlockTimeStamp) - extends DLCSetupTLV { + contractTimeout: BlockTimeStamp +) extends DLCSetupTLV { require( changeSerialId != fundOutputSerialId, - s"changeSerialId ($changeSerialId) cannot be equal to fundOutputSerialId ($fundOutputSerialId)") + s"changeSerialId ($changeSerialId) cannot be equal to fundOutputSerialId ($fundOutputSerialId)" + ) override val tpe: BigSizeUInt = DLCOfferTLV.tpe @@ -1959,8 +2038,8 @@ object NoNegotiationFieldsTLVFactory } case class NegotiationFieldsV1TLV( - roundingIntervalsV0TLV: RoundingIntervalsV0TLV) - extends NegotiationFieldsTLV { + roundingIntervalsV0TLV: RoundingIntervalsV0TLV +) extends NegotiationFieldsTLV { override val tpe: BigSizeUInt = NegotiationFieldsV1TLV.tpe override val value: ByteVector = { @@ -1983,10 +2062,11 @@ object NegotiationFieldsV1TLV extends TLVFactory[NegotiationFieldsV1TLV] { } case class NegotiationFieldsV2TLV( - nestedNegotiationFields: Vector[NegotiationFieldsTLV]) - extends NegotiationFieldsTLV { + nestedNegotiationFields: Vector[NegotiationFieldsTLV] +) extends NegotiationFieldsTLV { require( - nestedNegotiationFields.forall(!_.isInstanceOf[NegotiationFieldsV2TLV])) + nestedNegotiationFields.forall(!_.isInstanceOf[NegotiationFieldsV2TLV]) + ) override val tpe: BigSizeUInt = NegotiationFieldsV2TLV.tpe @@ -2021,8 +2101,8 @@ case class DLCAcceptTLV( changeSerialId: UInt64, cetSignatures: CETSignaturesTLV, refundSignature: ECDigitalSignature, - negotiationFields: NegotiationFieldsTLV) - extends DLCSetupTLV { + negotiationFields: NegotiationFieldsTLV +) extends DLCSetupTLV { override val tpe: BigSizeUInt = DLCAcceptTLV.tpe override val value: ByteVector = { @@ -2085,8 +2165,8 @@ case class DLCSignTLV( contractId: ByteVector, cetSignatures: CETSignaturesTLV, refundSignature: ECDigitalSignature, - fundingSignatures: FundingSignaturesTLV) - extends DLCSetupTLV { + fundingSignatures: FundingSignaturesTLV +) extends DLCSetupTLV { override val tpe: BigSizeUInt = DLCSignTLV.tpe override val value: ByteVector = { diff --git a/core/src/main/scala/org/bitcoins/core/protocol/tlv/ValueIterator.scala b/core/src/main/scala/org/bitcoins/core/protocol/tlv/ValueIterator.scala index 496c1a5144..dec8819d81 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/tlv/ValueIterator.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/tlv/ValueIterator.scala @@ -34,9 +34,9 @@ case class ValueIterator(value: ByteVector) { bytes } - /** IMPORTANT: This only works for factories which read off of - * the front of a ByteVector without consuming the whole thing. - * If this is not the case, you must specify how many bytes. + /** IMPORTANT: This only works for factories which read off of the front of a + * ByteVector without consuming the whole thing. If this is not the case, you + * must specify how many bytes. */ def take[E <: NetworkElement](factory: Factory[E]): E = { val elem = factory(current) @@ -50,8 +50,10 @@ case class ValueIterator(value: ByteVector) { } def takeBits(numBits: Int): ByteVector = { - require(numBits % 8 == 0, - s"Must take a round byte number of bits, got $numBits") + require( + numBits % 8 == 0, + s"Must take a round byte number of bits, got $numBits" + ) take(numBytes = numBits / 8) } @@ -109,7 +111,8 @@ case class ValueIterator(value: ByteVector) { case TRUE_BYTE => true case byte: Byte => throw new RuntimeException( - s"Boolean values must be 0x00 or 0x01, got $byte") + s"Boolean values must be 0x00 or 0x01, got $byte" + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/InputUtil.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/InputUtil.scala index a2dbdbc99e..f8db76247f 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/InputUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/InputUtil.scala @@ -15,9 +15,9 @@ import scala.annotation.tailrec object InputUtil { - /** Returns a valid sequence number for the given [[ScriptNumber]] - * A transaction needs a valid sequence number to spend a OP_CHECKSEQUENCEVERIFY script. - * See BIP68/112 for more information + /** Returns a valid sequence number for the given [[ScriptNumber]] A + * transaction needs a valid sequence number to spend a + * OP_CHECKSEQUENCEVERIFY script. See BIP68/112 for more information * [[https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki]] * [[https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki]] */ @@ -29,23 +29,26 @@ object InputUtil { } else { val n = scriptNum.toLong val sequence = UInt32( - n & TransactionConstants.sequenceLockTimeMask.toLong) - //set sequence number to indicate this is relative locktime + n & TransactionConstants.sequenceLockTimeMask.toLong + ) + // set sequence number to indicate this is relative locktime sequence | TransactionConstants.sequenceLockTimeTypeFlag } - /** This helper function calculates the appropriate sequence number for each transaction input. - * [[CLTVScriptPubKey]] and [[CSVScriptPubKey]]'s need certain sequence numbers on the inputs - * to make them spendable. - * See BIP68/112 and BIP65 for more info + /** This helper function calculates the appropriate sequence number for each + * transaction input. [[CLTVScriptPubKey]] and [[CSVScriptPubKey]]'s need + * certain sequence numbers on the inputs to make them spendable. See + * BIP68/112 and BIP65 for more info */ def calcSequenceForInputInfos( utxos: Seq[InputInfo], - defaultSequence: UInt32 = Policy.sequence): Seq[TransactionInput] = { + defaultSequence: UInt32 = Policy.sequence + ): Seq[TransactionInput] = { @tailrec def loop( remaining: Seq[InputInfo], - accum: Seq[TransactionInput]): Seq[TransactionInput] = + accum: Seq[TransactionInput] + ): Seq[TransactionInput] = remaining match { case Nil => accum.reverse case spendingInfo +: newRemaining => @@ -55,23 +58,30 @@ object InputUtil { case csv: CSVScriptPubKey => solveSequenceForCSV(csv.locktime) case _: CLTVScriptPubKey => UInt32.zero } - val input = TransactionInput(lockTime.outPoint, - EmptyScriptSignature, - sequence) + val input = TransactionInput( + lockTime.outPoint, + EmptyScriptSignature, + sequence + ) loop(newRemaining, input +: accum) case p2pkWithTimeout: P2PKWithTimeoutInputInfo => if (p2pkWithTimeout.isBeforeTimeout) { val input = - TransactionInput(spendingInfo.outPoint, - EmptyScriptSignature, - defaultSequence) + TransactionInput( + spendingInfo.outPoint, + EmptyScriptSignature, + defaultSequence + ) loop(newRemaining, input +: accum) } else { val sequence = solveSequenceForCSV( - p2pkWithTimeout.scriptPubKey.lockTime) - val input = TransactionInput(p2pkWithTimeout.outPoint, - EmptyScriptSignature, - sequence) + p2pkWithTimeout.scriptPubKey.lockTime + ) + val input = TransactionInput( + p2pkWithTimeout.outPoint, + EmptyScriptSignature, + sequence + ) loop(newRemaining, input +: accum) } case p2sh: P2SHInputInfo => @@ -83,11 +93,13 @@ object InputUtil { case _: P2WPKHV0InputInfo | _: UnassignedSegwitNativeInputInfo | _: P2PKInputInfo | _: P2PKHInputInfo | _: MultiSignatureInputInfo | _: EmptyInputInfo => - //none of these script types affect the sequence number of a tx so the defaultSequence is used + // none of these script types affect the sequence number of a tx so the defaultSequence is used val input = - TransactionInput(spendingInfo.outPoint, - EmptyScriptSignature, - defaultSequence) + TransactionInput( + spendingInfo.outPoint, + EmptyScriptSignature, + defaultSequence + ) loop(newRemaining, input +: accum) } } @@ -95,14 +107,15 @@ object InputUtil { loop(utxos, Nil) } - /** This helper function calculates the appropriate sequence number for each transaction input. - * [[CLTVScriptPubKey]] and [[CSVScriptPubKey]]'s need certain sequence numbers on the inputs - * to make them spendable. - * See BIP68/112 and BIP65 for more info + /** This helper function calculates the appropriate sequence number for each + * transaction input. [[CLTVScriptPubKey]] and [[CSVScriptPubKey]]'s need + * certain sequence numbers on the inputs to make them spendable. See + * BIP68/112 and BIP65 for more info */ def calcSequenceForInputs( utxos: Seq[InputSigningInfo[InputInfo]], - defaultSequence: UInt32 = Policy.sequence): Seq[TransactionInput] = { + defaultSequence: UInt32 = Policy.sequence + ): Seq[TransactionInput] = { calcSequenceForInputInfos(utxos.map(_.inputInfo), defaultSequence) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/OutputReference.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/OutputReference.scala index aa89b8f80d..ded2b6c887 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/OutputReference.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/OutputReference.scala @@ -6,8 +6,8 @@ import scodec.bits.ByteVector /** Represents a generic on-chain output */ case class OutputReference( outPoint: TransactionOutPoint, - output: TransactionOutput) - extends NetworkElement { + output: TransactionOutput +) extends NetworkElement { override def bytes: ByteVector = { outPoint.bytes ++ output.bytes diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/Transaction.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/Transaction.scala index 3fe281c6d5..69df7cb10b 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/Transaction.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/Transaction.scala @@ -12,8 +12,8 @@ import scodec.bits.ByteVector */ sealed abstract class Transaction extends NetworkElement { - /** The `sha256(sha256(tx))` of this transaction, - * Note that this is the little endian encoding of the hash, NOT the big endian encoding shown in block + /** The `sha256(sha256(tx))` of this transaction, Note that this is the little + * endian encoding of the hash, NOT the big endian encoding shown in block * explorers. See * [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation this link]] * for more info @@ -21,8 +21,8 @@ sealed abstract class Transaction extends NetworkElement { def txId: DoubleSha256Digest = CryptoUtil.doubleSHA256(bytes) /** This is the BIG ENDIAN encoding for the txid. This is commonly used for - * RPC interfaces and block explorers, this encoding is NOT used at the protocol level - * For more info see: + * RPC interfaces and block explorers, this encoding is NOT used at the + * protocol level For more info see: * [[https://bitcoin.stackexchange.com/questions/2063/why-does-the-bitcoin-protocol-use-the-little-endian-notation]] */ def txIdBE: DoubleSha256DigestBE = txId.flip @@ -39,13 +39,14 @@ sealed abstract class Transaction extends NetworkElement { /** The locktime for this transaction */ def lockTime: UInt32 - /** This is used to indicate how 'expensive' the transction is on the blockchain. - * This use to be a simple calculation before segwit (BIP141). Each byte in the transaction - * counted as 4 'weight' units. Now with segwit, the + /** This is used to indicate how 'expensive' the transction is on the + * blockchain. This use to be a simple calculation before segwit (BIP141). + * Each byte in the transaction counted as 4 'weight' units. Now with segwit, + * the * [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] - * is counted as 1 weight unit per byte, - * while other parts of the transaction (outputs, inputs, locktime etc) count as 4 weight units. - * As we add more witness versions, this may be subject to change. + * is counted as 1 weight unit per byte, while other parts of the transaction + * (outputs, inputs, locktime etc) count as 4 weight units. As we add more + * witness versions, this may be subject to change. * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#Transaction_size_calculations BIP 141]] * [[https://github.com/bitcoin/bitcoin/blob/5961b23898ee7c0af2626c46d5d70e80136578d3/src/consensus/validation.h#L96]] */ @@ -56,17 +57,20 @@ sealed abstract class Transaction extends NetworkElement { */ def vsize: Long = Math.ceil(weight / 4.0).toLong - /** Base transaction size is the size of the transaction serialised with the witness data stripped + /** Base transaction size is the size of the transaction serialised with the + * witness data stripped * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#Transaction_size_calculations]] */ def baseSize: Long = this match { case btx: NonWitnessTransaction => btx.byteSize case wtx: WitnessTransaction => - BaseTransaction(wtx.version, - wtx.inputs, - wtx.outputs, - wtx.lockTime).baseSize + BaseTransaction( + wtx.version, + wtx.inputs, + wtx.outputs, + wtx.lockTime + ).baseSize } def totalSize: Long = bytes.size @@ -82,18 +86,22 @@ sealed abstract class Transaction extends NetworkElement { case _: Int => false } - /** Updates the input at the given index and returns the new transaction with that input updated */ + /** Updates the input at the given index and returns the new transaction with + * that input updated + */ def updateInput(idx: Int, i: TransactionInput): Transaction = { val updatedInputs = inputs.updated(idx, i) this match { case _: NonWitnessTransaction => BaseTransaction(version, updatedInputs, outputs, lockTime) case wtx: WitnessTransaction => - WitnessTransaction(version, - updatedInputs, - outputs, - lockTime, - wtx.witness) + WitnessTransaction( + version, + updatedInputs, + outputs, + lockTime, + wtx.witness + ) } } @@ -108,18 +116,19 @@ object Transaction extends Factory[Transaction] { def newBuilder: RawTxBuilder = RawTxBuilder() override def fromBytes(bytes: ByteVector): Transaction = { - //see BIP141 for marker/flag bytes - //https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-id + // see BIP141 for marker/flag bytes + // https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-id val tx = { if ( bytes(4) == WitnessTransaction.marker && bytes( - 5) == WitnessTransaction.flag + 5 + ) == WitnessTransaction.flag ) { - //this throw/catch is _still_ necessary for the case where we have unsigned base transactions - //with zero inputs and 1 output which is serialized as "0001" at bytes 4 and 5. - //these transactions will not have a script witness associated with them making them invalid - //witness transactions (you need to have a witness to be considered a witness tx) - //see: https://github.com/bitcoin-s/bitcoin-s/blob/01d89df1b7c6bc4b1594406d54d5e6019705c654/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala#L88 + // this throw/catch is _still_ necessary for the case where we have unsigned base transactions + // with zero inputs and 1 output which is serialized as "0001" at bytes 4 and 5. + // these transactions will not have a script witness associated with them making them invalid + // witness transactions (you need to have a witness to be considered a witness tx) + // see: https://github.com/bitcoin-s/bitcoin-s/blob/01d89df1b7c6bc4b1594406d54d5e6019705c654/core-test/src/test/scala/org/bitcoins/core/protocol/transaction/TransactionTest.scala#L88 try { WitnessTransaction.fromBytes(bytes) } catch { @@ -153,8 +162,8 @@ case class BaseTransaction( version: Int32, inputs: Seq[TransactionInput], outputs: Seq[TransactionOutput], - lockTime: UInt32) - extends NonWitnessTransaction + lockTime: UInt32 +) extends NonWitnessTransaction object BaseTransaction extends Factory[BaseTransaction] { @@ -171,8 +180,9 @@ object BaseTransaction extends Factory[BaseTransaction] { BaseTransaction(version, inputs, outputs, lockTime) } - def unapply(tx: NonWitnessTransaction): Option[ - (Int32, Seq[TransactionInput], Seq[TransactionOutput], UInt32)] = { + def unapply( + tx: NonWitnessTransaction + ): Option[(Int32, Seq[TransactionInput], Seq[TransactionOutput], UInt32)] = { Some((tx.version, tx.inputs, tx.outputs, tx.lockTime)) } } @@ -190,14 +200,15 @@ case class WitnessTransaction( inputs: Seq[TransactionInput], outputs: Seq[TransactionOutput], lockTime: UInt32, - witness: TransactionWitness) - extends Transaction { + witness: TransactionWitness +) extends Transaction { require( inputs.length == witness.length, s"Must have same amount of inputs and witnesses in witness tx, inputs=${inputs.length} witnesses=${witness.length}" ) - /** The txId for the witness transaction from satoshi's original serialization */ + /** The txId for the witness transaction from satoshi's original serialization + */ override def txId: DoubleSha256Digest = { toBaseTx.txId } @@ -217,13 +228,14 @@ case class WitnessTransaction( toBaseTx.byteSize * 3 + byteSize } - /** Writes a [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] to a hex string - * This is unique from BaseTransaction.bytes in the fact - * that it adds a 'marker' and 'flag' to indicate that this tx is a - * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] and has extra - * witness data attached to it. - * See [[https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki BIP144]] for more info. - * Functionality inside of Bitcoin Core: + /** Writes a + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] + * to a hex string This is unique from BaseTransaction.bytes in the fact that + * it adds a 'marker' and 'flag' to indicate that this tx is a + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] + * and has extra witness data attached to it. See + * [[https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki BIP144]] + * for more info. Functionality inside of Bitcoin Core: * [[https://github.com/bitcoin/bitcoin/blob/e8cfe1ee2d01c493b758a67ad14707dca15792ea/src/primitives/transaction.h#L282-L287s]] */ override val bytes: ByteVector = { @@ -240,8 +252,10 @@ case class WitnessTransaction( } else toBaseTx.bytes } - /** Updates the [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] at the given index and - * returns a new [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] + /** Updates the + * [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] at the + * given index and returns a new + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] * with it's witness vector updated */ def updateWitness(idx: Int, scriptWit: ScriptWitness): WitnessTransaction = { @@ -252,11 +266,12 @@ case class WitnessTransaction( object WitnessTransaction extends Factory[WitnessTransaction] { - /** This read function is unique to BaseTransaction.fromBytes - * in the fact that it reads a 'marker' and 'flag' byte to indicate that this tx is a + /** This read function is unique to BaseTransaction.fromBytes in the fact that + * it reads a 'marker' and 'flag' byte to indicate that this tx is a * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]]. - * See [[https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki BIP144 ]] for more details. - * Functionality inside of Bitcoin Core: + * See + * [[https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki BIP144]] + * for more details. Functionality inside of Bitcoin Core: * [[https://github.com/bitcoin/bitcoin/blob/e8cfe1ee2d01c493b758a67ad14707dca15792ea/src/primitives/transaction.h#L244-L251]] */ override def fromBytes(bytes: ByteVector): WitnessTransaction = { @@ -265,11 +280,13 @@ object WitnessTransaction extends Factory[WitnessTransaction] { val marker = bytes(4) require( marker.toInt == 0, - "Incorrect marker for witness transaction, the marker MUST be 0 for the marker according to BIP141, got: " + marker) + "Incorrect marker for witness transaction, the marker MUST be 0 for the marker according to BIP141, got: " + marker + ) val flag = bytes(5) require( flag.toInt != 0, - "Incorrect flag for witness transaction, this must NOT be 0 according to BIP141, got: " + flag) + "Incorrect flag for witness transaction, this must NOT be 0 according to BIP141, got: " + flag + ) val txInputBytes = bytes.slice(6, bytes.size) val (inputs, outputBytes) = BytesUtil.parseCmpctSizeUIntSeq(txInputBytes, TransactionInput) @@ -285,19 +302,24 @@ object WitnessTransaction extends Factory[WitnessTransaction] { def toWitnessTx(tx: Transaction): WitnessTransaction = tx match { case btx: NonWitnessTransaction => - WitnessTransaction(btx.version, - btx.inputs, - btx.outputs, - btx.lockTime, - EmptyWitness.fromInputs(btx.inputs)) + WitnessTransaction( + btx.version, + btx.inputs, + btx.outputs, + btx.lockTime, + EmptyWitness.fromInputs(btx.inputs) + ) case wtx: WitnessTransaction => wtx } val marker: Byte = 0.toByte val flag: Byte = 1.toByte - /** These bytes -- at index 4 & 5 in a witness transaction -- are used to indicate a witness tx - * @see BIP141 https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-id + /** These bytes -- at index 4 & 5 in a witness transaction -- are used to + * indicate a witness tx + * @see + * BIP141 + * https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-id */ val witBytes: ByteVector = ByteVector(marker, flag) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionConstants.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionConstants.scala index 4674e2ea4f..4aea376a01 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionConstants.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionConstants.scala @@ -14,29 +14,31 @@ trait TransactionConstants { lazy val disableRBFSequence = sequence - UInt32.one lazy val enableRBFSequence: UInt32 = sequence - UInt32.two - /** If bit (1 << 31) of the sequence number is set, - * then no consensus meaning is applied to the sequence number and can be included - * in any block under all currently possible circumstances. - * @return the mask that ben used with a bitwise and to indicate if the sequence number has any meaning + /** If bit (1 << 31) of the sequence number is set, then no consensus meaning + * is applied to the sequence number and can be included in any block under + * all currently possible circumstances. + * @return + * the mask that ben used with a bitwise and to indicate if the sequence + * number has any meaning */ def locktimeDisabledFlag: UInt32 = UInt32(1L << 31) - /** If a transaction's input's sequence number encodes a relative lock-time, this mask is - * applied to extract that lock-time from the sequence field. + /** If a transaction's input's sequence number encodes a relative lock-time, + * this mask is applied to extract that lock-time from the sequence field. */ def sequenceLockTimeMask: UInt32 = UInt32(0x0000ffff) def fullSequenceLockTimeMask: UInt32 = sequenceLockTimeTypeFlag | sequenceLockTimeMask - /** If the transaction input sequence number encodes a relative lock-time and this flag - * is set, the relative lock-time has units of 512 seconds, + /** If the transaction input sequence number encodes a relative lock-time and + * this flag is set, the relative lock-time has units of 512 seconds, * otherwise it specifies blocks with a granularity of 1. */ def sequenceLockTimeTypeFlag: UInt32 = UInt32(1L << 22) - /** Threshold for nLockTime: below this value it is interpreted as block number, - * otherwise as UNIX timestamp. + /** Threshold for nLockTime: below this value it is interpreted as block + * number, otherwise as UNIX timestamp. */ def locktimeThreshold: UInt32 = UInt32(500000000) } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionInput.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionInput.scala index 5ae80e4858..3ab488d0f0 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionInput.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionInput.scala @@ -6,8 +6,8 @@ import org.bitcoins.core.serializers.transaction.RawTransactionInputParser import org.bitcoins.crypto.{DoubleSha256DigestBE, Factory, NetworkElement} import scodec.bits.ByteVector -/** Created by chris on 12/26/15. - * Algebraic data type that represents a transaction input +/** Created by chris on 12/26/15. Algebraic data type that represents a + * transaction input */ sealed abstract class TransactionInput extends NetworkElement { @@ -24,8 +24,8 @@ case object EmptyTransactionInput extends TransactionInput { override def sequence = TransactionConstants.sequence } -/** This represents a coinbase input - these always have a EmptyTransactionOutPoint - * and arbitrary data inside the script signature +/** This represents a coinbase input - these always have a + * EmptyTransactionOutPoint and arbitrary data inside the script signature */ sealed abstract class CoinbaseInput extends TransactionInput { override def previousOutput = EmptyTransactionOutPoint @@ -36,21 +36,25 @@ object TransactionInput extends Factory[TransactionInput] { private case class TransactionInputImpl( previousOutput: TransactionOutPoint, scriptSignature: ScriptSignature, - sequence: UInt32) - extends TransactionInput + sequence: UInt32 + ) extends TransactionInput def empty: TransactionInput = EmptyTransactionInput - /** Generates a transaction input from the provided txid and output index. - * A script signature can also be provided, this defaults to an empty signature. + /** Generates a transaction input from the provided txid and output index. A + * script signature can also be provided, this defaults to an empty + * signature. */ def fromTxidAndVout( txid: DoubleSha256DigestBE, vout: UInt32, - signature: ScriptSignature = ScriptSignature.empty): TransactionInput = { + signature: ScriptSignature = ScriptSignature.empty + ): TransactionInput = { val outpoint = TransactionOutPoint(txid, vout) - TransactionInput(outPoint = outpoint, - scriptSignature = signature, - sequenceNumber = TransactionConstants.sequence) + TransactionInput( + outPoint = outpoint, + scriptSignature = signature, + sequenceNumber = TransactionConstants.sequence + ) } @@ -60,7 +64,8 @@ object TransactionInput extends Factory[TransactionInput] { def apply( outPoint: TransactionOutPoint, scriptSignature: ScriptSignature, - sequenceNumber: UInt32): TransactionInput = + sequenceNumber: UInt32 + ): TransactionInput = outPoint match { case EmptyTransactionOutPoint => CoinbaseInput(scriptSignature, sequenceNumber) @@ -74,16 +79,20 @@ object CoinbaseInput { private case class CoinbaseInputImpl( scriptSignature: ScriptSignature, - sequence: UInt32) - extends CoinbaseInput + sequence: UInt32 + ) extends CoinbaseInput /** Creates a coinbase input - coinbase inputs always have an empty outpoint - * @param scriptSignature this can contain anything, miners use this to signify support for various protocol BIPs - * @return the coinbase input + * @param scriptSignature + * this can contain anything, miners use this to signify support for + * various protocol BIPs + * @return + * the coinbase input */ def apply( scriptSignature: ScriptSignature, - sequence: UInt32): CoinbaseInput = { + sequence: UInt32 + ): CoinbaseInput = { CoinbaseInputImpl(scriptSignature, sequence) } } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutPoint.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutPoint.scala index 9bf93afc6d..34bd1062a5 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutPoint.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutPoint.scala @@ -5,8 +5,10 @@ import org.bitcoins.core.serializers.transaction.RawTransactionOutPointParser import org.bitcoins.crypto._ import scodec.bits._ -/** @param txId The transaction id for the crediting transaction for this input - * @param vout The output index in the parent transaction for the output we are spending +/** @param txId + * The transaction id for the crediting transaction for this input + * @param vout + * The output index in the parent transaction for the output we are spending */ case class TransactionOutPoint(txId: DoubleSha256Digest, vout: UInt32) extends NetworkElement { @@ -38,12 +40,16 @@ case class TransactionOutPoint(txId: DoubleSha256Digest, vout: UInt32) /** UInt32s cannot hold negative numbers, but sometimes the Bitcoin Protocol * requires the vout to be -1, which is serialized as `0xFFFFFFFF`. * - * @see [[https://github.com/bitcoin/bitcoin/blob/d612837814020ae832499d18e6ee5eb919a87907/src/primitives/transaction.h transaction.h]] - * @see http://stackoverflow.com/questions/2711522/what-happens-if-i-assign-a-negative-value-to-an-unsigned-variable + * @see + * [[https://github.com/bitcoin/bitcoin/blob/d612837814020ae832499d18e6ee5eb919a87907/src/primitives/transaction.h transaction.h]] + * @see + * http://stackoverflow.com/questions/2711522/what-happens-if-i-assign-a-negative-value-to-an-unsigned-variable */ final object EmptyTransactionOutPoint - extends TransactionOutPoint(txId = DoubleSha256Digest.empty, - vout = UInt32.max) { + extends TransactionOutPoint( + txId = DoubleSha256Digest.empty, + vout = UInt32.max + ) { override def toString(): String = "EmptyTransactionOutPoint" } @@ -54,8 +60,11 @@ object TransactionOutPoint def fromBytes(bytes: ByteVector): TransactionOutPoint = RawTransactionOutPointParser.read(bytes) - /** @param txId The transaction id for the crediting transaction for this input - * @param vout The output index in the parent transaction for the output we are spending + /** @param txId + * The transaction id for the crediting transaction for this input + * @param vout + * The output index in the parent transaction for the output we are + * spending */ def apply(txId: DoubleSha256DigestBE, vout: UInt32): TransactionOutPoint = { TransactionOutPoint(txId.flip, vout) diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutput.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutput.scala index 2821a61105..3cf4c8a104 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutput.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionOutput.scala @@ -12,8 +12,10 @@ case class TransactionOutput(value: CurrencyUnit, scriptPubKey: ScriptPubKey) } final object EmptyTransactionOutput - extends TransactionOutput(CurrencyUnits.negativeSatoshi, - ScriptPubKey.empty) { + extends TransactionOutput( + CurrencyUnits.negativeSatoshi, + ScriptPubKey.empty + ) { override def toString(): String = "EmptyTransactionOutput" } diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionWitness.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionWitness.scala index 7cea0748b7..ad2b4abb17 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionWitness.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TransactionWitness.scala @@ -6,8 +6,9 @@ import org.bitcoins.core.util.{BytesUtil, SeqWrapper} import org.bitcoins.crypto.NetworkElement import scodec.bits.ByteVector -/** Created by chris on 11/21/16. - * The witness data for [[org.bitcoins.core.protocol.script.ScriptSignature ScriptSignature]] in this transaction +/** Created by chris on 11/21/16. The witness data for + * [[org.bitcoins.core.protocol.script.ScriptSignature ScriptSignature]] in + * this transaction * [[https://github.com/bitcoin/bitcoin/blob/b4e4ba475a5679e09f279aaf2a83dcf93c632bdb/src/primitives/transaction.h#L232-L268]] */ sealed abstract class TransactionWitness @@ -20,8 +21,8 @@ sealed abstract class TransactionWitness RawTransactionWitnessParser.write(this) } - /** Update the `witnesses` index to the given witness - * Pads the witnesses vector if needed to accomodate the new witness + /** Update the `witnesses` index to the given witness Pads the witnesses + * vector if needed to accomodate the new witness */ def updated(index: Int, witness: ScriptWitness): TransactionWitness = { val scriptWits: Vector[ScriptWitness] = { @@ -38,10 +39,9 @@ sealed abstract class TransactionWitness TransactionWitness(scriptWits) } - /** Pads the existing `witnesses` so that we can insert a witness - * into the given index. If `witnesses` is not properly padded - * we can have an index out of bounds exception thrown - * when trying to update the vector. + /** Pads the existing `witnesses` so that we can insert a witness into the + * given index. If `witnesses` is not properly padded we can have an index + * out of bounds exception thrown when trying to update the vector. */ private def padScriptWitness(index: Int): Vector[ScriptWitness] = { val neededPadding = index - witnesses.size + 1 @@ -55,11 +55,14 @@ sealed abstract class TransactionWitness } } -/** Each input (even if it does not spend a segwit output) needs to have a witness associated with it - * in a [[WitnessTransaction]]. This helper case class is used to "fill in" [[EmptyScriptWitness]] for - * the inputs that do not spend a [[org.bitcoins.core.protocol.script.WitnessScriptPubKeyV0 WitnessScriptPubKeyV0]] +/** Each input (even if it does not spend a segwit output) needs to have a + * witness associated with it in a [[WitnessTransaction]]. This helper case + * class is used to "fill in" [[EmptyScriptWitness]] for the inputs that do not + * spend a + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKeyV0 WitnessScriptPubKeyV0]] * - * @see https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#specification + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#specification */ case class EmptyWitness(witnesses: Vector[EmptyScriptWitness.type]) extends TransactionWitness @@ -88,21 +91,26 @@ object TransactionWitness { if (witnesses.exists(_ != EmptyScriptWitness)) { TransactionWitnessImpl(witnesses) } else { - //means that everything must be a empty ScriptWitness + // means that everything must be a empty ScriptWitness EmptyWitness.fromN(witnesses.length) } } - /** Creates a [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] from a + /** Creates a + * [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] + * from a * [[org.bitcoins.core.protocol.script.ScriptWitness Seq[Option[ScriptWitness]]. * This constructor is for convinience if a certain input does not spend a * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] * It simply transforms the `None` types to - * [[org.bitcoins.core.protocol.script.EmptyScriptWitness EmptyScriptWitness]] and then calls the normal - * [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] constructor + * [[org.bitcoins.core.protocol.script.EmptyScriptWitness EmptyScriptWitness]] + * and then calls the normal + * [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] + * constructor */ def fromWitOpt( - witnesses: Vector[Option[ScriptWitness]]): TransactionWitness = { + witnesses: Vector[Option[ScriptWitness]] + ): TransactionWitness = { val replaced: Vector[ScriptWitness] = witnesses.map { case Some(wit) => wit case None => EmptyScriptWitness diff --git a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TxUtil.scala b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TxUtil.scala index d6f544a3c7..fdf6705dc3 100644 --- a/core/src/main/scala/org/bitcoins/core/protocol/transaction/TxUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/protocol/transaction/TxUtil.scala @@ -23,12 +23,14 @@ object TxUtil { def isRBFEnabled(transaction: Transaction): Boolean = { transaction.inputs.exists( - _.sequence < TransactionConstants.disableRBFSequence) + _.sequence < TransactionConstants.disableRBFSequence + ) } private def computeNextLockTime( currentLockTimeOpt: Option[UInt32], - locktime: Long): Try[UInt32] = { + locktime: Long + ): Try[UInt32] = { val lockTimeT = if (locktime > UInt32.max.toLong || locktime < 0) { TxBuilderError.IncompatibleLockTimes @@ -41,15 +43,15 @@ object TxUtil { if ( currentLockTime < lockTimeThreshold && lockTime >= lockTimeThreshold ) { - //means that we spend two different locktime types, one of the outputs spends a - //OP_CLTV script by block height, the other spends one by time stamp + // means that we spend two different locktime types, one of the outputs spends a + // OP_CLTV script by block height, the other spends one by time stamp TxBuilderError.IncompatibleLockTimes } else Success(lockTime) } else if ( currentLockTime >= lockTimeThreshold && lockTime < lockTimeThreshold ) { - //means that we spend two different locktime types, one of the outputs spends a - //OP_CLTV script by block height, the other spends one by time stamp + // means that we spend two different locktime types, one of the outputs spends a + // OP_CLTV script by block height, the other spends one by time stamp TxBuilderError.IncompatibleLockTimes } else { Success(currentLockTime) @@ -59,16 +61,17 @@ object TxUtil { } } - /** This helper function calculates the appropriate locktime for a transaction. - * To be able to spend [[CLTVScriptPubKey]]'s you need to have the transaction's - * locktime set to the same value (or higher) than the output it is spending. - * See BIP65 for more info + /** This helper function calculates the appropriate locktime for a + * transaction. To be able to spend [[CLTVScriptPubKey]]'s you need to have + * the transaction's locktime set to the same value (or higher) than the + * output it is spending. See BIP65 for more info */ def calcLockTimeForInfos(utxos: Seq[InputInfo]): Try[UInt32] = { @tailrec def loop( remaining: Seq[InputInfo], - currentLockTimeOpt: Option[UInt32]): Try[UInt32] = + currentLockTimeOpt: Option[UInt32] + ): Try[UInt32] = remaining match { case Nil => Success(currentLockTimeOpt.getOrElse(TransactionConstants.lockTime)) @@ -79,8 +82,10 @@ object TxUtil { case _: CSVScriptPubKey => loop(newRemaining, currentLockTimeOpt) case cltv: CLTVScriptPubKey => - val result = computeNextLockTime(currentLockTimeOpt, - cltv.locktime.toLong) + val result = computeNextLockTime( + currentLockTimeOpt, + cltv.locktime.toLong + ) result match { case Success(newLockTime) => @@ -94,7 +99,8 @@ object TxUtil { } else { val result = computeNextLockTime( currentLockTimeOpt, - p2pkWithTimeout.scriptPubKey.lockTime.toLong) + p2pkWithTimeout.scriptPubKey.lockTime.toLong + ) result match { case Success(newLockTime) => @@ -107,8 +113,10 @@ object TxUtil { case p2wsh: P2WSHV0InputInfo => loop(p2wsh.nestedInputInfo +: newRemaining, currentLockTimeOpt) case conditional: ConditionalInputInfo => - loop(conditional.nestedInputInfo +: newRemaining, - currentLockTimeOpt) + loop( + conditional.nestedInputInfo +: newRemaining, + currentLockTimeOpt + ) case _: P2WPKHV0InputInfo | _: UnassignedSegwitNativeInputInfo | _: P2PKInputInfo | _: P2PKHInputInfo | _: MultiSignatureInputInfo | _: EmptyInputInfo => @@ -120,10 +128,10 @@ object TxUtil { loop(utxos, None) } - /** This helper function calculates the appropriate locktime for a transaction. - * To be able to spend [[CLTVScriptPubKey]]'s you need to have the transaction's - * locktime set to the same value (or higher) than the output it is spending. - * See BIP65 for more info + /** This helper function calculates the appropriate locktime for a + * transaction. To be able to spend [[CLTVScriptPubKey]]'s you need to have + * the transaction's locktime set to the same value (or higher) than the + * output it is spending. See BIP65 for more info */ def calcLockTime(utxos: Seq[InputSigningInfo[InputInfo]]): Try[UInt32] = { calcLockTimeForInfos(utxos.map(_.inputInfo)) @@ -131,20 +139,25 @@ object TxUtil { def buildDummyTx( utxos: Vector[InputInfo], - outputs: Vector[TransactionOutput]): Transaction = { + outputs: Vector[TransactionOutput] + ): Transaction = { val dummySpendingInfos = utxos.map { inputInfo => val mockSigners = inputInfo.pubKeys.take(inputInfo.requiredSigs).map(Sign.dummySign) - inputInfo.toSpendingInfo(EmptyTransaction, - mockSigners, - HashType.sigHashAll) + inputInfo.toSpendingInfo( + EmptyTransaction, + mockSigners, + HashType.sigHashAll + ) } val dummyInputs = utxos.map { inputInfo => - TransactionInput(inputInfo.outPoint, - EmptyScriptSignature, - Policy.sequence) + TransactionInput( + inputInfo.outPoint, + EmptyScriptSignature, + Policy.sequence + ) } val txBuilder = RawTxBuilder() ++= dummyInputs ++= outputs @@ -152,15 +165,17 @@ object TxUtil { val utx = withFinalizer.buildTx() - RawTxSigner.sign(utx, - dummySpendingInfos, - RawTxSigner.emptyInvariant, - dummySign = true) + RawTxSigner.sign( + utx, + dummySpendingInfos, + RawTxSigner.emptyInvariant, + dummySign = true + ) } /** Inserts script signatures and (potentially) witness data to a given - * transaction using DummyECDigitalSignatures for all sigs in order - * to produce a transaction roughly the size of the expected fully signed + * transaction using DummyECDigitalSignatures for all sigs in order to + * produce a transaction roughly the size of the expected fully signed * transaction. Useful during fee estimation. * * Note that the resulting dummy-signed Transaction will have populated @@ -168,20 +183,25 @@ object TxUtil { */ def addDummySigs( utx: Transaction, - inputInfos: Vector[InputInfo]): Transaction = { + inputInfos: Vector[InputInfo] + ): Transaction = { val dummyInputAndWitnesses = inputInfos.zipWithIndex.map { case (inputInfo, index) => val mockSigners = inputInfo.pubKeys.take(inputInfo.requiredSigs).map { pubKey => - Sign(_ => DummyECDigitalSignature, - (_, _) => DummyECDigitalSignature, - pubKey) + Sign( + _ => DummyECDigitalSignature, + (_, _) => DummyECDigitalSignature, + pubKey + ) } val mockSpendingInfo = - inputInfo.toSpendingInfo(EmptyTransaction, - mockSigners, - HashType.sigHashAll) + inputInfo.toSpendingInfo( + EmptyTransaction, + mockSigners, + HashType.sigHashAll + ) val tx = BitcoinSigner @@ -196,7 +216,8 @@ object TxUtil { case wit: ScriptWitnessV0 => Some(wit) case taprootWitness: TaprootWitness => throw new UnsupportedOperationException( - s"Taproot not supported, got=$taprootWitness") + s"Taproot not supported, got=$taprootWitness" + ) } } @@ -213,30 +234,38 @@ object TxUtil { } } - /** Sets the ScriptSignature for every input in the given transaction to an EmptyScriptSignature - * as well as sets the witness to an EmptyWitness - * @param tx Transaction to empty signatures - * @return Transaction with no signatures + /** Sets the ScriptSignature for every input in the given transaction to an + * EmptyScriptSignature as well as sets the witness to an EmptyWitness + * @param tx + * Transaction to empty signatures + * @return + * Transaction with no signatures */ def emptyAllScriptSigs(tx: Transaction): Transaction = { val newInputs = tx.inputs.map { input => - TransactionInput(input.previousOutput, - EmptyScriptSignature, - input.sequence) + TransactionInput( + input.previousOutput, + EmptyScriptSignature, + input.sequence + ) } tx match { case btx: NonWitnessTransaction => - BaseTransaction(version = btx.version, - inputs = newInputs, - outputs = btx.outputs, - lockTime = btx.lockTime) + BaseTransaction( + version = btx.version, + inputs = newInputs, + outputs = btx.outputs, + lockTime = btx.lockTime + ) case wtx: WitnessTransaction => - WitnessTransaction(version = wtx.version, - inputs = newInputs, - outputs = wtx.outputs, - lockTime = wtx.lockTime, - witness = EmptyWitness.fromInputs(newInputs)) + WitnessTransaction( + version = wtx.version, + inputs = newInputs, + outputs = wtx.outputs, + lockTime = wtx.lockTime, + witness = EmptyWitness.fromInputs(newInputs) + ) } } @@ -245,7 +274,8 @@ object TxUtil { isSigned: Boolean, inputInfos: Vector[InputInfo], expectedFeeRate: FeeUnit, - tx: Transaction): Try[Unit] = { + tx: Transaction + ): Try[Unit] = { val dustT = if (isSigned) { sanityDustCheck(tx) } else { @@ -270,14 +300,15 @@ object TxUtil { } } - /** Checks that the creditingAmount >= destinationAmount - * and then does a sanity check on the transaction's fee + /** Checks that the creditingAmount >= destinationAmount and then does a + * sanity check on the transaction's fee */ def sanityAmountChecks( isSigned: Boolean, inputInfos: Vector[InputInfo], expectedFeeRate: FeeUnit, - tx: Transaction): Try[Unit] = { + tx: Transaction + ): Try[Unit] = { val spentAmount = tx.outputs.foldLeft(CurrencyUnits.zero)(_ + _.value) val creditingAmount = inputInfos.foldLeft(CurrencyUnits.zero)(_ + _.amount) @@ -298,31 +329,35 @@ object TxUtil { /** Checks if the fee is within a 'valid' range * - * @param estimatedFee the estimated amount of fee we should pay - * @param actualFee the actual amount of fee the transaction pays - * @param feeRate the fee rate in satoshis/vbyte we paid per byte on this tx + * @param estimatedFee + * the estimated amount of fee we should pay + * @param actualFee + * the actual amount of fee the transaction pays + * @param feeRate + * the fee rate in satoshis/vbyte we paid per byte on this tx * @return */ def isValidFeeRange( estimatedFee: CurrencyUnit, actualFee: CurrencyUnit, - feeRate: FeeUnit): Try[Unit] = { + feeRate: FeeUnit + ): Try[Unit] = { if (estimatedFee == actualFee) { Success(()) } else { - //what the number '40' represents is the allowed variance -- in bytes -- between the size of the two - //versions of signed tx. I believe the two signed version can vary in size because the digital - //signature might have changed in size. It could become larger or smaller depending on the digital - //signatures produced. + // what the number '40' represents is the allowed variance -- in bytes -- between the size of the two + // versions of signed tx. I believe the two signed version can vary in size because the digital + // signature might have changed in size. It could become larger or smaller depending on the digital + // signatures produced. - //Personally I think 40 seems like a little high. As you shouldn't vary more than a 2 bytes per input in the tx i think? - //bumping for now though as I don't want to spend time debugging - //I think there is something incorrect that errors to the low side of fee estimation - //for p2sh(p2wpkh) txs + // Personally I think 40 seems like a little high. As you shouldn't vary more than a 2 bytes per input in the tx i think? + // bumping for now though as I don't want to spend time debugging + // I think there is something incorrect that errors to the low side of fee estimation + // for p2sh(p2wpkh) txs - //See this link for more info on variance in size on ECDigitalSignatures - //https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm + // See this link for more info on variance in size on ECDigitalSignatures + // https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm val acceptableVariance = 40 * feeRate.toLong val min = Satoshis(-acceptableVariance) @@ -338,10 +373,12 @@ object TxUtil { } } - /** Adds the signingInfo's scriptWitness from the transaction, if it has one */ + /** Adds the signingInfo's scriptWitness from the transaction, if it has one + */ def addWitnessData( tx: Transaction, - signingInfo: InputSigningInfo[InputInfo]): WitnessTransaction = { + signingInfo: InputSigningInfo[InputInfo] + ): WitnessTransaction = { val noWitnessWtx = WitnessTransaction.toWitnessTx(tx) val indexOpt = tx.inputs.zipWithIndex @@ -353,7 +390,8 @@ object TxUtil { (scriptWitnessOpt, indexOpt) match { case (_, None) => throw new IllegalArgumentException( - s"Input is not contained in tx, got $signingInfo") + s"Input is not contained in tx, got $signingInfo" + ) case (None, Some(_)) => noWitnessWtx case (Some(scriptWitness), Some(index)) => @@ -367,7 +405,8 @@ object TxUtil { case Some(index) => index case None => throw new IllegalArgumentException( - s"The transaction did not contain the expected outPoint (${inputInfo.outPoint}), got $tx") + s"The transaction did not contain the expected outPoint (${inputInfo.outPoint}), got $tx" + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBT.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBT.scala index 42a13b2d73..50fdb519b9 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBT.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBT.scala @@ -21,14 +21,16 @@ import scala.util.{Failure, Success, Try} case class PSBT( globalMap: GlobalPSBTMap, inputMaps: Vector[InputPSBTMap], - outputMaps: Vector[OutputPSBTMap]) - extends NetworkElement { + outputMaps: Vector[OutputPSBTMap] +) extends NetworkElement { require( inputMaps.size == transaction.inputs.size, - s"There must be an input map for every input in the global transaction, inputs: ${transaction.inputs}") + s"There must be an input map for every input in the global transaction, inputs: ${transaction.inputs}" + ) require( outputMaps.size == transaction.outputs.size, - s"There must be an output map for every output in the global transaction, outputs: ${transaction.outputs}") + s"There must be an output map for every output in the global transaction, outputs: ${transaction.outputs}" + ) require( inputMaps.zip(transaction.inputs).forall { case (inputMap, txIn) => @@ -72,8 +74,10 @@ case class PSBT( def validateBIP143Vulnerability: PSBT = { require( isFinalized || inputMaps.size == 1 || inputMaps.forall( - !_.isBIP143Vulnerable), - "One or more of the input maps are susceptible to the BIP 143 vulnerability") + !_.isBIP143Vulnerable + ), + "One or more of the input maps are susceptible to the BIP 143 vulnerability" + ) this } @@ -140,15 +144,20 @@ case class PSBT( } } - /** Combiner defined by https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#combiner - * Takes another PSBT and adds all records that are not contained in this PSBT - * A record's distinctness is determined by its key - * @param other PSBT to be combined with - * @return A PSBT with the combined data of the two PSBTs + /** Combiner defined by + * https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#combiner + * Takes another PSBT and adds all records that are not contained in this + * PSBT A record's distinctness is determined by its key + * @param other + * PSBT to be combined with + * @return + * A PSBT with the combined data of the two PSBTs */ def combinePSBT(other: PSBT): PSBT = { - require(this.transaction.txId == other.transaction.txId, - "Can only combine PSBTs with the same global transaction.") + require( + this.transaction.txId == other.transaction.txId, + "Can only combine PSBTs with the same global transaction." + ) val global = this.globalMap.combine(other.globalMap) val inputs = this.inputMaps @@ -166,8 +175,10 @@ case class PSBT( } def finalizeInput(index: Int): Try[PSBT] = { - require(index >= 0 && index < inputMaps.size, - s"Index must be within 0 and the number of inputs, got: $index") + require( + index >= 0 && index < inputMaps.size, + s"Index must be within 0 and the number of inputs, got: $index" + ) val inputMap = inputMaps(index) if (inputMap.isFinalized) { Success(this) @@ -182,13 +193,16 @@ case class PSBT( } /** Finalizes this PSBT if possible, returns a Failure otherwise - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#input-finalizer]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#input-finalizer]] */ def finalizePSBT: Try[PSBT] = { if (isFinalized) { Failure( new IllegalStateException( - s"Cannot finalize an already finalized PSBT: $this")) + s"Cannot finalize an already finalized PSBT: $this" + ) + ) } else { val finalizedInputTs = inputMaps.zip(transaction.inputs).map { case (inputMap, input) => inputMap.finalize(input) @@ -209,65 +223,88 @@ case class PSBT( } } - /** Signs the PSBT's input at the given input with the signer, then adds it to the PSBT - * in a PartialSignature record - * @param inputIndex Index of input to sign - * @param signer Function or private key used to sign the PSBT - * @param conditionalPath Represents the spending branch being taken in a ScriptPubKey's execution - * @param isDummySignature Do not sign the tx for real, just use a dummy signature, this is useful for fee estimation + /** Signs the PSBT's input at the given input with the signer, then adds it to + * the PSBT in a PartialSignature record + * @param inputIndex + * Index of input to sign + * @param signer + * Function or private key used to sign the PSBT + * @param conditionalPath + * Represents the spending branch being taken in a ScriptPubKey's execution + * @param isDummySignature + * Do not sign the tx for real, just use a dummy signature, this is useful + * for fee estimation * @return */ def sign( inputIndex: Int, signer: Sign, conditionalPath: ConditionalPath = ConditionalPath.NoCondition, - isDummySignature: Boolean = false): PSBT = { + isDummySignature: Boolean = false + ): PSBT = { require( inputMaps.size == 1 || !inputMaps(inputIndex).isBIP143Vulnerable, "This input map is susceptible to the BIP 143 vulnerability, add the non-witness utxo to be safe" ) - BitcoinSigner.sign(psbt = this, - inputIndex = inputIndex, - signer = signer, - conditionalPath = conditionalPath, - isDummySignature = isDummySignature) + BitcoinSigner.sign( + psbt = this, + inputIndex = inputIndex, + signer = signer, + conditionalPath = conditionalPath, + isDummySignature = isDummySignature + ) } - /** Takes the InputPSBTMap at the given index and returns a NewSpendingInfoFull - * that can be used to sign the input - * @param index index of the InputPSBTMap - * @param signers Signers that will be used to sign the input - * @param conditionalPath Path that should be used for the script - * @return A corresponding NewSpendingInfoFull + /** Takes the InputPSBTMap at the given index and returns a + * NewSpendingInfoFull that can be used to sign the input + * @param index + * index of the InputPSBTMap + * @param signers + * Signers that will be used to sign the input + * @param conditionalPath + * Path that should be used for the script + * @return + * A corresponding NewSpendingInfoFull */ def getSpendingInfoUsingSigners( index: Int, signers: Vector[Sign], - conditionalPath: ConditionalPath = - ConditionalPath.NoCondition): ScriptSignatureParams[InputInfo] = { - require(index >= 0 && index < inputMaps.size, - s"Index must be within 0 and the number of inputs, got: $index") + conditionalPath: ConditionalPath = ConditionalPath.NoCondition + ): ScriptSignatureParams[InputInfo] = { + require( + index >= 0 && index < inputMaps.size, + s"Index must be within 0 and the number of inputs, got: $index" + ) inputMaps(index) - .toUTXOSatisfyingInfoUsingSigners(transaction.inputs(index), - signers, - conditionalPath) + .toUTXOSatisfyingInfoUsingSigners( + transaction.inputs(index), + signers, + conditionalPath + ) } /** Adds tx to the indexed InputPSBTMap to either the NonWitnessOrUnknownUTXO - * or WitnessUTXO field depending on the tx and available information in the PSBT - * @param tx Transaction to add to PSBT - * @param index index of the InputPSBTMap to add tx to - * @return PSBT with added tx + * or WitnessUTXO field depending on the tx and available information in the + * PSBT + * @param tx + * Transaction to add to PSBT + * @param index + * index of the InputPSBTMap to add tx to + * @return + * PSBT with added tx */ def addUTXOToInput(tx: Transaction, index: Int): PSBT = { require( index < inputMaps.size, - s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}") + s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}" + ) val inputMap = inputMaps(index) - require(!inputMap.isFinalized, - s"Cannot update an InputPSBTMap that is finalized, index: $index") + require( + !inputMap.isFinalized, + s"Cannot update an InputPSBTMap that is finalized, index: $index" + ) val txIn = transaction.inputs(index) val elements = @@ -294,11 +331,13 @@ case class PSBT( inputMap.filterRecords(WitnessUTXOKeyId) :+ WitnessUTXO(out) } else { inputMap.filterRecords( - NonWitnessUTXOKeyId) :+ NonWitnessOrUnknownUTXO(tx) + NonWitnessUTXOKeyId + ) :+ NonWitnessOrUnknownUTXO(tx) } } else { throw new IllegalArgumentException( - s"Transaction does not correspond to map at given index($index), got: $tx") + s"Transaction does not correspond to map at given index($index), got: $tx" + ) } val newInputMaps = @@ -307,21 +346,30 @@ case class PSBT( } - /** Adds the TransactionOutput to the indexed InputPSBTMap to the WitnessUTXO field - * @param output TransactionOutput to add to PSBT - * @param index index of the InputPSBTMap to add tx to - * @return PSBT with added tx + /** Adds the TransactionOutput to the indexed InputPSBTMap to the WitnessUTXO + * field + * @param output + * TransactionOutput to add to PSBT + * @param index + * index of the InputPSBTMap to add tx to + * @return + * PSBT with added tx */ def addWitnessUTXOToInput(output: TransactionOutput, index: Int): PSBT = { - require(WitnessScriptPubKey.isValidAsm(output.scriptPubKey.asm), - s"Given output was not a Witness UTXO: $output") + require( + WitnessScriptPubKey.isValidAsm(output.scriptPubKey.asm), + s"Given output was not a Witness UTXO: $output" + ) require( index < inputMaps.size, - s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}") + s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}" + ) val inputMap = inputMaps(index) - require(!inputMap.isFinalized, - s"Cannot update an InputPSBTMap that is finalized, index: $index") + require( + !inputMap.isFinalized, + s"Cannot update an InputPSBTMap that is finalized, index: $index" + ) val elements = inputMap.filterRecords(WitnessUTXOKeyId) :+ WitnessUTXO(output) @@ -330,20 +378,28 @@ case class PSBT( PSBT(globalMap, newInputMaps, outputMaps) } - /** Adds script to the indexed InputPSBTMap to either the RedeemScript - * or WitnessScript field depending on the script and available information in the PSBT - * @param script ScriptPubKey to add to PSBT - * @param index index of the InputPSBTMap to add script to - * @return PSBT with added script + /** Adds script to the indexed InputPSBTMap to either the RedeemScript or + * WitnessScript field depending on the script and available information in + * the PSBT + * @param script + * ScriptPubKey to add to PSBT + * @param index + * index of the InputPSBTMap to add script to + * @return + * PSBT with added script */ def addRedeemOrWitnessScriptToInput( script: ScriptPubKey, - index: Int): PSBT = { + index: Int + ): PSBT = { require( index < inputMaps.size, - s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}") - require(!inputMaps(index).isFinalized, - s"Cannot update an InputPSBTMap that is finalized, index: $index") + s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}" + ) + require( + !inputMaps(index).isFinalized, + s"Cannot update an InputPSBTMap that is finalized, index: $index" + ) val inputMap = inputMaps(index) @@ -357,7 +413,8 @@ case class PSBT( .WitnessScript(script.asInstanceOf[RawScriptPubKey]) } else { inputMap.filterRecords(RedeemScriptKeyId) :+ InputPSBTRecord.RedeemScript( - script) + script + ) } val newMap = InputPSBTMap(elements).compressMap(transaction.inputs(index)) val newInputMaps = inputMaps.updated(index, newMap) @@ -367,13 +424,15 @@ case class PSBT( private def redeemScriptToOutputRecord( outputScript: ScriptPubKey, - redeemScript: ScriptPubKey): OutputPSBTRecord = { + redeemScript: ScriptPubKey + ): OutputPSBTRecord = { outputScript match { case p2sh: P2SHScriptPubKey => val scriptHash = P2SHScriptPubKey(redeemScript).scriptHash if (scriptHash != p2sh.scriptHash) { throw new IllegalArgumentException( - s"The given script's hash does not match the expected script has, got: $scriptHash, expected ${p2sh.scriptHash}") + s"The given script's hash does not match the expected script has, got: $scriptHash, expected ${p2sh.scriptHash}" + ) } else { OutputPSBTRecord.RedeemScript(redeemScript) } @@ -385,12 +444,14 @@ case class PSBT( _: TaprootScriptPubKey | _: UnassignedWitnessScriptPubKey | _: P2WSHWitnessSPKV0) => throw new IllegalArgumentException( - s"Cannot make p2wsh from non raw spk=$nonraw") + s"Cannot make p2wsh from non raw spk=$nonraw" + ) } } if (scriptHash != p2wsh.scriptHash) { throw new IllegalArgumentException( - s"The given script's hash does not match the expected script has, got: $scriptHash, expected ${p2wsh.scriptHash}") + s"The given script's hash does not match the expected script has, got: $scriptHash, expected ${p2wsh.scriptHash}" + ) } else { OutputPSBTRecord.WitnessScript(redeemScript) } @@ -400,23 +461,31 @@ case class PSBT( _: P2PKWithTimeoutScriptPubKey | _: WitnessScriptPubKey | _: P2PKScriptPubKey | _: P2PKHScriptPubKey => throw new IllegalArgumentException( - s"Output script does not need a redeem script, got: $outputScript") + s"Output script does not need a redeem script, got: $outputScript" + ) } } def addScriptWitnessToInput( scriptWitness: ScriptWitness, - index: Int): PSBT = { - require(index >= 0, - s"index must be greater than or equal to 0, got: $index") + index: Int + ): PSBT = { + require( + index >= 0, + s"index must be greater than or equal to 0, got: $index" + ) require( index < inputMaps.size, - s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}") - require(!inputMaps(index).isFinalized, - s"Cannot update an InputPSBTMap that is finalized, index: $index") + s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}" + ) + require( + !inputMaps(index).isFinalized, + s"Cannot update an InputPSBTMap that is finalized, index: $index" + ) require( inputMaps(index).witnessScriptOpt.isEmpty, - s"Input map already contains a ScriptWitness: ${inputMaps(index).witnessScriptOpt.get}") + s"Input map already contains a ScriptWitness: ${inputMaps(index).witnessScriptOpt.get}" + ) val previousElements = inputMaps(index).elements @@ -430,10 +499,12 @@ case class PSBT( InputPSBTMap(previousElements :+ newElement) case taprootWitness: TaprootWitness => throw new UnsupportedOperationException( - s"Taproot not supported, got=$taprootWitness") + s"Taproot not supported, got=$taprootWitness" + ) case EmptyScriptWitness => throw new IllegalArgumentException( - s"Invalid scriptWitness given, got: $scriptWitness") + s"Invalid scriptWitness given, got: $scriptWitness" + ) } val newInputMaps = inputMaps.updated(index, newMap) PSBT(globalMap, newInputMaps, outputMaps) @@ -442,14 +513,20 @@ case class PSBT( def addFinalizedScriptWitnessToInput( scriptSignature: ScriptSignature, scriptWitness: ScriptWitness, - index: Int): PSBT = { - require(index >= 0, - s"index must be greater than or equal to 0, got: $index") + index: Int + ): PSBT = { + require( + index >= 0, + s"index must be greater than or equal to 0, got: $index" + ) require( index < inputMaps.size, - s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}") - require(!inputMaps(index).isFinalized, - s"Cannot update an InputPSBTMap that is finalized, index: $index") + s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}" + ) + require( + !inputMaps(index).isFinalized, + s"Cannot update an InputPSBTMap that is finalized, index: $index" + ) val prevInput = inputMaps(index) @@ -468,29 +545,38 @@ case class PSBT( s"Input already contains fields: ${prevInput.elements}" ) - val finalizedScripts = Vector(FinalizedScriptSig(scriptSignature), - FinalizedScriptWitness(scriptWitness)) + val finalizedScripts = Vector( + FinalizedScriptSig(scriptSignature), + FinalizedScriptWitness(scriptWitness) + ) // Replace RedeemScripts with FinalizedScriptSignatures and add FinalizedScriptWitnesses val records = prevInput.elements.filterNot( - _.isInstanceOf[RedeemScript]) ++ finalizedScripts + _.isInstanceOf[RedeemScript] + ) ++ finalizedScripts val newMap = InputPSBTMap(records) val newInputMaps = inputMaps.updated(index, newMap) PSBT(globalMap, newInputMaps, outputMaps) } - /** Adds script to the indexed OutputPSBTMap to either the RedeemScript - * or WitnessScript field depending on the script and available information in the PSBT - * @param script ScriptPubKey to add to PSBT - * @param index index of the OutputPSBTMap to add script to - * @return PSBT with added script + /** Adds script to the indexed OutputPSBTMap to either the RedeemScript or + * WitnessScript field depending on the script and available information in + * the PSBT + * @param script + * ScriptPubKey to add to PSBT + * @param index + * index of the OutputPSBTMap to add script to + * @return + * PSBT with added script */ def addRedeemOrWitnessScriptToOutput( script: ScriptPubKey, - index: Int): PSBT = { + index: Int + ): PSBT = { require( index < outputMaps.size, - s"index must be less than the number of output maps present in the psbt, $index >= ${outputMaps.size}") + s"index must be less than the number of output maps present in the psbt, $index >= ${outputMaps.size}" + ) require(!isFinalized, "Cannot update a PSBT that is finalized") val outputMap = outputMaps(index) @@ -503,8 +589,10 @@ case class PSBT( if (!isWitScript && hasWitScript) redeemScriptToOutputRecord(redeemScriptOpt.get, script) else - redeemScriptToOutputRecord(transaction.outputs(index).scriptPubKey, - script) + redeemScriptToOutputRecord( + transaction.outputs(index).scriptPubKey, + script + ) val newMap = OutputPSBTMap(outputMap.elements :+ newElement) val newOutputMaps = outputMaps.updated(index, newMap) @@ -514,16 +602,21 @@ case class PSBT( def addScriptWitnessToOutput( scriptWitness: ScriptWitness, - index: Int): PSBT = { - require(index >= 0, - s"index must be greater than or equal to 0, got: $index") + index: Int + ): PSBT = { + require( + index >= 0, + s"index must be greater than or equal to 0, got: $index" + ) require( index < outputMaps.size, - s"index must be less than the number of output maps present in the psbt, $index >= ${inputMaps.size}") + s"index must be less than the number of output maps present in the psbt, $index >= ${inputMaps.size}" + ) require(!isFinalized, "Cannot update a PSBT that is finalized") require( outputMaps(index).witnessScriptOpt.isEmpty, - s"Output map already contains a ScriptWitness: ${outputMaps(index).witnessScriptOpt.get}") + s"Output map already contains a ScriptWitness: ${outputMaps(index).witnessScriptOpt.get}" + ) val outputMap = outputMaps(index) @@ -535,13 +628,16 @@ case class PSBT( case p2wsh: P2WSHWitnessV0 => OutputPSBTMap( outputMap.filterRecords(PSBTOutputKeyId.WitnessScriptKeyId) :+ - OutputPSBTRecord.WitnessScript(p2wsh.redeemScript)) + OutputPSBTRecord.WitnessScript(p2wsh.redeemScript) + ) case taprootWitness: TaprootWitness => throw new UnsupportedOperationException( - s"Taproot not supported, got=$taprootWitness") + s"Taproot not supported, got=$taprootWitness" + ) case EmptyScriptWitness => throw new IllegalArgumentException( - s"Invalid scriptWitness given, got: $scriptWitness") + s"Invalid scriptWitness given, got: $scriptWitness" + ) } val newOutputMaps = outputMaps.updated(index, newMap) @@ -550,7 +646,9 @@ case class PSBT( private def addKeyPathToMap[ RecordType <: PSBTRecord, - MapType <: PSBTMap[RecordType]]( + MapType <: PSBTMap[ + RecordType + ]]( extKey: ExtKey, path: BIP32Path, pubKey: ECPublicKey, @@ -558,10 +656,12 @@ case class PSBT( keyIdByte: Byte, maps: Vector[MapType], makeRecord: (ECPublicKey, ByteVector, BIP32Path) => RecordType, - makeMap: Vector[RecordType] => MapType): Vector[MapType] = { + makeMap: Vector[RecordType] => MapType + ): Vector[MapType] = { require( index < maps.size, - s"index must be less than the number of output maps present in the psbt, $index >= ${outputMaps.size}") + s"index must be less than the number of output maps present in the psbt, $index >= ${outputMaps.size}" + ) require(!isFinalized, "Cannot update a PSBT that is finalized") val previousElements = maps(index).elements @@ -584,17 +684,23 @@ case class PSBT( maps.updated(index, makeMap(elements)) } - /** Adds the BIP32Path to the indexed InputPSBTMap to the BIP32DerivationPath field - * @param extKey ExtKey to derive key from - * @param path path of key to add to PSBT - * @param index index of the InputPSBTMap to add the BIP32Path to - * @return PSBT with added BIP32Path + /** Adds the BIP32Path to the indexed InputPSBTMap to the BIP32DerivationPath + * field + * @param extKey + * ExtKey to derive key from + * @param path + * path of key to add to PSBT + * @param index + * index of the InputPSBTMap to add the BIP32Path to + * @return + * PSBT with added BIP32Path */ def addKeyPathToInput( extKey: ExtKey, path: BIP32Path, pubKey: ECPublicKey, - index: Int): PSBT = { + index: Int + ): PSBT = { val newInputMaps = addKeyPathToMap[InputPSBTRecord, InputPSBTMap]( extKey = extKey, path = path, @@ -609,17 +715,23 @@ case class PSBT( PSBT(globalMap, newInputMaps, outputMaps) } - /** Adds the BIP32Path to the indexed OutputPSBTMap to the BIP32DerivationPath field - * @param extKey ExtKey to derive key from - * @param path path of key to add to PSBT - * @param index index of the OutputPSBTMap to add the BIP32Path to - * @return PSBT with added BIP32Path + /** Adds the BIP32Path to the indexed OutputPSBTMap to the BIP32DerivationPath + * field + * @param extKey + * ExtKey to derive key from + * @param path + * path of key to add to PSBT + * @param index + * index of the OutputPSBTMap to add the BIP32Path to + * @return + * PSBT with added BIP32Path */ def addKeyPathToOutput( extKey: ExtKey, path: BIP32Path, pubKey: ECPublicKey, - index: Int): PSBT = { + index: Int + ): PSBT = { val newOutputMaps = addKeyPathToMap[OutputPSBTRecord, OutputPSBTMap]( extKey = extKey, path = path, @@ -634,16 +746,22 @@ case class PSBT( PSBT(globalMap, inputMaps, newOutputMaps) } - /** @param hashType HashType to add to the input - * @param index index of the InputPSBTMap to add the HashType to - * @return PSBT with added HashType + /** @param hashType + * HashType to add to the input + * @param index + * index of the InputPSBTMap to add the HashType to + * @return + * PSBT with added HashType */ def addSigHashTypeToInput(hashType: HashType, index: Int): PSBT = { require( index < inputMaps.size, - s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}") - require(!inputMaps(index).isFinalized, - s"Cannot update an InputPSBTMap that is finalized, index: $index") + s"index must be less than the number of input maps present in the psbt, $index >= ${inputMaps.size}" + ) + require( + !inputMaps(index).isFinalized, + s"Cannot update an InputPSBTMap that is finalized, index: $index" + ) val newElements = inputMaps(index).filterRecords(SigHashTypeKeyId) :+ SigHashType(hashType) @@ -656,7 +774,8 @@ case class PSBT( def addSignature( pubKey: ECPublicKey, sig: ECDigitalSignature, - inputIndex: Int): PSBT = + inputIndex: Int + ): PSBT = addSignature(PartialSignature(pubKey, sig), inputIndex) def addSignature(partialSignature: PartialSignature, inputIndex: Int): PSBT = @@ -665,13 +784,16 @@ case class PSBT( /** Adds all the PartialSignatures to the input map at the given index */ def addSignatures( partialSignatures: Vector[PartialSignature], - inputIndex: Int): PSBT = { + inputIndex: Int + ): PSBT = { require( inputIndex < inputMaps.size, - s"index must be less than the number of input maps present in the psbt, $inputIndex >= ${inputMaps.size}") + s"index must be less than the number of input maps present in the psbt, $inputIndex >= ${inputMaps.size}" + ) require( !inputMaps(inputIndex).isFinalized, - s"Cannot update an InputPSBTMap that is finalized, index: $inputIndex") + s"Cannot update an InputPSBTMap that is finalized, index: $inputIndex" + ) val intersect = inputMaps(inputIndex).partialSignatures.intersect(partialSignatures) val allSigs = inputMaps(inputIndex).partialSignatures ++ partialSignatures @@ -702,7 +824,8 @@ case class PSBT( witnessUTXO.witnessUTXO case None => throw new IllegalStateException( - "Cannot get previous output for input without previous transaction or witness UTXO") + "Cannot get previous output for input without previous transaction or witness UTXO" + ) } } @@ -724,16 +847,18 @@ case class PSBT( utxoOpt match { case Some(utxo) => val output = utxo.transactionSpent.outputs( - transaction.inputs(index).previousOutput.vout.toInt) + transaction.inputs(index).previousOutput.vout.toInt + ) output.scriptPubKey match { case _: RawScriptPubKey => None case _: P2SHScriptPubKey => inputMap.finalizedScriptSigOpt match { case Some( - FinalizedScriptSig(scriptSig: P2SHScriptSignature)) => + FinalizedScriptSig(scriptSig: P2SHScriptSignature) + ) => scriptSig.redeemScript match { case _: NonWitnessScriptPubKey => None - case _: WitnessScriptPubKey => Some(WitnessUTXO(output)) + case _: WitnessScriptPubKey => Some(WitnessUTXO(output)) } case None | Some(_) => None } @@ -806,15 +931,19 @@ case class PSBT( inputMaps.zipWithIndex.foldLeft(Try(extractTransaction)) { case (txT, (inputMap, index)) => txT.flatMap { tx => - BitcoinScriptUtil.verifyPSBTInputScript(tx = tx, - inputMap = inputMap, - index = index, - outputMap = outputMap) + BitcoinScriptUtil.verifyPSBTInputScript( + tx = tx, + inputMap = inputMap, + index = index, + outputMap = outputMap + ) } } } - /** @see [[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#transaction-extractor]] */ + /** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#transaction-extractor]] + */ def extractTransaction: Transaction = { if (isFinalized) { val newInputs = @@ -831,35 +960,39 @@ case class PSBT( .exists(_.isInstanceOf[FinalizedScriptWitness]) ) { val witness = inputMaps.zipWithIndex.foldLeft[TransactionWitness]( - EmptyWitness.fromInputs(transaction.inputs)) { - case (witness, (inputMap, index)) => - inputMap.finalizedScriptWitnessOpt match { - case None => witness - case Some( - InputPSBTRecord.FinalizedScriptWitness(scriptWitness)) => - witness.updated(index, scriptWitness) - } + EmptyWitness.fromInputs(transaction.inputs) + ) { case (witness, (inputMap, index)) => + inputMap.finalizedScriptWitnessOpt match { + case None => witness + case Some(InputPSBTRecord.FinalizedScriptWitness(scriptWitness)) => + witness.updated(index, scriptWitness) + } } - WitnessTransaction(transaction.version, - newInputs, - transaction.outputs, - transaction.lockTime, - witness) + WitnessTransaction( + transaction.version, + newInputs, + transaction.outputs, + transaction.lockTime, + witness + ) } else { transaction match { case btx: NonWitnessTransaction => BaseTransaction(btx.version, newInputs, btx.outputs, btx.lockTime) case wtx: WitnessTransaction => - WitnessTransaction(wtx.version, - newInputs, - wtx.outputs, - wtx.lockTime, - wtx.witness) + WitnessTransaction( + wtx.version, + newInputs, + wtx.outputs, + wtx.lockTime, + wtx.witness + ) } } } else { throw new IllegalStateException( - "PSBT must be finalized in order to extract") + "PSBT must be finalized in order to extract" + ) } } } @@ -884,14 +1017,17 @@ object PSBT extends Factory[PSBT] with StringFactory[PSBT] { PSBT(base64) case None => throw new IllegalArgumentException( - s"String given must be in base64 or hexadecimal, got: $str") + s"String given must be in base64 or hexadecimal, got: $str" + ) } } } override def fromBytes(bytes: ByteVector): PSBT = { - require(bytes.startsWith(magicBytes), - s"A PSBT must start with the magic bytes $magicBytes, got: $bytes") + require( + bytes.startsWith(magicBytes), + s"A PSBT must start with the magic bytes $magicBytes, got: $bytes" + ) val globalBytes = bytes.drop(magicBytes.size) @@ -904,38 +1040,47 @@ object PSBT extends Factory[PSBT] with StringFactory[PSBT] { bytes: ByteVector, numMaps: Int, accum: Vector[MapType], - factory: Factory[MapType]): Vector[MapType] = { + factory: Factory[MapType] + ): Vector[MapType] = { if (numMaps <= 0 || bytes.isEmpty) { accum } else { val newMap = factory.fromBytes(bytes) - mapLoop(bytes.drop(newMap.bytes.size), - numMaps - 1, - accum :+ newMap, - factory) + mapLoop( + bytes.drop(newMap.bytes.size), + numMaps - 1, + accum :+ newMap, + factory + ) } } val inputBytes = globalBytes.drop(global.bytes.size) - val inputMaps = mapLoop[InputPSBTMap](inputBytes, - tx.inputs.size, - Vector.empty, - InputPSBTMap) + val inputMaps = mapLoop[InputPSBTMap]( + inputBytes, + tx.inputs.size, + Vector.empty, + InputPSBTMap + ) val outputBytes = inputBytes.drop(inputMaps.foldLeft(0)(_ + _.bytes.size.toInt)) - val outputMaps = mapLoop[OutputPSBTMap](outputBytes, - tx.outputs.size, - Vector.empty, - OutputPSBTMap) + val outputMaps = mapLoop[OutputPSBTMap]( + outputBytes, + tx.outputs.size, + Vector.empty, + OutputPSBTMap + ) val remainingBytes = outputBytes.drop(outputMaps.foldLeft(0)(_ + _.bytes.size.toInt)) - require(remainingBytes.isEmpty, - s"The PSBT should be empty now, got: $remainingBytes") + require( + remainingBytes.isEmpty, + s"The PSBT should be empty now, got: $remainingBytes" + ) PSBT(global, inputMaps, outputMaps) } @@ -944,18 +1089,23 @@ object PSBT extends Factory[PSBT] with StringFactory[PSBT] { ByteVector.fromBase64(base64) match { case None => throw new IllegalArgumentException( - s"String given was not in base64 format, got: $base64") + s"String given was not in base64 format, got: $base64" + ) case Some(bytes) => fromBytes(bytes) } } /** Creates an empty PSBT with only the global transaction record filled - * @param unsignedTx global transaction for the PSBT - * @return Created PSBT + * @param unsignedTx + * global transaction for the PSBT + * @return + * Created PSBT */ def fromUnsignedTx(unsignedTx: Transaction): PSBT = { - require(unsignedTx.inputs.forall(_.scriptSignature == EmptyScriptSignature), - s"The transaction must not have any signatures, got: $unsignedTx") + require( + unsignedTx.inputs.forall(_.scriptSignature == EmptyScriptSignature), + s"The transaction must not have any signatures, got: $unsignedTx" + ) val btx = unsignedTx match { case wtx: WitnessTransaction => @@ -963,7 +1113,8 @@ object PSBT extends Factory[PSBT] with StringFactory[PSBT] { case base: NonWitnessTransaction => base } val globalMap = GlobalPSBTMap( - Vector(GlobalPSBTRecord.UnsignedTransaction(btx))) + Vector(GlobalPSBTRecord.UnsignedTransaction(btx)) + ) val inputMaps = unsignedTx.inputs.map(_ => InputPSBTMap.empty).toVector val outputMaps = unsignedTx.outputs.map(_ => OutputPSBTMap.empty).toVector @@ -973,9 +1124,11 @@ object PSBT extends Factory[PSBT] with StringFactory[PSBT] { def fromUnsignedTxWithP2SHScript(tx: Transaction): PSBT = { val inputs = tx.inputs.toVector val utxInputs = inputs.map { input => - TransactionInput(input.previousOutput, - EmptyScriptSignature, - input.sequence) + TransactionInput( + input.previousOutput, + EmptyScriptSignature, + input.sequence + ) } val utx = BaseTransaction(tx.version, utxInputs, tx.outputs, tx.lockTime) val psbt = fromUnsignedTx(utx) @@ -998,28 +1151,34 @@ object PSBT extends Factory[PSBT] with StringFactory[PSBT] { */ def fromUnsignedTxAndInputs( unsignedTx: Transaction, - spendingInfoAndNonWitnessTxs: Vector[ - ScriptSignatureParams[InputInfo]]): PSBT = { - fromUnsignedTxAndInputs(unsignedTx, - spendingInfoAndNonWitnessTxs, - finalized = false) + spendingInfoAndNonWitnessTxs: Vector[ScriptSignatureParams[InputInfo]] + ): PSBT = { + fromUnsignedTxAndInputs( + unsignedTx, + spendingInfoAndNonWitnessTxs, + finalized = false + ) } - /** Constructs a finalized PSBT from an - * unsigned transaction and a SpendingInfoAndNonWitnessTxs + /** Constructs a finalized PSBT from an unsigned transaction and a + * SpendingInfoAndNonWitnessTxs */ def finalizedFromUnsignedTxAndInputs( unsignedTx: Transaction, - spendingInfos: Vector[ScriptSignatureParams[InputInfo]]): PSBT = { + spendingInfos: Vector[ScriptSignatureParams[InputInfo]] + ): PSBT = { fromUnsignedTxAndInputs(unsignedTx, spendingInfos, finalized = true) } private def fromUnsignedTxAndInputs( unsignedTx: Transaction, spendingInfos: Vector[ScriptSignatureParams[InputInfo]], - finalized: Boolean): PSBT = { - require(spendingInfos.length == unsignedTx.inputs.length, - "Must have a SpendingInfo for every input") + finalized: Boolean + ): PSBT = { + require( + spendingInfos.length == unsignedTx.inputs.length, + "Must have a SpendingInfo for every input" + ) require( spendingInfos.zip(unsignedTx.inputs).forall { case (info, input) => info.outPoint == input.previousOutput @@ -1034,7 +1193,8 @@ object PSBT extends Factory[PSBT] with StringFactory[PSBT] { } val globalMap = GlobalPSBTMap( - Vector(GlobalPSBTRecord.UnsignedTransaction(btx))) + Vector(GlobalPSBTRecord.UnsignedTransaction(btx)) + ) val inputMaps = spendingInfos.map { info => if (finalized) { InputPSBTMap.finalizedFromSpendingInfo(info, unsignedTx) diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBTKeyId.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBTKeyId.scala index 5a291f1c07..f99c1ed690 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBTKeyId.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBTKeyId.scala @@ -3,8 +3,8 @@ package org.bitcoins.core.psbt import org.bitcoins.crypto.Factory import scodec.bits.ByteVector -/** A PSBTKeyId refers to the first byte of a key that signifies which kind of key-value map - * is in a given PSBTRecord +/** A PSBTKeyId refers to the first byte of a key that signifies which kind of + * key-value map is in a given PSBTRecord */ sealed trait PSBTKeyId { def byte: Byte diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBTMap.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBTMap.scala index 808477065f..09f400a500 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBTMap.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBTMap.scala @@ -14,8 +14,10 @@ import scala.annotation.tailrec import scala.util.{Failure, Success, Try} sealed trait PSBTMap[+RecordType <: PSBTRecord] extends NetworkElement { - require(elements.map(_.key).groupBy(identity).values.forall(_.length == 1), - s"All keys must be unique. Got: $elements") + require( + elements.map(_.key).groupBy(identity).values.forall(_.length == 1), + s"All keys must be unique. Got: $elements" + ) def elements: Vector[RecordType] @@ -26,7 +28,8 @@ sealed trait PSBTMap[+RecordType <: PSBTRecord] extends NetworkElement { protected def getRecords[KeyIdType <: PSBTKeyId]( key: KeyIdType, - keyIdFactory: PSBTKeyIdFactory[KeyIdType]): Vector[key.RecordType] = { + keyIdFactory: PSBTKeyIdFactory[KeyIdType] + ): Vector[key.RecordType] = { elements .filter(element => keyIdFactory.fromByte(element.key.head) == key) .asInstanceOf[Vector[key.RecordType]] @@ -34,13 +37,15 @@ sealed trait PSBTMap[+RecordType <: PSBTRecord] extends NetworkElement { protected def filterRecords[KeyIdType <: PSBTKeyId]( key: KeyIdType, - keyIdFactory: PSBTKeyIdFactory[KeyIdType]): Vector[RecordType] = { + keyIdFactory: PSBTKeyIdFactory[KeyIdType] + ): Vector[RecordType] = { elements .filterNot(element => keyIdFactory.fromByte(element.key.head) == key) } protected def distinctByKey[rType <: PSBTRecord]( - records: Vector[rType]): Vector[rType] = { + records: Vector[rType] + ): Vector[rType] = { records.groupBy(_.key).map(_._2.head).toVector } } @@ -51,7 +56,9 @@ object PSBTMap { sealed trait PSBTMapFactory[ RecordType <: PSBTRecord, - MapType <: PSBTMap[RecordType]] + MapType <: PSBTMap[ + RecordType + ]] extends Factory[MapType] { def recordFactory: Factory[RecordType] @@ -63,7 +70,8 @@ sealed trait PSBTMapFactory[ @tailrec def loop( remainingBytes: ByteVector, - accum: Vector[RecordType]): Vector[RecordType] = { + accum: Vector[RecordType] + ): Vector[RecordType] = { if (remainingBytes.head == PSBTMap.separatorByte) { accum } else { @@ -83,8 +91,10 @@ case class GlobalPSBTMap(elements: Vector[GlobalPSBTRecord]) with PSBTMap[GlobalPSBTRecord] { import org.bitcoins.core.psbt.GlobalPSBTRecord._ import org.bitcoins.core.psbt.PSBTGlobalKeyId._ - require(getRecords(UnsignedTransactionKeyId).nonEmpty, - "A GlobalPSBTMap must have a Unsigned Transaction") + require( + getRecords(UnsignedTransactionKeyId).nonEmpty, + "A GlobalPSBTMap must have a Unsigned Transaction" + ) override val wrapped: Vector[GlobalPSBTRecord] = elements def unsignedTransaction: UnsignedTransaction = { @@ -107,9 +117,12 @@ case class GlobalPSBTMap(elements: Vector[GlobalPSBTRecord]) super.filterRecords(key, PSBTGlobalKeyId) } - /** Takes another GlobalPSBTMap and adds all records that are not contained in this GlobalPSBTMap - * @param other GlobalPSBTMap to be combined with - * @return A GlobalPSBTMap with the combined data of the two GlobalPSBTMaps + /** Takes another GlobalPSBTMap and adds all records that are not contained in + * this GlobalPSBTMap + * @param other + * GlobalPSBTMap to be combined with + * @return + * A GlobalPSBTMap with the combined data of the two GlobalPSBTMaps */ def combine(other: GlobalPSBTMap): GlobalPSBTMap = { require( @@ -122,11 +135,13 @@ case class GlobalPSBTMap(elements: Vector[GlobalPSBTRecord]) // https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#version-numbers if (this.version.version > other.version.version) { val newElements = distinctByKey( - this.elements ++ other.filterRecords(VersionKeyId)) + this.elements ++ other.filterRecords(VersionKeyId) + ) GlobalPSBTMap(newElements) } else if (this.version.version < other.version.version) { val newElements = distinctByKey( - this.filterRecords(VersionKeyId) ++ other.elements) + this.filterRecords(VersionKeyId) ++ other.elements + ) GlobalPSBTMap(newElements) } else { val newElements = distinctByKey(this.elements ++ other.elements) @@ -180,7 +195,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) /** The previous output for this input * - * @param vout The vout from the input's out point + * @param vout + * The vout from the input's out point */ def prevOutOpt(vout: Int): Option[TransactionOutput] = { witnessUTXOOpt match { @@ -196,14 +212,16 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) } // todo maybe rethink return type - /** The HASH160 of each public key that could be used to sign the input, - * if calculable. [[Sha256Hash160Digest]] is used because we won't know the - * raw public key for P2PKH scripts + /** The HASH160 of each public key that could be used to sign the input, if + * calculable. [[Sha256Hash160Digest]] is used because we won't know the raw + * public key for P2PKH scripts * - * @param spk The [[ScriptPubKey]] of the script to calculate from + * @param spk + * The [[ScriptPubKey]] of the script to calculate from */ private def missingSigsFromScript( - spk: ScriptPubKey): Vector[Sha256Hash160Digest] = { + spk: ScriptPubKey + ): Vector[Sha256Hash160Digest] = { spk match { case spk: TaprootScriptPubKey => leafScriptOpt match { @@ -263,11 +281,12 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) } } - /** The HASH160 of each public key that could be used to sign the input, - * if calculable. [[Sha256Hash160Digest]] is used because we won't know the - * raw public key for P2PKH scripts + /** The HASH160 of each public key that could be used to sign the input, if + * calculable. [[Sha256Hash160Digest]] is used because we won't know the raw + * public key for P2PKH scripts * - * @param vout The vout from the input's out point + * @param vout + * The vout from the input's out point */ def missingSignatures(vout: Int): Vector[Sha256Hash160Digest] = { prevOutOpt(vout) match { @@ -357,7 +376,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) def isFinalized: Boolean = getRecords(FinalizedScriptSigKeyId).nonEmpty || getRecords( - FinalizedScriptWitnessKeyId).nonEmpty + FinalizedScriptWitnessKeyId + ).nonEmpty def isBIP143Vulnerable: Boolean = { if ( @@ -391,7 +411,9 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) case (None, None) => Failure( new IllegalStateException( - s"Cannot finalize without UTXO record: $this")) + s"Cannot finalize without UTXO record: $this" + ) + ) case (Some(witnessUtxo), _) => Success(witnessUtxo.witnessUTXO.scriptPubKey) case (_, Some(utxo)) => @@ -407,10 +429,13 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) /** Finalizes this input if possible, returning None if not */ private def finalize(spkToSatisfy: ScriptPubKey): Try[InputPSBTMap] = { - /** Removes non-utxo and non-unkown records, replacing them with finalized records */ + /** Removes non-utxo and non-unkown records, replacing them with finalized + * records + */ def wipeAndAdd( scriptSig: ScriptSignature, - witnessOpt: Option[ScriptWitness] = None): InputPSBTMap = { + witnessOpt: Option[ScriptWitness] = None + ): InputPSBTMap = { val utxos = getRecords(WitnessUTXOKeyId) ++ getRecords(NonWitnessUTXOKeyId) val unknowns = @@ -427,20 +452,26 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) InputPSBTMap(records) } - /** Turns the required PartialSignatures into a ScriptSignature and calls wipeAndAdd - * @return None if the requirement is not met + /** Turns the required PartialSignatures into a ScriptSignature and calls + * wipeAndAdd + * @return + * None if the requirement is not met */ def collectSigs( required: Int, - constructScriptSig: Seq[PartialSignature] => ScriptSignature): Try[ - InputPSBTMap] = { + constructScriptSig: Seq[PartialSignature] => ScriptSignature + ): Try[InputPSBTMap] = { val sigs = getRecords(PartialSignatureKeyId) if (sigs.length != required) { - Failure(new IllegalArgumentException( - s"Could not collect $required signatures when only the following were present: $sigs")) + Failure( + new IllegalArgumentException( + s"Could not collect $required signatures when only the following were present: $sigs" + ) + ) } else { val scriptSig = constructScriptSig( - sigs.map(sig => PartialSignature(sig.pubKey, sig.signature))) + sigs.map(sig => PartialSignature(sig.pubKey, sig.signature)) + ) val newInputMap = wipeAndAdd(scriptSig) @@ -454,7 +485,9 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) case None => Failure( new IllegalStateException( - s"Cannot finalize the following input because $reason: $this")) + s"Cannot finalize the following input because $reason: $this" + ) + ) } } @@ -489,7 +522,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) val scriptSig = EmptyScriptSignature wipeAndAdd( scriptSig, - Some(P2WSHWitnessV0(redeemScript, nestedScriptSig.scriptSig))) + Some(P2WSHWitnessV0(redeemScript, nestedScriptSig.scriptSig)) + ) } } case _: P2WPKHWitnessSPKV0 => @@ -505,76 +539,98 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) getRecords(PartialSignatureKeyId).headOption toTry(sigOpt, "there is no partial signature record").flatMap { sig => if (sig.pubKey == p2pkWithTimeout.pubKey) { - val scriptSig = P2PKWithTimeoutScriptSignature(beforeTimeout = true, - signature = - sig.signature) + val scriptSig = P2PKWithTimeoutScriptSignature( + beforeTimeout = true, + signature = sig.signature + ) Success(wipeAndAdd(scriptSig, None)) } else if (sig.pubKey == p2pkWithTimeout.timeoutPubKey) { val scriptSig = - P2PKWithTimeoutScriptSignature(beforeTimeout = false, - signature = sig.signature) + P2PKWithTimeoutScriptSignature( + beforeTimeout = false, + signature = sig.signature + ) Success(wipeAndAdd(scriptSig, None)) } else { - Failure(new IllegalArgumentException( - s"Cannot finalize the following input because the signature provided ($sig) signs for neither key in $p2pkWithTimeout: $this")) + Failure( + new IllegalArgumentException( + s"Cannot finalize the following input because the signature provided ($sig) signs for neither key in $p2pkWithTimeout: $this" + ) + ) } } case conditional: ConditionalScriptPubKey => val builder = - Vector.newBuilder[( - ConditionalPath, - Vector[Sha256Hash160Digest], - RawScriptPubKey)] + Vector.newBuilder[ + (ConditionalPath, Vector[Sha256Hash160Digest], RawScriptPubKey) + ] - /** Traverses the ConditionalScriptPubKey tree for leaves and adds them to builder */ + /** Traverses the ConditionalScriptPubKey tree for leaves and adds them + * to builder + */ def addLeaves(rawSPK: RawScriptPubKey, path: Vector[Boolean]): Unit = { rawSPK match { case conditional: ConditionalScriptPubKey => addLeaves(conditional.trueSPK, path :+ true) addLeaves(conditional.falseSPK, path :+ false) case p2pkWithTimeout: P2PKWithTimeoutScriptPubKey => - addLeaves(P2PKScriptPubKey.fromP2PKWithTimeout(p2pkWithTimeout, - timeoutBranch = - false), - path :+ true) + addLeaves( + P2PKScriptPubKey + .fromP2PKWithTimeout(p2pkWithTimeout, timeoutBranch = false), + path :+ true + ) val timeoutSPK = CLTVScriptPubKey( p2pkWithTimeout.lockTime, - P2PKScriptPubKey.fromP2PKWithTimeout(p2pkWithTimeout, - timeoutBranch = true)) + P2PKScriptPubKey.fromP2PKWithTimeout( + p2pkWithTimeout, + timeoutBranch = true + ) + ) addLeaves(timeoutSPK, path :+ false) case cltv: CLTVScriptPubKey => addLeaves(cltv.nestedScriptPubKey, path) case csv: CSVScriptPubKey => addLeaves(csv.nestedScriptPubKey, path) case p2pkh: P2PKHScriptPubKey => - builder += ((ConditionalPath.fromBranch(path), - Vector(p2pkh.pubKeyHash), - p2pkh)) + builder += (( + ConditionalPath.fromBranch(path), + Vector(p2pkh.pubKeyHash), + p2pkh + )) case p2pk: P2PKScriptPubKey => val hash = CryptoUtil.sha256Hash160(p2pk.publicKey.bytes) - builder += ((ConditionalPath.fromBranch(path), - Vector(hash), - p2pk)) + builder += (( + ConditionalPath.fromBranch(path), + Vector(hash), + p2pk + )) case multiSig: MultiSignatureScriptPubKey => // If no sigs are required we handle in a special way below if (multiSig.requiredSigs == 0) { - builder += ((ConditionalPath.fromBranch(path), - Vector.empty, - multiSig)) + builder += (( + ConditionalPath.fromBranch(path), + Vector.empty, + multiSig + )) } else { val hashes = multiSig.publicKeys.toVector.map(pubKey => CryptoUtil.sha256Hash160(pubKey.bytes)) - builder += ((ConditionalPath.fromBranch(path), - hashes, - multiSig)) + builder += (( + ConditionalPath.fromBranch(path), + hashes, + multiSig + )) } case EmptyScriptPubKey => - builder += ((ConditionalPath.fromBranch(path), - Vector.empty, - EmptyScriptPubKey)) + builder += (( + ConditionalPath.fromBranch(path), + Vector.empty, + EmptyScriptPubKey + )) case _: NonStandardScriptPubKey | _: WitnessCommitment => throw new UnsupportedOperationException( - s"$rawSPK is not yet supported") + s"$rawSPK is not yet supported" + ) } } @@ -593,7 +649,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) val leafT = toTry( leafOpt, - s"no conditional branch using $sigs in $conditional could be found") + s"no conditional branch using $sigs in $conditional could be found" + ) leafT.flatMap { case (path, _, spk) => val finalizedOpt = finalize(spk) @@ -604,7 +661,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) val scriptSig = ConditionalScriptSignature.fromNestedScriptSig( nestedScriptSig.scriptSig, - path) + path + ) wipeAndAdd(scriptSig) } } @@ -613,17 +671,23 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) case _: P2PKHScriptPubKey => collectSigs( required = 1, - sigs => P2PKHScriptSignature(sigs.head.signature, sigs.head.pubKey)) + sigs => P2PKHScriptSignature(sigs.head.signature, sigs.head.pubKey) + ) case _: P2PKScriptPubKey => - collectSigs(required = 1, - sigs => P2PKScriptSignature(sigs.head.signature)) + collectSigs( + required = 1, + sigs => P2PKScriptSignature(sigs.head.signature) + ) case multiSig: MultiSignatureScriptPubKey => def generateScriptSig( - sigs: Seq[PartialSignature]): MultiSignatureScriptSignature = { + sigs: Seq[PartialSignature] + ): MultiSignatureScriptSignature = { val sortedSigs = sigs .map { partialSig => - (partialSig.signature, - multiSig.publicKeys.indexOf(partialSig.pubKey)) + ( + partialSig.signature, + multiSig.publicKeys.indexOf(partialSig.pubKey) + ) } .sortBy(_._2) .map(_._1) @@ -646,38 +710,49 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) Success(wipeAndAdd(EmptyScriptSignature, Some(witnessScript))) case None => // todo add script spend support - Failure(new UnsupportedOperationException( - s"Cannot finalize the following input because no key spend signature was provided: $this")) + Failure( + new UnsupportedOperationException( + s"Cannot finalize the following input because no key spend signature was provided: $this" + ) + ) } case _: NonStandardScriptPubKey | _: UnassignedWitnessScriptPubKey | _: WitnessCommitment => Failure( new UnsupportedOperationException( - s"$spkToSatisfy is not yet supported")) + s"$spkToSatisfy is not yet supported" + ) + ) } } - /** Takes another InputPSBTMap and adds all records that are not contained in this InputPSBTMap - * A record's distinctness is determined by its key - * @param other InputPSBTMap to be combined with - * @return A InputPSBTMap with the combined data of the two InputPSBTMaps + /** Takes another InputPSBTMap and adds all records that are not contained in + * this InputPSBTMap A record's distinctness is determined by its key + * @param other + * InputPSBTMap to be combined with + * @return + * A InputPSBTMap with the combined data of the two InputPSBTMaps */ def combine(other: InputPSBTMap): InputPSBTMap = { InputPSBTMap(distinctByKey(this.elements ++ other.elements)) } - /** Takes the InputPSBTMap returns a NewSpendingInfoFull - * that can be used to sign the input - * @param txIn The transaction input that this InputPSBTMap represents - * @param signers Signers that will be used to sign the input - * @param conditionalPath Path that should be used for the script - * @return A corresponding NewSpendingInfoFull + /** Takes the InputPSBTMap returns a NewSpendingInfoFull that can be used to + * sign the input + * @param txIn + * The transaction input that this InputPSBTMap represents + * @param signers + * Signers that will be used to sign the input + * @param conditionalPath + * Path that should be used for the script + * @return + * A corresponding NewSpendingInfoFull */ def toUTXOSatisfyingInfoUsingSigners( txIn: TransactionInput, signers: Vector[Sign], - conditionalPath: ConditionalPath = - ConditionalPath.NoCondition): ScriptSignatureParams[InputInfo] = { + conditionalPath: ConditionalPath = ConditionalPath.NoCondition + ): ScriptSignatureParams[InputInfo] = { require(!isFinalized, s"Cannot update an InputPSBTMap that is finalized") val infoSingle = @@ -694,7 +769,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) def toInputInfo( txIn: TransactionInput, conditionalPath: ConditionalPath = ConditionalPath.NoCondition, - preImages: Vector[NetworkElement] = Vector.empty): InputInfo = { + preImages: Vector[NetworkElement] = Vector.empty + ): InputInfo = { if (isFinalized) toInputInfoFinalized(txIn, conditionalPath, preImages) else toInputInfoNonFinalized(txIn, conditionalPath, preImages) @@ -703,7 +779,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) def toInputInfoFinalized( txIn: TransactionInput, conditionalPath: ConditionalPath, - preImages: Vector[NetworkElement]): InputInfo = { + preImages: Vector[NetworkElement] + ): InputInfo = { val outPoint = txIn.previousOutput val witVec = getRecords(WitnessUTXOKeyId) @@ -716,7 +793,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) tx.outputs(txIn.previousOutput.vout.toInt) } else { throw new UnsupportedOperationException( - s"Not enough information in the InputPSBTMap to get a valid InputInfo: $elements") + s"Not enough information in the InputPSBTMap to get a valid InputInfo: $elements" + ) } val redeemScriptOpt = finalizedScriptSigOpt match { @@ -736,18 +814,21 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) val scriptWitnessOpt = finalizedScriptWitnessOpt.map(_.scriptWitness) - InputInfo(outPoint, - output, - redeemScriptOpt, - scriptWitnessOpt, - conditionalPath, - preImages) + InputInfo( + outPoint, + output, + redeemScriptOpt, + scriptWitnessOpt, + conditionalPath, + preImages + ) } private def toInputInfoNonFinalized( txIn: TransactionInput, conditionalPath: ConditionalPath, - preImages: Vector[NetworkElement]): InputInfo = { + preImages: Vector[NetworkElement] + ): InputInfo = { val outPoint = txIn.previousOutput val witVec = getRecords(WitnessUTXOKeyId) @@ -760,7 +841,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) tx.outputs(txIn.previousOutput.vout.toInt) } else { throw new RuntimeException( - "Not enough information in the InputPSBTMap to get a valid InputInfo") + "Not enough information in the InputPSBTMap to get a valid InputInfo" + ) } val redeemScriptOpt = this.redeemScriptOpt.map(_.redeemScript) @@ -772,35 +854,41 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) } else if ( output.scriptPubKey .isInstanceOf[P2WPKHWitnessSPKV0] || redeemScriptOpt.exists( - _.isInstanceOf[P2WPKHWitnessSPKV0]) + _.isInstanceOf[P2WPKHWitnessSPKV0] + ) ) { - require(preImages.size == 1, - "P2WPKHWitnessV0 must have it's public key as a pre-image") + require( + preImages.size == 1, + "P2WPKHWitnessV0 must have it's public key as a pre-image" + ) preImages.head match { case pubKey: ECPublicKey => Some(P2WPKHWitnessV0(pubKey)) case _: NetworkElement => throw new IllegalArgumentException( - "P2WPKHWitnessV0 must have it's public key as a pre-image") + "P2WPKHWitnessV0 must have it's public key as a pre-image" + ) } } else { None } - InputInfo(outPoint, - output, - redeemScriptOpt, - scriptWitnessOpt, - conditionalPath, - preImages) + InputInfo( + outPoint, + output, + redeemScriptOpt, + scriptWitnessOpt, + conditionalPath, + preImages + ) } def toUTXOSigningInfo( txIn: TransactionInput, signer: Sign, - conditionalPath: ConditionalPath = - ConditionalPath.NoCondition): ECSignatureParams[InputInfo] = { + conditionalPath: ConditionalPath = ConditionalPath.NoCondition + ): ECSignatureParams[InputInfo] = { require(!isFinalized, s"Cannot update an InputPSBTMap that is finalized") val txVec = getRecords(NonWitnessUTXOKeyId) @@ -815,7 +903,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) } private def changeToWitnessUTXO( - transactionOutput: TransactionOutput): InputPSBTMap = { + transactionOutput: TransactionOutput + ): InputPSBTMap = { val newElements = transactionOutput.scriptPubKey match { case _: P2SHScriptPubKey => if (redeemScriptOpt.isDefined) { @@ -846,13 +935,15 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) InputPSBTMap(newElements) } - /** After a discovered vulnerability in BIP-143, this is no longer safe for SegwitV0 - * Check if this satisfies criteria for witness. If it does, delete the NonWitnessOrUnknownUTXO field - * This is useful for following reasons. - * 1. Compresses the size of the data - * 2. Allows for segwit only compatibility - * @param txIn The TransactionInput that this InputPSBTMap represents - * @return The compressed InputPSBTMap + /** After a discovered vulnerability in BIP-143, this is no longer safe for + * SegwitV0 Check if this satisfies criteria for witness. If it does, delete + * the NonWitnessOrUnknownUTXO field This is useful for following reasons. + * 1. Compresses the size of the data 2. Allows for segwit only + * compatibility + * @param txIn + * The TransactionInput that this InputPSBTMap represents + * @return + * The compressed InputPSBTMap */ def compressMap(txIn: TransactionInput): InputPSBTMap = { if (isFinalized) { @@ -866,7 +957,8 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) changeToWitnessUTXO(out).elements } else { throw new IllegalArgumentException( - s"Invalid txIn given, got: $txIn") + s"Invalid txIn given, got: $txIn" + ) } } else { elements @@ -880,13 +972,14 @@ case class InputPSBTMap(elements: Vector[InputPSBTRecord]) object InputPSBTMap extends PSBTMapFactory[InputPSBTRecord, InputPSBTMap] { import org.bitcoins.core.psbt.InputPSBTRecord._ - /** Constructs a finalized InputPSBTMap from a NewSpendingInfoFull, - * the corresponding PSBT's unsigned transaction, and if this is - * a non-witness spend, the transaction being spent + /** Constructs a finalized InputPSBTMap from a NewSpendingInfoFull, the + * corresponding PSBT's unsigned transaction, and if this is a non-witness + * spend, the transaction being spent */ def finalizedFromSpendingInfo( spendingInfo: ScriptSignatureParams[InputInfo], - unsignedTx: Transaction): InputPSBTMap = { + unsignedTx: Transaction + ): InputPSBTMap = { val sigComponent = BitcoinSigner .sign(spendingInfo, unsignedTx, isDummySignature = false) @@ -922,11 +1015,14 @@ object InputPSBTMap extends PSBTMapFactory[InputPSBTRecord, InputPSBTMap] { */ def fromUTXOInfo( spendingInfo: ScriptSignatureParams[InputInfo], - unsignedTx: Transaction): InputPSBTMap = { + unsignedTx: Transaction + ): InputPSBTMap = { val sigs = spendingInfo.toSingles.map { spendingInfoSingle => - BitcoinSigner.signSingle(spendingInfoSingle, - unsignedTx, - isDummySignature = false) + BitcoinSigner.signSingle( + spendingInfoSingle, + unsignedTx, + isDummySignature = false + ) } val builder = Vector.newBuilder[InputPSBTRecord] @@ -1003,10 +1099,12 @@ case class OutputPSBTMap(elements: Vector[OutputPSBTRecord]) super.filterRecords(key, PSBTOutputKeyId) } - /** Takes another OutputPSBTMap and adds all records that are not contained in this OutputPSBTMap - * A record's distinctness is determined by its key - * @param other OutputPSBTMap to be combined with - * @return A OutputPSBTMap with the combined data of the two OutputPSBTMaps + /** Takes another OutputPSBTMap and adds all records that are not contained in + * this OutputPSBTMap A record's distinctness is determined by its key + * @param other + * OutputPSBTMap to be combined with + * @return + * A OutputPSBTMap with the combined data of the two OutputPSBTMaps */ def combine(other: OutputPSBTMap): OutputPSBTMap = { OutputPSBTMap(distinctByKey(this.elements ++ other.elements)) diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala index a01b1c575f..2095924e42 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBTRecord.scala @@ -65,7 +65,8 @@ object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] { extends GlobalPSBTRecord { require( transaction.inputs.forall(_.scriptSignature == EmptyScriptSignature), - s"All ScriptSignatures must be empty, got $transaction") + s"All ScriptSignatures must be empty, got $transaction" + ) override type KeyId = UnsignedTransactionKeyId.type override val key: ByteVector = ByteVector(UnsignedTransactionKeyId.byte) @@ -75,15 +76,16 @@ object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] { case class XPubKey( xpub: ExtPublicKey, masterFingerprint: ByteVector, - derivationPath: BIP32Path) - extends GlobalPSBTRecord { + derivationPath: BIP32Path + ) extends GlobalPSBTRecord { require( derivationPath.length == xpub.depth.toInt, s"Derivation path length does not match xpubkey depth, difference: ${derivationPath.length - xpub.depth.toInt}" ) require( masterFingerprint.length == 4, - s"Master key fingerprints are 4 bytes long, got: $masterFingerprint") + s"Master key fingerprints are 4 bytes long, got: $masterFingerprint" + ) override type KeyId = XPubKeyKeyId.type override val key: ByteVector = ByteVector(XPubKeyKeyId.byte) ++ xpub.bytes @@ -102,8 +104,10 @@ object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] { extends GlobalPSBTRecord { override type KeyId = UnknownKeyId.type private val keyId = PSBTGlobalKeyId.fromBytes(key) - require(keyId == UnknownKeyId, - s"Cannot make an Unknown record with a $keyId") + require( + keyId == UnknownKeyId, + s"Cannot make an Unknown record with a $keyId" + ) } override def fromBytes(bytes: ByteVector): GlobalPSBTRecord = { @@ -112,8 +116,10 @@ object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] { val (key, value) = PSBTRecord.fromBytes(bytes) PSBTGlobalKeyId.fromByte(key.head) match { case UnsignedTransactionKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) UnsignedTransaction(BaseTransaction.fromBytes(value)) case XPubKeyKeyId => @@ -122,13 +128,17 @@ object GlobalPSBTRecord extends Factory[GlobalPSBTRecord] { val path = BIP32Path.fromBytesLE(value.drop(4)) XPubKey(xpub, fingerprint, path) case VersionKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) val version = UInt32.fromBytesLE(value) - require(PSBT.knownVersions.contains(version), - s"Unknown version number given: $version") + require( + PSBT.knownVersions.contains(version), + s"Unknown version number given: $version" + ) Version(version) case UnknownKeyId => GlobalPSBTRecord.Unknown(key, value) @@ -159,10 +169,12 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { case class PartialSignature( pubKey: ECPublicKeyBytes, - signature: ECDigitalSignature) - extends InputPSBTRecord { - require(pubKey.byteSize == 33, - s"pubKey must be 33 bytes, got: ${pubKey.byteSize}") + signature: ECDigitalSignature + ) extends InputPSBTRecord { + require( + pubKey.byteSize == 33, + s"pubKey must be 33 bytes, got: ${pubKey.byteSize}" + ) override type KeyId = PartialSignatureKeyId.type @@ -175,12 +187,14 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { def apply( pubKey: ECPublicKey, - signature: ECDigitalSignature): PartialSignature = { + signature: ECDigitalSignature + ): PartialSignature = { PartialSignature(pubKey.toPublicKeyBytes(), signature) } def dummyPartialSig( - pubKey: ECPublicKey = ECPublicKey.freshPublicKey): PartialSignature = { + pubKey: ECPublicKey = ECPublicKey.freshPublicKey + ): PartialSignature = { PartialSignature(pubKey, DummyECDigitalSignature) } @@ -190,14 +204,16 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { partialSignature case other: InputPSBTRecord => throw new IllegalArgumentException( - s"Invalid PartialSignature encoding, got: $other") + s"Invalid PartialSignature encoding, got: $other" + ) } def vecFromBytes(bytes: ByteVector): Vector[PartialSignature] = { @scala.annotation.tailrec def loop( remainingBytes: ByteVector, - accum: Vector[PartialSignature]): Vector[PartialSignature] = { + accum: Vector[PartialSignature] + ): Vector[PartialSignature] = { if (remainingBytes.isEmpty) { accum } else { @@ -238,10 +254,12 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { case class BIP32DerivationPath( pubKey: ECPublicKey, masterFingerprint: ByteVector, - path: BIP32Path) - extends InputPSBTRecord { - require(pubKey.byteSize == 33, - s"pubKey must be 33 bytes, got: ${pubKey.byteSize}") + path: BIP32Path + ) extends InputPSBTRecord { + require( + pubKey.byteSize == 33, + s"pubKey must be 33 bytes, got: ${pubKey.byteSize}" + ) override type KeyId = BIP32DerivationPathKeyId.type @@ -271,7 +289,8 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { override type KeyId = ProofOfReservesCommitmentKeyId.type override val key: ByteVector = ByteVector( - ProofOfReservesCommitmentKeyId.byte) + ProofOfReservesCommitmentKeyId.byte + ) override val value: ByteVector = porCommitment } @@ -334,20 +353,21 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { case class TRScriptSpendSignature( xOnlyPubKey: XOnlyPubKey, leafHash: Sha256Digest, - signature: SchnorrDigitalSignature) - extends InputPSBTRecord { + signature: SchnorrDigitalSignature + ) extends InputPSBTRecord { override type KeyId = TRScriptSpendSignatureKeyId.type override val key: ByteVector = ByteVector( - TRScriptSpendSignatureKeyId.byte) ++ xOnlyPubKey.bytes ++ leafHash.bytes + TRScriptSpendSignatureKeyId.byte + ) ++ xOnlyPubKey.bytes ++ leafHash.bytes override val value: ByteVector = signature.bytes } case class TRLeafScript( controlBlock: ControlBlock, script: RawScriptPubKey, - leafVersion: Byte) - extends InputPSBTRecord { + leafVersion: Byte + ) extends InputPSBTRecord { override type KeyId = TRLeafScriptKeyId.type override val key: ByteVector = { @@ -363,8 +383,8 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { xOnlyPubKey: XOnlyPubKey, hashes: Vector[Sha256Digest], masterFingerprint: ByteVector, - path: BIP32Path) - extends InputPSBTRecord { + path: BIP32Path + ) extends InputPSBTRecord { override type KeyId = TRBIP32DerivationPathKeyId.type @@ -400,8 +420,10 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { extends InputPSBTRecord { override type KeyId = UnknownKeyId.type private val keyId = PSBTInputKeyId.fromBytes(key) - require(keyId == UnknownKeyId, - s"Cannot make an Unknown record with a $keyId") + require( + keyId == UnknownKeyId, + s"Cannot make an Unknown record with a $keyId" + ) } override def fromBytes(bytes: ByteVector): InputPSBTRecord = { @@ -410,13 +432,17 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { val (key, value) = PSBTRecord.fromBytes(bytes) PSBTInputKeyId.fromByte(key.head) match { case NonWitnessUTXOKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) NonWitnessOrUnknownUTXO(Transaction(value)) case WitnessUTXOKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) WitnessUTXO(TransactionOutput.fromBytes(value)) case PartialSignatureKeyId => @@ -424,18 +450,24 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { val sig = ECDigitalSignature(value) PartialSignature(pubKey, sig) case SigHashTypeKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) SigHashType(HashType.fromBytesLE(value)) case PSBTInputKeyId.RedeemScriptKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) InputPSBTRecord.RedeemScript(ScriptPubKey.fromAsmBytes(value)) case PSBTInputKeyId.WitnessScriptKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) InputPSBTRecord.WitnessScript(RawScriptPubKey.fromAsmBytes(value)) case PSBTInputKeyId.BIP32DerivationPathKeyId => @@ -444,14 +476,18 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { val path = BIP32Path.fromBytesLE(value.drop(4)) InputPSBTRecord.BIP32DerivationPath(pubKey, fingerprint, path) case FinalizedScriptSigKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) val sig = ScriptSignature.fromAsmBytes(value) FinalizedScriptSig(sig) case FinalizedScriptWitnessKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) FinalizedScriptWitness(RawScriptWitnessParser.read(value)) case ProofOfReservesCommitmentKeyId => @@ -459,60 +495,77 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { case RIPEMD160PreImageKeyId => require( key.size == 21, - s"The key must contain the 1 byte type followed by the 20 byte hash, got: $key") + s"The key must contain the 1 byte type followed by the 20 byte hash, got: $key" + ) val hash = key.tail val record = RIPEMD160PreImage(value) - require(record.hash.bytes == hash, - "Received invalid RIPEMD160PreImage, hash does not match") + require( + record.hash.bytes == hash, + "Received invalid RIPEMD160PreImage, hash does not match" + ) record case SHA256PreImageKeyId => require( key.size == 33, - s"The key must contain the 1 byte type followed by the 32 byte hash, got: $key") + s"The key must contain the 1 byte type followed by the 32 byte hash, got: $key" + ) val hash = key.tail val record = SHA256PreImage(value) - require(record.hash.bytes == hash, - "Received invalid SHA256PreImage, hash does not match") + require( + record.hash.bytes == hash, + "Received invalid SHA256PreImage, hash does not match" + ) record case HASH160PreImageKeyId => require( key.size == 21, - s"The key must contain the 1 byte type followed by the 20 byte hash, got: $key") + s"The key must contain the 1 byte type followed by the 20 byte hash, got: $key" + ) val hash = key.tail val record = HASH160PreImage(value) - require(record.hash.bytes == hash, - "Received invalid HASH160PreImage, hash does not match") + require( + record.hash.bytes == hash, + "Received invalid HASH160PreImage, hash does not match" + ) record case HASH256PreImageKeyId => require( key.size == 21, - s"The key must contain the 1 byte type followed by the 32 byte hash, got: $key") + s"The key must contain the 1 byte type followed by the 32 byte hash, got: $key" + ) val hash = key.tail val record = HASH256PreImage(value) - require(record.hash.bytes == hash, - "Received invalid HASH256PreImage, hash does not match") + require( + record.hash.bytes == hash, + "Received invalid HASH256PreImage, hash does not match" + ) record case TRKeySpendSignatureKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) val sig = SchnorrDigitalSignature.fromBytes(value) TRKeySpendSignature(sig) case TRScriptSpendSignatureKeyId => require( key.size == 65, - s"The key must only contain the 65 bytes type, got: ${key.size}") + s"The key must only contain the 65 bytes type, got: ${key.size}" + ) val (xOnlyPubKey, leafHash) = key.tail.splitAt(32) val sig = SchnorrDigitalSignature.fromBytes(value) - TRScriptSpendSignature(XOnlyPubKey(xOnlyPubKey), - Sha256Digest(leafHash), - sig) + TRScriptSpendSignature( + XOnlyPubKey(xOnlyPubKey), + Sha256Digest(leafHash), + sig + ) case TRLeafScriptKeyId => val controlBlock = ControlBlock(key.tail) @@ -533,25 +586,33 @@ object InputPSBTRecord extends Factory[InputPSBTRecord] { val fingerprint = remaining.take(4) val path = BIP32Path.fromBytesLE(remaining.drop(4)) - TRBIP32DerivationPath(xOnlyPubKey = pubKey, - hashes = hashes, - masterFingerprint = fingerprint, - path = path) + TRBIP32DerivationPath( + xOnlyPubKey = pubKey, + hashes = hashes, + masterFingerprint = fingerprint, + path = path + ) case TRInternalKeyKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) require( value.size == 32, - s"The value must contain the 32 byte x-only public key, got: ${value.size}") + s"The value must contain the 32 byte x-only public key, got: ${value.size}" + ) TRInternalKey(XOnlyPubKey.fromBytes(value)) case TRMerkelRootKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) require( value.size == 32, - s"The value must contain the 32 byte x-only public key, got: ${value.size}") + s"The value must contain the 32 byte x-only public key, got: ${value.size}" + ) TRMerkelRoot(Sha256Digest(value)) case UnknownKeyId => InputPSBTRecord.Unknown(key, value) @@ -582,10 +643,12 @@ object OutputPSBTRecord extends Factory[OutputPSBTRecord] { case class BIP32DerivationPath( pubKey: ECPublicKey, masterFingerprint: ByteVector, - path: BIP32Path) - extends OutputPSBTRecord { - require(pubKey.byteSize == 33, - s"pubKey must be 33 bytes, got: ${pubKey.byteSize}") + path: BIP32Path + ) extends OutputPSBTRecord { + require( + pubKey.byteSize == 33, + s"pubKey must be 33 bytes, got: ${pubKey.byteSize}" + ) override type KeyId = BIP32DerivationPathKeyId.type @@ -611,7 +674,8 @@ object OutputPSBTRecord extends Factory[OutputPSBTRecord] { leafs.foldLeft(ByteVector.empty) { (acc, leaf) => val spk = leaf._3 acc ++ ByteVector.fromByte(leaf._1) ++ ByteVector.fromByte( - leaf._2) ++ CompactSizeUInt.calc(spk).bytes ++ spk + leaf._2 + ) ++ CompactSizeUInt.calc(spk).bytes ++ spk } } } @@ -620,8 +684,8 @@ object OutputPSBTRecord extends Factory[OutputPSBTRecord] { xOnlyPubKey: XOnlyPubKey, hashes: Vector[Sha256Digest], masterFingerprint: ByteVector, - path: BIP32Path) - extends OutputPSBTRecord { + path: BIP32Path + ) extends OutputPSBTRecord { override type KeyId = TRBIP32DerivationPathKeyId.type @@ -651,21 +715,27 @@ object OutputPSBTRecord extends Factory[OutputPSBTRecord] { extends OutputPSBTRecord { override type KeyId = UnknownKeyId.type private val keyId = PSBTOutputKeyId.fromBytes(key) - require(keyId == UnknownKeyId, - s"Cannot make an Unknown record with a $keyId") + require( + keyId == UnknownKeyId, + s"Cannot make an Unknown record with a $keyId" + ) } override def fromBytes(bytes: ByteVector): OutputPSBTRecord = { val (key, value) = PSBTRecord.fromBytes(bytes) PSBTOutputKeyId.fromByte(key.head) match { case PSBTOutputKeyId.RedeemScriptKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) OutputPSBTRecord.RedeemScript(ScriptPubKey.fromAsmBytes(value)) case PSBTOutputKeyId.WitnessScriptKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) OutputPSBTRecord.WitnessScript(ScriptPubKey.fromAsmBytes(value)) case PSBTOutputKeyId.BIP32DerivationPathKeyId => @@ -675,8 +745,10 @@ object OutputPSBTRecord extends Factory[OutputPSBTRecord] { OutputPSBTRecord.BIP32DerivationPath(pubKey, fingerprint, path) case PSBTOutputKeyId.TRInternalKeyKeyId => - require(key.size == 1, - s"The key must only contain the 1 byte type, got: ${key.size}") + require( + key.size == 1, + s"The key must only contain the 1 byte type, got: ${key.size}" + ) val xOnlyPubKey = XOnlyPubKey.fromBytes(value) OutputPSBTRecord.TRInternalKey(xOnlyPubKey) @@ -684,8 +756,8 @@ object OutputPSBTRecord extends Factory[OutputPSBTRecord] { @tailrec def loop( bytes: ByteVector, - accum: Vector[(Byte, Byte, ByteVector)]): Vector[ - (Byte, Byte, ByteVector)] = { + accum: Vector[(Byte, Byte, ByteVector)] + ): Vector[(Byte, Byte, ByteVector)] = { if (bytes.isEmpty) { accum } else { @@ -713,10 +785,12 @@ object OutputPSBTRecord extends Factory[OutputPSBTRecord] { val fingerprint = remaining.take(4) val path = BIP32Path.fromBytesLE(remaining.drop(4)) - OutputPSBTRecord.TRBIP32DerivationPath(xOnlyPubKey = pubKey, - hashes = hashes, - masterFingerprint = fingerprint, - path = path) + OutputPSBTRecord.TRBIP32DerivationPath( + xOnlyPubKey = pubKey, + hashes = hashes, + masterFingerprint = fingerprint, + path = path + ) case UnknownKeyId => OutputPSBTRecord.Unknown(key, value) } diff --git a/core/src/main/scala/org/bitcoins/core/psbt/PSBTRole.scala b/core/src/main/scala/org/bitcoins/core/psbt/PSBTRole.scala index 3d797e1612..81e29d800a 100644 --- a/core/src/main/scala/org/bitcoins/core/psbt/PSBTRole.scala +++ b/core/src/main/scala/org/bitcoins/core/psbt/PSBTRole.scala @@ -37,11 +37,13 @@ object PSBTRole extends StringFactory[PSBTRole] { override def order: Int = 4 } - val all: Vector[PSBTRole] = Vector(CreatorPSBTRole, - UpdaterPSBTRole, - SignerPSBTRole, - FinalizerPSBTRole, - ExtractorPSBTRole) + val all: Vector[PSBTRole] = Vector( + CreatorPSBTRole, + UpdaterPSBTRole, + SignerPSBTRole, + FinalizerPSBTRole, + ExtractorPSBTRole + ) override def fromStringOpt(string: String): Option[PSBTRole] = { all.find(_.toString.toLowerCase == string.toLowerCase) diff --git a/core/src/main/scala/org/bitcoins/core/script/ScriptOperationFactory.scala b/core/src/main/scala/org/bitcoins/core/script/ScriptOperationFactory.scala index 7c736cee9e..7703f35a10 100644 --- a/core/src/main/scala/org/bitcoins/core/script/ScriptOperationFactory.scala +++ b/core/src/main/scala/org/bitcoins/core/script/ScriptOperationFactory.scala @@ -13,21 +13,23 @@ import org.bitcoins.core.util.BytesUtil import org.bitcoins.crypto.StringFactory import scodec.bits.ByteVector -/** Created by chris on 1/8/16. - * Responsible for matching script op codes with their given - * hexadecimal representation or byte representation +/** Created by chris on 1/8/16. Responsible for matching script op codes with + * their given hexadecimal representation or byte representation */ trait ScriptOperationFactory[T <: ScriptOperation] extends StringFactory[T] { - /** All of the [[org.bitcoins.core.script.ScriptOperation ScriptOperation]]s for a particular `T`. */ + /** All of the [[org.bitcoins.core.script.ScriptOperation ScriptOperation]]s + * for a particular `T`. + */ def operations: Vector[T] - /** Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from a given string + /** Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from + * a given string */ override def fromStringOpt(str: String): Option[T] = { val result: Option[T] = operations.find(_.toString == str) if (result.isEmpty) { - //try and remove the 'OP_' prefix on the operations and see if it matches anything. + // try and remove the 'OP_' prefix on the operations and see if it matches anything. operations.find(op => removeOP_Prefix(op.toString) == removeOP_Prefix(str)) } else result @@ -41,21 +43,24 @@ trait ScriptOperationFactory[T <: ScriptOperation] extends StringFactory[T] { } } - /** Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from its hexadecimal representation. + /** Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from + * its hexadecimal representation. */ def fromHex(hex: String): Option[T] = { val bytes = BytesUtil.decodeHex(hex) fromBytes(bytes) } - /** Removes the 'OP_' prefix from a given operation. - * Example: `OP_EQUALVERIFY` would be transformed into `EQUALVERIFY` + /** Removes the 'OP_' prefix from a given operation. Example: `OP_EQUALVERIFY` + * would be transformed into `EQUALVERIFY` */ private def removeOP_Prefix(str: String): String = { str.replace("OP_", "") } - /** Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from a given [[scala.Byte Byte]]. */ + /** Finds a [[org.bitcoins.core.script.ScriptOperation ScriptOperation]] from + * a given [[scala.Byte Byte]]. + */ @inline final def fromByte(byte: Byte): T = { scriptOpMap(byte).asInstanceOf[T] } @@ -79,11 +84,9 @@ trait ScriptOperationFactory[T <: ScriptOperation] extends StringFactory[T] { object ScriptOperation extends ScriptOperationFactory[ScriptOperation] { - /** This contains duplicate operations - * There is an optimization here by moving popular opcodes - * to the front of the vector so when we iterate through it, - * we are more likely to find the op code we are looking for - * sooner + /** This contains duplicate operations There is an optimization here by moving + * popular opcodes to the front of the vector so when we iterate through it, + * we are more likely to find the op code we are looking for sooner */ final override val operations: Vector[ScriptOperation] = { StackPushOperationFactory.pushDataOperations ++ diff --git a/core/src/main/scala/org/bitcoins/core/script/ScriptProgram.scala b/core/src/main/scala/org/bitcoins/core/script/ScriptProgram.scala index e5de2d6c9e..cbb91333d1 100644 --- a/core/src/main/scala/org/bitcoins/core/script/ScriptProgram.scala +++ b/core/src/main/scala/org/bitcoins/core/script/ScriptProgram.scala @@ -40,8 +40,9 @@ sealed trait ScriptProgram { /** The alternative stack is used in some Script op codes. */ def altStack: List[ScriptToken] - /** [[org.bitcoins.core.script.flag.ScriptFlag ScriptFlag]] that are run with the script. - * These flags indicate special conditions that a script needs to be run with. + /** [[org.bitcoins.core.script.flag.ScriptFlag ScriptFlag]] that are run with + * the script. These flags indicate special conditions that a script needs to + * be run with. * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.h#L31]] * @return */ @@ -54,10 +55,13 @@ sealed trait ScriptProgram { /** Returns true if the stack top is false */ def stackTopIsFalse: Boolean = !stackTopIsTrue - /** Sets a [[org.bitcoins.core.script.result.ScriptError ScriptError]] on a given - * [[org.bitcoins.core.script.ScriptProgram ScriptProgram]]. - * @param error the error that the program hit while being executed in the script interpreter - * @return the ExecutedScriptProgram with the given error set inside of the trait + /** Sets a [[org.bitcoins.core.script.result.ScriptError ScriptError]] on a + * given [[org.bitcoins.core.script.ScriptProgram ScriptProgram]]. + * @param error + * the error that the program hit while being executed in the script + * interpreter + * @return + * the ExecutedScriptProgram with the given error set inside of the trait */ def failExecution(error: ScriptError): ExecutedScriptProgram @@ -82,7 +86,9 @@ sealed trait ScriptProgram { } } - /** Calculates the leaf hash if we have a tapscript, else returns None if we don't have a tapscript */ + /** Calculates the leaf hash if we have a tapscript, else returns None if we + * don't have a tapscript + */ def tapLeafHashOpt: Option[Sha256Digest] = { getTapscriptOpt.map { sp => val leaf = TapLeaf(TaprootScriptPath.TAPROOT_LEAF_TAPSCRIPT, sp.script) @@ -107,8 +113,8 @@ case class PreExecutionScriptProgram( script: List[ScriptToken], originalScript: List[ScriptToken], altStack: List[ScriptToken], - flags: Seq[ScriptFlag]) - extends ScriptProgram { + flags: Seq[ScriptFlag] +) extends ScriptProgram { def startingValidationWeight: Option[Long] = txSignatureComponent match { case _: BaseTxSigComponent | _: WitnessTxSigComponentRaw | @@ -150,13 +156,15 @@ case class PreExecutionScriptProgram( } def updateOriginalScript( - tokens: Seq[ScriptToken]): PreExecutionScriptProgram = { + tokens: Seq[ScriptToken] + ): PreExecutionScriptProgram = { this.copy(originalScript = tokens.toList) } def updateStackAndScript( stackTokens: Seq[ScriptToken], - scriptTokens: Seq[ScriptToken]): PreExecutionScriptProgram = { + scriptTokens: Seq[ScriptToken] + ): PreExecutionScriptProgram = { val updatedStack = this.updateStack(stackTokens) val updatedScript = updatedStack.updateScript(scriptTokens) require(updatedStack.stack == stackTokens) @@ -182,23 +190,31 @@ object PreExecutionScriptProgram { /** This represents any ScriptProgram that is not PreExecution */ sealed trait StartedScriptProgram extends ScriptProgram { - /** The index of the last code separator WITH push operations in the original script */ + /** The index of the last code separator WITH push operations in the original + * script + */ def lastCodeSeparator: Option[Int] def taprootSerializationOptions: TaprootSerializationOptions } -/** Implements the counting required for O(1) handling of conditionals in Bitcoin Script. - * @see [[https://github.com/bitcoin/bitcoin/pull/16902]] +/** Implements the counting required for O(1) handling of conditionals in + * Bitcoin Script. + * @see + * [[https://github.com/bitcoin/bitcoin/pull/16902]] * - * @param trueCount The depth of OP_IFs/OP_NOTIFs we've entered on the true condition before the first false. - * @param falseAndIgnoreCount The depth of OP_IFs/OP_NOTIFs we've entered after and including the first false condition. - * Every OP_IF/OP_NOTIF adds to trueCount or falseAndIgnoreCount. - * OP_ELSE has an effect only when falseAndIgnoreCount == 0 or 1, in which case it moves - * 1 from trueCount to falseAndIgnoreCount or vice versa. - * OP_ENDIF subtracts one from either falseAndIgnoreCount or trueCount if falseAndIgnoreCount == 0. - * trueCount + falseAndIgnoreCount represents the current depth in the conditional tree. - * falseAndIgnoreCount == 0 represents whether operations should be executed. + * @param trueCount + * The depth of OP_IFs/OP_NOTIFs we've entered on the true condition before + * the first false. + * @param falseAndIgnoreCount + * The depth of OP_IFs/OP_NOTIFs we've entered after and including the first + * false condition. Every OP_IF/OP_NOTIF adds to trueCount or + * falseAndIgnoreCount. OP_ELSE has an effect only when falseAndIgnoreCount + * \== 0 or 1, in which case it moves 1 from trueCount to falseAndIgnoreCount + * or vice versa. OP_ENDIF subtracts one from either falseAndIgnoreCount or + * trueCount if falseAndIgnoreCount == 0. trueCount + falseAndIgnoreCount + * represents the current depth in the conditional tree. falseAndIgnoreCount + * \== 0 represents whether operations should be executed. */ case class ConditionalCounter(trueCount: Int, falseAndIgnoreCount: Int) { require(trueCount >= 0, "Should have failed as unbalanced") @@ -220,8 +236,8 @@ case class ConditionalCounter(trueCount: Int, falseAndIgnoreCount: Int) { trueCount + falseAndIgnoreCount } - /** Should be called for every OP_IF and OP_NOTIF with whether the first (true) - * or second (false) branch should be taken. + /** Should be called for every OP_IF and OP_NOTIF with whether the first + * (true) or second (false) branch should be taken. */ def addCondition(condition: Boolean): ConditionalCounter = { if (!noFalseEncountered || !condition) { @@ -265,11 +281,15 @@ object ConditionalCounter { ConditionalCounter(trueCount = 0, falseAndIgnoreCount = 0) } -/** Type for a [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] that is currently being - * evaluated by the [[org.bitcoins.core.script.interpreter.ScriptInterpreter ScriptInterpreter]]. +/** Type for a [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] that is + * currently being evaluated by the + * [[org.bitcoins.core.script.interpreter.ScriptInterpreter ScriptInterpreter]]. * - * @param lastCodeSeparator The index of the last [[org.bitcoins.core.script.crypto.OP_CODESEPARATOR OP_CODESEPARATOR]] - * @param conditionalCounter Keeps track of where we are within a conditional tree. + * @param lastCodeSeparator + * The index of the last + * [[org.bitcoins.core.script.crypto.OP_CODESEPARATOR OP_CODESEPARATOR]] + * @param conditionalCounter + * Keeps track of where we are within a conditional tree. */ case class ExecutionInProgressScriptProgram( txSignatureComponent: TxSigComponent, @@ -281,8 +301,8 @@ case class ExecutionInProgressScriptProgram( lastCodeSeparator: Option[Int], codeSeparatorTapscriptIdx: Option[Int], validationWeightRemaining: Option[Long], - conditionalCounter: ConditionalCounter) - extends StartedScriptProgram { + conditionalCounter: ConditionalCounter +) extends StartedScriptProgram { def toExecutedProgram: ExecutedScriptProgram = { val errorOpt = if (conditionalCounter.totalDepth > 0) { @@ -309,7 +329,8 @@ case class ExecutionInProgressScriptProgram( } def replaceFlags( - newFlags: Seq[ScriptFlag]): ExecutionInProgressScriptProgram = { + newFlags: Seq[ScriptFlag] + ): ExecutionInProgressScriptProgram = { this.copy(flags = newFlags) } @@ -321,7 +342,8 @@ case class ExecutionInProgressScriptProgram( /** ScriptInterpreter should look at the script head only if this is true. * * Note that OP_IF, OP_NOTIF, OP_ELSE, and OP_ENDIF must be executed even if - * isInExecutionBranch is false as they must modify the states of trueCount and falseAndIgnoreCount. + * isInExecutionBranch is false as they must modify the states of trueCount + * and falseAndIgnoreCount. */ def shouldExecuteNextOperation: Boolean = { script.headOption match { @@ -331,8 +353,8 @@ case class ExecutionInProgressScriptProgram( } } - /** Should be called for every OP_IF and OP_NOTIF with whether the first (true) - * or second (false) branch should be taken. + /** Should be called for every OP_IF and OP_NOTIF with whether the first + * (true) or second (false) branch should be taken. */ def addCondition(condition: Boolean): ExecutionInProgressScriptProgram = { this.copy(conditionalCounter = conditionalCounter.addCondition(condition)) @@ -356,7 +378,8 @@ case class ExecutionInProgressScriptProgram( } } - /** Removes the flags on the given [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] + /** Removes the flags on the given + * [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] * * @return */ @@ -365,40 +388,47 @@ case class ExecutionInProgressScriptProgram( } def updateStack( - tokens: Seq[ScriptToken]): ExecutionInProgressScriptProgram = { + tokens: Seq[ScriptToken] + ): ExecutionInProgressScriptProgram = { this.copy(stack = tokens.toList) } def updateAltStack( - tokens: Seq[ScriptToken]): ExecutionInProgressScriptProgram = { + tokens: Seq[ScriptToken] + ): ExecutionInProgressScriptProgram = { this.copy(altStack = tokens.toList) } def updateScript( - tokens: Seq[ScriptToken]): ExecutionInProgressScriptProgram = { + tokens: Seq[ScriptToken] + ): ExecutionInProgressScriptProgram = { this.copy(script = tokens.toList) } def updateStackAndScript( stack: Seq[ScriptToken], - script: Seq[ScriptToken]): ExecutionInProgressScriptProgram = { + script: Seq[ScriptToken] + ): ExecutionInProgressScriptProgram = { this .updateStack(stack) .updateScript(script) } def updateOriginalScript( - tokens: Seq[ScriptToken]): ExecutionInProgressScriptProgram = { + tokens: Seq[ScriptToken] + ): ExecutionInProgressScriptProgram = { this.copy(originalScript = tokens.toList) } def updateLastCodeSeparator( - newLastCodeSeparator: Int): ExecutionInProgressScriptProgram = { + newLastCodeSeparator: Int + ): ExecutionInProgressScriptProgram = { this.copy(lastCodeSeparator = Some(newLastCodeSeparator)) } def updateTapscriptCodeSeparatorIdx( - newIdx: Int): ExecutionInProgressScriptProgram = { + newIdx: Int + ): ExecutionInProgressScriptProgram = { this.copy(codeSeparatorTapscriptIdx = Some(newIdx)) } @@ -407,18 +437,23 @@ case class ExecutionInProgressScriptProgram( } def taprootSerializationOptions: TaprootSerializationOptions = { - TaprootSerializationOptions(tapLeafHashOpt, - getAnnexHashOpt, - codeSeparatorTapscriptIdx.map(UInt32(_))) + TaprootSerializationOptions( + tapLeafHashOpt, + getAnnexHashOpt, + codeSeparatorTapscriptIdx.map(UInt32(_)) + ) } } -/** Type for a [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] that has been - * evaluated completely by the +/** Type for a [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] that has + * been evaluated completely by the * [[org.bitcoins.core.script.interpreter.ScriptInterpreter ScriptInterpreter]]. * - * @param error Indicates if the [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] has - * encountered a [[org.bitcoins.core.script.result.ScriptError ScriptError]] in its execution. + * @param error + * Indicates if the [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] + * has encountered a + * [[org.bitcoins.core.script.result.ScriptError ScriptError]] in its + * execution. */ case class ExecutedScriptProgram( txSignatureComponent: TxSigComponent, @@ -429,13 +464,15 @@ case class ExecutedScriptProgram( flags: Seq[ScriptFlag], lastCodeSeparator: Option[Int], codeSeparatorTapscriptIdx: Option[Int], - error: Option[ScriptError]) - extends StartedScriptProgram { + error: Option[ScriptError] +) extends StartedScriptProgram { def taprootSerializationOptions: TaprootSerializationOptions = { - TaprootSerializationOptions(tapLeafHashOpt, - getAnnexHashOpt, - codeSeparatorTapscriptIdx.map(UInt32(_))) + TaprootSerializationOptions( + tapLeafHashOpt, + getAnnexHashOpt, + codeSeparatorTapscriptIdx.map(UInt32(_)) + ) } override def failExecution(error: ScriptError): ExecutedScriptProgram = { diff --git a/core/src/main/scala/org/bitcoins/core/script/ScriptType.scala b/core/src/main/scala/org/bitcoins/core/script/ScriptType.scala index a2488845bb..5fb6cb7c76 100644 --- a/core/src/main/scala/org/bitcoins/core/script/ScriptType.scala +++ b/core/src/main/scala/org/bitcoins/core/script/ScriptType.scala @@ -4,9 +4,11 @@ import org.bitcoins.crypto.StringFactory /** The different Bitcoin Script type variations * - * @see [[https://github.com/bitcoin/bitcoin/blob/fa6180188b8ab89af97860e6497716405a48bab6/src/script/standard.h#L56 standard.h]] - * and [[https://github.com/bitcoin/bitcoin/blob/03732f8644a449af34f4df1bb3b8915fb15ef22c/src/script/standard.cpp#L27 standarc.cpp]] - * from Bitcoin Core + * @see + * [[https://github.com/bitcoin/bitcoin/blob/fa6180188b8ab89af97860e6497716405a48bab6/src/script/standard.h#L56 standard.h]] + * and + * [[https://github.com/bitcoin/bitcoin/blob/03732f8644a449af34f4df1bb3b8915fb15ef22c/src/script/standard.cpp#L27 standarc.cpp]] + * from Bitcoin Core */ sealed abstract class ScriptType { import org.bitcoins.core.script.ScriptType._ @@ -35,9 +37,11 @@ sealed abstract class ScriptType { /** The different Bitcoin Script type variations * - * @see [[https://github.com/bitcoin/bitcoin/blob/fa6180188b8ab89af97860e6497716405a48bab6/src/script/standard.h#L56 standard.h]] - * and [[https://github.com/bitcoin/bitcoin/blob/03732f8644a449af34f4df1bb3b8915fb15ef22c/src/script/standard.cpp#L27 standarc.cpp]] - * from Bitcoin Core + * @see + * [[https://github.com/bitcoin/bitcoin/blob/fa6180188b8ab89af97860e6497716405a48bab6/src/script/standard.h#L56 standard.h]] + * and + * [[https://github.com/bitcoin/bitcoin/blob/03732f8644a449af34f4df1bb3b8915fb15ef22c/src/script/standard.cpp#L27 standarc.cpp]] + * from Bitcoin Core */ object ScriptType extends StringFactory[ScriptType] { diff --git a/core/src/main/scala/org/bitcoins/core/script/arithmetic/ArithmeticInterpreter.scala b/core/src/main/scala/org/bitcoins/core/script/arithmetic/ArithmeticInterpreter.scala index 5579190ea1..ece65e4f4c 100644 --- a/core/src/main/scala/org/bitcoins/core/script/arithmetic/ArithmeticInterpreter.scala +++ b/core/src/main/scala/org/bitcoins/core/script/arithmetic/ArithmeticInterpreter.scala @@ -22,78 +22,104 @@ sealed abstract class ArithmeticInterpreter { /** a is added to b. */ def opAdd(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_ADD), - "Script top must be OP_ADD") + require( + program.script.headOption.contains(OP_ADD), + "Script top must be OP_ADD" + ) performBinaryArithmeticOperation(program, (x, y) => x + y) } /** Increments the stack top by 1. */ def op1Add( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_1ADD), - "Script top must be OP_1ADD") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_1ADD), + "Script top must be OP_1ADD" + ) performUnaryArithmeticOperation(program, x => x + ScriptNumber.one) } /** Decrements the stack top by 1. */ def op1Sub( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_1SUB), - "Script top must be OP_1SUB") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_1SUB), + "Script top must be OP_1SUB" + ) performUnaryArithmeticOperation(program, x => x - ScriptNumber.one) } /** b is subtracted from a. */ def opSub(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_SUB), - "Script top must be OP_SUB") + require( + program.script.headOption.contains(OP_SUB), + "Script top must be OP_SUB" + ) performBinaryArithmeticOperation(program, (x, y) => y - x) } /** Takes the absolute value of the stack top. */ def opAbs(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_ABS), - "Script top must be OP_ABS") + require( + program.script.headOption.contains(OP_ABS), + "Script top must be OP_ABS" + ) performUnaryArithmeticOperation( program, { case ScriptNumber.zero => ScriptNumber.zero case x @ (_: ScriptNumber) => ScriptNumber(x.toLong.abs) - }) + } + ) } /** Negates the stack top. */ def opNegate( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_NEGATE), - "Script top must be OP_NEGATE") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_NEGATE), + "Script top must be OP_NEGATE" + ) performUnaryArithmeticOperation(program, x => -x) } /** If the input is 0 or 1, it is flipped. Otherwise the output will be 0. */ def opNot(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_NOT), - "Script top must be OP_NOT") + require( + program.script.headOption.contains(OP_NOT), + "Script top must be OP_NOT" + ) performUnaryArithmeticOperation( program, - _ => if (program.stackTopIsFalse) OP_TRUE else OP_FALSE) + _ => if (program.stackTopIsFalse) OP_TRUE else OP_FALSE + ) } /** Returns 0 if the input is 0. 1 otherwise. */ def op0NotEqual( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_0NOTEQUAL), - "Script top must be OP_0NOTEQUAL") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_0NOTEQUAL), + "Script top must be OP_0NOTEQUAL" + ) performUnaryArithmeticOperation( program, - x => if (x.toLong == 0) OP_FALSE else OP_TRUE) + x => if (x.toLong == 0) OP_FALSE else OP_TRUE + ) } /** If both a and b are not 0, the output is 1. Otherwise 0. */ def opBoolAnd( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_BOOLAND), - "Script top must be OP_BOOLAND") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_BOOLAND), + "Script top must be OP_BOOLAND" + ) performBinaryBooleanOperation( program, (x, y) => { @@ -104,43 +130,56 @@ sealed abstract class ArithmeticInterpreter { /** If a or b is not 0, the output is 1. Otherwise 0. */ def opBoolOr( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_BOOLOR), - "Script top must be OP_BOOLOR") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_BOOLOR), + "Script top must be OP_BOOLOR" + ) performBinaryBooleanOperation( program, (x, y) => { !ScriptNumberUtil.isZero(x) || !ScriptNumberUtil.isZero(y) - }) + } + ) } /** Returns 1 if the numbers are equal, 0 otherwise. */ def opNumEqual( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_NUMEQUAL), - "Script top must be OP_NUMEQUAL") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_NUMEQUAL), + "Script top must be OP_NUMEQUAL" + ) performBinaryBooleanOperation(program, (x, y) => x.numEqual(y)) } - /** Same as [[org.bitcoins.core.script.arithmetic.OP_NUMEQUAL OP_NUMEQUAL]], but runs - * [[org.bitcoins.core.script.control.OP_VERIFY OP_VERIFY]] afterward. + /** Same as [[org.bitcoins.core.script.arithmetic.OP_NUMEQUAL OP_NUMEQUAL]], + * but runs [[org.bitcoins.core.script.control.OP_VERIFY OP_VERIFY]] + * afterward. */ def opNumEqualVerify( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_NUMEQUALVERIFY), - "Script top must be OP_NUMEQUALVERIFY") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_NUMEQUALVERIFY), + "Script top must be OP_NUMEQUALVERIFY" + ) if (program.stack.size < 2) { program.failExecution(ScriptErrorInvalidStackOperation) } else { val numEqualProgram = program.updateStackAndScript( program.stack, - OP_NUMEQUAL :: program.script.tail) + OP_NUMEQUAL :: program.script.tail + ) val numEqualResultOrError = opNumEqual(numEqualProgram) numEqualResultOrError match { case numEqualResult: ExecutionInProgressScriptProgram => val verifyProgram = numEqualResult.updateStackAndScript( numEqualResult.stack, - OP_VERIFY :: numEqualResult.script) + OP_VERIFY :: numEqualResult.script + ) val verifyResult = ControlOperationsInterpreter.opVerify(verifyProgram) verifyResult @@ -152,78 +191,106 @@ sealed abstract class ArithmeticInterpreter { /** Returns 1 if the numbers are not equal, 0 otherwise. */ def opNumNotEqual( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_NUMNOTEQUAL), - "Script top must be OP_NUMNOTEQUAL") - performBinaryBooleanOperation(program, - (x, y) => { - x.toLong != y.toLong - }) + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_NUMNOTEQUAL), + "Script top must be OP_NUMNOTEQUAL" + ) + performBinaryBooleanOperation( + program, + (x, y) => { + x.toLong != y.toLong + } + ) } /** Returns 1 if a is less than b, 0 otherwise. */ def opLessThan( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_LESSTHAN), - "Script top must be OP_LESSTHAN") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_LESSTHAN), + "Script top must be OP_LESSTHAN" + ) performBinaryBooleanOperation(program, (x, y) => y < x) } /** Returns 1 if a is greater than b, 0 otherwise. */ def opGreaterThan( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_GREATERTHAN), - "Script top must be OP_GREATERTHAN") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_GREATERTHAN), + "Script top must be OP_GREATERTHAN" + ) performBinaryBooleanOperation(program, (x, y) => y > x) } /** Returns 1 if a is less than or equal to b, 0 otherwise. */ def opLessThanOrEqual( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_LESSTHANOREQUAL), - "Script top must be OP_LESSTHANOREQUAL") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_LESSTHANOREQUAL), + "Script top must be OP_LESSTHANOREQUAL" + ) performBinaryBooleanOperation(program, (x, y) => y <= x) } /** Returns 1 if a is greater than or equal to b, 0 otherwise. */ def opGreaterThanOrEqual( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_GREATERTHANOREQUAL), - "Script top must be OP_GREATERTHANOREQUAL") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_GREATERTHANOREQUAL), + "Script top must be OP_GREATERTHANOREQUAL" + ) performBinaryBooleanOperation(program, (x, y) => y >= x) } /** Returns the smaller of a and b. */ def opMin(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_MIN), - "Script top must be OP_MIN") + require( + program.script.headOption.contains(OP_MIN), + "Script top must be OP_MIN" + ) if (program.stack.size < 2) { program.failExecution(ScriptErrorInvalidStackOperation) } else { performComparisonOnTwoStackTopItems( program, - (x: ScriptNumber, y: ScriptNumber) => if (x < y) x else y) + (x: ScriptNumber, y: ScriptNumber) => if (x < y) x else y + ) } } /** Returns the larger of a and b. */ def opMax(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_MAX), - "Script top must be OP_MAX") + require( + program.script.headOption.contains(OP_MAX), + "Script top must be OP_MAX" + ) if (program.stack.size < 2) { program.failExecution(ScriptErrorInvalidStackOperation) } else { performComparisonOnTwoStackTopItems( program, - (x: ScriptNumber, y: ScriptNumber) => if (x > y) x else y) + (x: ScriptNumber, y: ScriptNumber) => if (x > y) x else y + ) } } - /** Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. */ + /** Returns 1 if x is within the specified range (left-inclusive), 0 + * otherwise. + */ def opWithin( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_WITHIN), - "Script top must be OP_WITHIN") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_WITHIN), + "Script top must be OP_WITHIN" + ) if (program.stack.size < 3) { program.failExecution(ScriptErrorInvalidStackOperation) } else { @@ -240,35 +307,43 @@ sealed abstract class ArithmeticInterpreter { } else if ( isLargerThan4Bytes(c) || isLargerThan4Bytes(b) || isLargerThan4Bytes(a) ) { - //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here - //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 + // pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + // https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 program.failExecution(ScriptErrorUnknownError) } else { val isWithinRange = a >= b && a < c val newStackTop = if (isWithinRange) OP_TRUE else OP_FALSE program.updateStackAndScript( newStackTop :: program.stack.tail.tail.tail, - program.script.tail) + program.script.tail + ) } } } - /** This function checks if a number is <= 4 bytes in size - * We cannot perform arithmetic operations on bitcoin numbers that are larger than 4 bytes. + /** This function checks if a number is <= 4 bytes in size We cannot perform + * arithmetic operations on bitcoin numbers that are larger than 4 bytes. * https://github.com/bitcoin/bitcoin/blob/a6a860796a44a2805a58391a009ba22752f64e32/src/script/script.h#L214-L239. */ private def isLargerThan4Bytes(scriptNumber: ScriptNumber): Boolean = scriptNumber.bytes.size > 4 /** Performs the given arithmetic operation on the stack head - * @param program the program whose stack top is used as an argument for the arithmetic operation - * @param op the arithmetic operation that needs to be executed on the number, for instance incrementing by 1 - * @return the program with the result from performing the arithmetic operation pushed onto the top of the stack + * @param program + * the program whose stack top is used as an argument for the arithmetic + * operation + * @param op + * the arithmetic operation that needs to be executed on the number, for + * instance incrementing by 1 + * @return + * the program with the result from performing the arithmetic operation + * pushed onto the top of the stack */ @tailrec private def performUnaryArithmeticOperation( program: ExecutionInProgressScriptProgram, - op: ScriptNumber => ScriptNumber): StartedScriptProgram = { + op: ScriptNumber => ScriptNumber + ): StartedScriptProgram = { program.stack.headOption match { case None => program.failExecution(ScriptErrorInvalidStackOperation) @@ -279,13 +354,15 @@ sealed abstract class ArithmeticInterpreter { ) { program.failExecution(ScriptErrorMinimalData) } else if (isLargerThan4Bytes(s)) { - //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here - //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 + // pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + // https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 program.failExecution(ScriptErrorUnknownError) } else { val newScriptNumber = op(s) - program.updateStackAndScript(newScriptNumber :: program.stack.tail, - program.script.tail) + program.updateStackAndScript( + newScriptNumber :: program.stack.tail, + program.script.tail + ) } case Some(s: ScriptConstant) => if ( @@ -300,23 +377,28 @@ sealed abstract class ArithmeticInterpreter { performUnaryArithmeticOperation(newProgram, op) } case Some(_: ScriptToken) => - //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here - //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 + // pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + // https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 program.failExecution(ScriptErrorUnknownError) } } /** Performs the given arithmetic operation on the top two stack items - * @param program the program whose stack top is used as an argument for the arithmetic operation - * @param op the arithmetic operation that needs to be executed on the number, for instance incrementing by 1 - * @return the program with the result from performing the arithmetic operation pushed onto the top of the stack + * @param program + * the program whose stack top is used as an argument for the arithmetic + * operation + * @param op + * the arithmetic operation that needs to be executed on the number, for + * instance incrementing by 1 + * @return + * the program with the result from performing the arithmetic operation + * pushed onto the top of the stack */ @tailrec private def performBinaryArithmeticOperation( program: ExecutionInProgressScriptProgram, - op: ( - ScriptNumber, - ScriptNumber) => ScriptNumber): StartedScriptProgram = { + op: (ScriptNumber, ScriptNumber) => ScriptNumber + ): StartedScriptProgram = { if (program.stack.size < 2) { program.failExecution(ScriptErrorInvalidStackOperation) } else { @@ -324,22 +406,26 @@ sealed abstract class ArithmeticInterpreter { case (x: ScriptNumber, y: ScriptNumber) => if ( ScriptFlagUtil.requireMinimalData( - program.flags) && (!BitcoinScriptUtil + program.flags + ) && (!BitcoinScriptUtil .isShortestEncoding(x) || !BitcoinScriptUtil.isShortestEncoding( - y)) + y + )) ) { program.failExecution(ScriptErrorUnknownError) } else if (isLargerThan4Bytes(x) || isLargerThan4Bytes(y)) { - //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here - //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 + // pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + // https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 program.failExecution(ScriptErrorUnknownError) } else { val newStackTop = op(x, y) - program.updateStackAndScript(newStackTop :: program.stack.tail.tail, - program.script.tail) + program.updateStackAndScript( + newStackTop :: program.stack.tail.tail, + program.script.tail + ) } case (x: ScriptConstant, _: ScriptNumber) => - //interpret x as a number + // interpret x as a number val interpretedNumber = ScriptNumber(x.hex) val newProgram = program.updateStack(interpretedNumber :: program.stack.tail) @@ -350,28 +436,33 @@ sealed abstract class ArithmeticInterpreter { program.updateStack(x :: interpretedNumber :: program.stack.tail) performBinaryArithmeticOperation(newProgram, op) case (x: ScriptConstant, y: ScriptConstant) => - //interpret x and y as a number + // interpret x and y as a number val interpretedNumberX = ScriptNumber(x.hex) val interpretedNumberY = ScriptNumber(y.hex) val newProgram = program.updateStack( - interpretedNumberX :: interpretedNumberY :: program.stack.tail.tail) + interpretedNumberX :: interpretedNumberY :: program.stack.tail.tail + ) performBinaryArithmeticOperation(newProgram, op) case (_: ScriptToken, _: ScriptToken) => - //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here - //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 + // pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + // https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 program.failExecution(ScriptErrorUnknownError) } } } /** Compares two script numbers with the given boolean operation - * @param program the program whose two top stack elements are used for the comparison - * @param op the operation which compares the two script numbers - * @return the program with either OP_FALSE or OP_TRUE on the stack top + * @param program + * the program whose two top stack elements are used for the comparison + * @param op + * the operation which compares the two script numbers + * @return + * the program with either OP_FALSE or OP_TRUE on the stack top */ private def performBinaryBooleanOperation( program: ExecutionInProgressScriptProgram, - op: (ScriptNumber, ScriptNumber) => Boolean): StartedScriptProgram = { + op: (ScriptNumber, ScriptNumber) => Boolean + ): StartedScriptProgram = { if (program.stack.size < 2) { program.failExecution(ScriptErrorInvalidStackOperation) } else { @@ -383,58 +474,67 @@ sealed abstract class ArithmeticInterpreter { ) { program.failExecution(ScriptErrorUnknownError) } else if (isLargerThan4Bytes(x) || isLargerThan4Bytes(y)) { - //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here - //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 + // pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + // https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 program.failExecution(ScriptErrorUnknownError) } else { val newStackTop = if (op(x, y)) OP_TRUE else OP_FALSE - program.updateStackAndScript(newStackTop :: program.stack.tail.tail, - program.script.tail) + program.updateStackAndScript( + newStackTop :: program.stack.tail.tail, + program.script.tail + ) } } } - /** Takes the top two stack items, parses them to numbers then executes the op function on them and places the result - * onto the stack top - * @param program the script program whose two top stack items are used as arguments for op - * @param op the operation that needs to be executed on the two stack top items - * @return the program with the result of op pushed onto the top of the stack + /** Takes the top two stack items, parses them to numbers then executes the op + * function on them and places the result onto the stack top + * @param program + * the script program whose two top stack items are used as arguments for + * op + * @param op + * the operation that needs to be executed on the two stack top items + * @return + * the program with the result of op pushed onto the top of the stack */ private def performComparisonOnTwoStackTopItems( program: ExecutionInProgressScriptProgram, - op: ( - ScriptNumber, - ScriptNumber) => ScriptNumber): StartedScriptProgram = { + op: (ScriptNumber, ScriptNumber) => ScriptNumber + ): StartedScriptProgram = { performBinaryArithmeticOperation(program, op) } /** Takes the top two stack elements and parses them as script numbers - * @param program the program whose top two stack elements are being parsed as script numbers - * @return the tuple with the first element being the first stack element, the second element in the tuple being the second stack element + * @param program + * the program whose top two stack elements are being parsed as script + * numbers + * @return + * the tuple with the first element being the first stack element, the + * second element in the tuple being the second stack element */ private def parseTopTwoStackElementsAsScriptNumbers( - program: ExecutionInProgressScriptProgram): ( - ScriptNumber, - ScriptNumber) = { + program: ExecutionInProgressScriptProgram + ): (ScriptNumber, ScriptNumber) = { (program.stack.head, program.stack.tail.head) match { case (x: ScriptNumber, y: ScriptNumber) => (x, y) case (x: ScriptConstant, y: ScriptNumber) => val interpretedNumber = ScriptNumber(x.hex) (interpretedNumber, y) case (x: ScriptNumber, y: ScriptConstant) => - //interpret y as a number + // interpret y as a number val interpretedNumber = ScriptNumber(y.hex) (x, interpretedNumber) case (x: ScriptConstant, y: ScriptConstant) => - //interpret x and y as a number + // interpret x and y as a number val interpretedNumberX = ScriptNumber(x.hex) val interpretedNumberY = ScriptNumber(y.hex) (interpretedNumberX, interpretedNumberY) case (_: ScriptToken, _: ScriptToken) => - //pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here - //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 + // pretty sure that an error is thrown inside of CScriptNum which in turn is caught by interpreter.cpp here + // https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L999-L1002 throw new RuntimeException( - "Stack top elements must have be script constants to be interpreted as numbers") + "Stack top elements must have be script constants to be interpreted as numbers" + ) } } } diff --git a/core/src/main/scala/org/bitcoins/core/script/arithmetic/ArithmeticOperations.scala b/core/src/main/scala/org/bitcoins/core/script/arithmetic/ArithmeticOperations.scala index 4ce32e39cf..f3fc81fa7f 100644 --- a/core/src/main/scala/org/bitcoins/core/script/arithmetic/ArithmeticOperations.scala +++ b/core/src/main/scala/org/bitcoins/core/script/arithmetic/ArithmeticOperations.scala @@ -101,7 +101,8 @@ case object OP_MAX extends ArithmeticOperation { override val opCode: Int = 164 } -/** Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. */ +/** Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. + */ case object OP_WITHIN extends ArithmeticOperation { override val opCode: Int = 165 } diff --git a/core/src/main/scala/org/bitcoins/core/script/bitwise/BitwiseInterpreter.scala b/core/src/main/scala/org/bitcoins/core/script/bitwise/BitwiseInterpreter.scala index a0e67ca2ea..4152553068 100644 --- a/core/src/main/scala/org/bitcoins/core/script/bitwise/BitwiseInterpreter.scala +++ b/core/src/main/scala/org/bitcoins/core/script/bitwise/BitwiseInterpreter.scala @@ -18,9 +18,12 @@ sealed abstract class BitwiseInterpreter { /** Returns 1 if the inputs are exactly equal, 0 otherwise. */ def opEqual( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_EQUAL), - "Script operation must be OP_EQUAL") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_EQUAL), + "Script operation must be OP_EQUAL" + ) if (program.stack.size < 2) { program.failExecution(ScriptErrorInvalidStackOperation) } else { @@ -38,8 +41,10 @@ sealed abstract class BitwiseInterpreter { case _ => h.bytes == h1.bytes } val scriptBoolean = if (result) OP_TRUE else OP_FALSE - program.updateStackAndScript(scriptBoolean :: program.stack.tail.tail, - program.script.tail) + program.updateStackAndScript( + scriptBoolean :: program.stack.tail.tail, + program.script.tail + ) } } @@ -47,11 +52,14 @@ sealed abstract class BitwiseInterpreter { * [[org.bitcoins.core.script.control.OP_VERIFY OP_VERIFY]] afterward. */ def opEqualVerify( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_EQUALVERIFY), - "Script operation must be OP_EQUALVERIFY") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_EQUALVERIFY), + "Script operation must be OP_EQUALVERIFY" + ) if (program.stack.size > 1) { - //first replace OP_EQUALVERIFY with OP_EQUAL and OP_VERIFY + // first replace OP_EQUALVERIFY with OP_EQUAL and OP_VERIFY val simpleScript = OP_EQUAL :: OP_VERIFY :: program.script.tail val newProgram = opEqual(program.updateScript(simpleScript)) val verifiedOrErr = newProgram match { diff --git a/core/src/main/scala/org/bitcoins/core/script/bitwise/BitwiseOperations.scala b/core/src/main/scala/org/bitcoins/core/script/bitwise/BitwiseOperations.scala index b027c8d10b..a79f4f65e9 100644 --- a/core/src/main/scala/org/bitcoins/core/script/bitwise/BitwiseOperations.scala +++ b/core/src/main/scala/org/bitcoins/core/script/bitwise/BitwiseOperations.scala @@ -12,7 +12,9 @@ case object OP_EQUAL extends BitwiseOperation { override val opCode: Int = 135 } -/** Same as [[OP_EQUAL]], but runs [[org.bitcoins.core.script.control.OP_VERIFY]] afterward. */ +/** Same as [[OP_EQUAL]], but runs + * [[org.bitcoins.core.script.control.OP_VERIFY]] afterward. + */ case object OP_EQUALVERIFY extends BitwiseOperation { override val opCode: Int = 136 } diff --git a/core/src/main/scala/org/bitcoins/core/script/constant/BytesToPushOntoStack.scala b/core/src/main/scala/org/bitcoins/core/script/constant/BytesToPushOntoStack.scala index 13933c1d72..d15382bd21 100644 --- a/core/src/main/scala/org/bitcoins/core/script/constant/BytesToPushOntoStack.scala +++ b/core/src/main/scala/org/bitcoins/core/script/constant/BytesToPushOntoStack.scala @@ -2,8 +2,8 @@ package org.bitcoins.core.script.constant import org.bitcoins.core.script.ScriptOperationFactory -/** Created by chris on 1/9/16. - * Represents a the amount of bytes that need to be pushed onto the stack +/** Created by chris on 1/9/16. Represents a the amount of bytes that need to be + * pushed onto the stack */ trait BytesToPushOntoStack extends ScriptOperation @@ -30,14 +30,16 @@ object BytesToPushOntoStack def fromNumber(num: Long): BytesToPushOntoStack = { if (num > 75) throw new IllegalArgumentException( - "We cannot have a BytesToPushOntoStack for greater than 75 bytes") + "We cannot have a BytesToPushOntoStack for greater than 75 bytes" + ) else { val bytesToPushOntoStackOpt = operations.find(_.opCode == num) bytesToPushOntoStackOpt match { case Some(bytesToPushOntoStack) => bytesToPushOntoStack case None => throw new IllegalArgumentException( - s"We cannot have a BytesToPushOntoStack for greater than 75 bytes, got=$num") + s"We cannot have a BytesToPushOntoStack for greater than 75 bytes, got=$num" + ) } } } diff --git a/core/src/main/scala/org/bitcoins/core/script/constant/ConstantInterpreter.scala b/core/src/main/scala/org/bitcoins/core/script/constant/ConstantInterpreter.scala index f0b432c07b..e3b916788c 100644 --- a/core/src/main/scala/org/bitcoins/core/script/constant/ConstantInterpreter.scala +++ b/core/src/main/scala/org/bitcoins/core/script/constant/ConstantInterpreter.scala @@ -16,31 +16,47 @@ sealed abstract class ConstantInterpreter { /** The next byte contains the number of bytes to be pushed onto the stack. */ def opPushData1( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_PUSHDATA1), - "Top of script stack must be OP_PUSHDATA1") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_PUSHDATA1), + "Top of script stack must be OP_PUSHDATA1" + ) opPushData(program) } - /** The next two bytes contain the number of bytes to be pushed onto the stack. */ + /** The next two bytes contain the number of bytes to be pushed onto the + * stack. + */ def opPushData2( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_PUSHDATA2), - "Top of script stack must be OP_PUSHDATA2") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_PUSHDATA2), + "Top of script stack must be OP_PUSHDATA2" + ) opPushData(program) } - /** The next four bytes contain the number of bytes to be pushed onto the stack. */ + /** The next four bytes contain the number of bytes to be pushed onto the + * stack. + */ def opPushData4( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_PUSHDATA4), - "Top of script stack must be OP_PUSHDATA4") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_PUSHDATA4), + "Top of script stack must be OP_PUSHDATA4" + ) opPushData(program) } - /** Pushes the number of bytes onto the stack that is specified by script number on the script stack. */ + /** Pushes the number of bytes onto the stack that is specified by script + * number on the script stack. + */ def pushScriptNumberBytesToStack( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { val bytesNeeded: Long = program.script.head match { case OP_PUSHDATA1 | OP_PUSHDATA2 | OP_PUSHDATA4 => bytesNeededForPushOp(program.script(1)) @@ -51,15 +67,17 @@ sealed abstract class ConstantInterpreter { @tailrec def takeUntilBytesNeeded( scriptTokens: List[ScriptToken], - accum: List[ScriptToken]): (List[ScriptToken], List[ScriptToken]) = { + accum: List[ScriptToken] + ): (List[ScriptToken], List[ScriptToken]) = { val bytesSum = accum.map(_.bytes.size).sum if (bytesSum == bytesNeeded) (scriptTokens, accum) else if (scriptTokens.isEmpty) (Nil, accum) else if (bytesSum > bytesNeeded) throw new RuntimeException( - "We cannot have more bytes than what our script number specified") + "We cannot have more bytes than what our script number specified" + ) else { - //for the case when a ScriptNumberImpl(x) was parsed as a ByteToPushOntoStackImpl(x) + // for the case when a ScriptNumberImpl(x) was parsed as a ByteToPushOntoStackImpl(x) val scriptToken = scriptTokens.head match { case x: BytesToPushOntoStack => ScriptNumber(x.opCode) case x => x @@ -77,14 +95,16 @@ sealed abstract class ConstantInterpreter { if (bytesToPushOntoStack.size == 1) bytesToPushOntoStack.head else ScriptConstant( - BytesUtil.flipEndianness( - BytesUtil.toByteVector(bytesToPushOntoStack))) + BytesUtil.flipEndianness(BytesUtil.toByteVector(bytesToPushOntoStack)) + ) - //check to see if we have the exact amount of bytes needed to be pushed onto the stack - //if we do not, mark the program as invalid + // check to see if we have the exact amount of bytes needed to be pushed onto the stack + // if we do not, mark the program as invalid if (bytesNeeded == 0) - program.updateStackAndScript(ScriptNumber.zero :: program.stack, - newScript) + program.updateStackAndScript( + ScriptNumber.zero :: program.stack, + newScript + ) else if ( ScriptFlagUtil.requireMinimalData(program.flags) && bytesNeeded == 1 && constant.isInstanceOf[ScriptNumber] && constant.toLong <= 16 @@ -100,18 +120,22 @@ sealed abstract class ConstantInterpreter { } else program.updateStackAndScript(constant :: program.stack, newScript) } - /** Checks if the MINIMALDATA script flag is set, if so checks if we are using the minimal push operation - * if we are, then we push the bytes onto the stack. + /** Checks if the MINIMALDATA script flag is set, if so checks if we are using + * the minimal push operation if we are, then we push the bytes onto the + * stack. */ private def opPushData( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - //for the case where we have to push 0 bytes onto the stack, which is technically the empty byte vector + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + // for the case where we have to push 0 bytes onto the stack, which is technically the empty byte vector def emptyPush(): StartedScriptProgram = { if (ScriptFlagUtil.requireMinimalData(program.flags)) { program.failExecution(ScriptErrorMinimalData) } else { - program.updateStackAndScript(ScriptNumber.zero :: program.stack, - program.script.tail.tail) + program.updateStackAndScript( + ScriptNumber.zero :: program.stack, + program.script.tail.tail + ) } } @@ -123,7 +147,8 @@ sealed abstract class ConstantInterpreter { case _: ScriptToken => if ( ScriptFlagUtil.requireMinimalData( - program.flags) && program.script.size > 2 && !BitcoinScriptUtil + program.flags + ) && program.script.size > 2 && !BitcoinScriptUtil .isMinimalPush(program.script.head, program.script(2)) ) { program.failExecution(ScriptErrorMinimalData) @@ -145,7 +170,8 @@ sealed abstract class ConstantInterpreter { java.lang.Long.parseLong(constantFlippedEndianness, 16) case _ => throw new IllegalArgumentException( - "Token must be BytesToPushOntoStack to push a number of bytes onto the stack") + "Token must be BytesToPushOntoStack to push a number of bytes onto the stack" + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/script/constant/Constants.scala b/core/src/main/scala/org/bitcoins/core/script/constant/Constants.scala index 6c4739dd7a..06e3e623be 100644 --- a/core/src/main/scala/org/bitcoins/core/script/constant/Constants.scala +++ b/core/src/main/scala/org/bitcoins/core/script/constant/Constants.scala @@ -18,7 +18,9 @@ sealed trait ScriptToken extends NetworkElement { /** The byte representation of this [[ScriptToken]]. */ def bytes: ByteVector - /** The conversion from the byte representation of a [[ScriptToken]] to a number. */ + /** The conversion from the byte representation of a [[ScriptToken]] to a + * number. + */ def toLong: Long = ScriptNumberUtil.toLong(bytes) } @@ -36,7 +38,8 @@ trait ScriptOperation extends ScriptToken { /** A constant in the Script language for instance as String or a number. */ sealed abstract class ScriptConstant extends ScriptToken { - /** Returns if the [[ScriptConstant]] is encoded in the shortest possible way. */ + /** Returns if the [[ScriptConstant]] is encoded in the shortest possible way. + */ def isShortestEncoding: Boolean = BitcoinScriptUtil.isShortestEncoding(this) } @@ -75,8 +78,9 @@ sealed abstract class ScriptNumber def |(that: ScriptNumber): ScriptNumber = ScriptNumber(underlying | that.underlying) - /** This equality just checks that the underlying scala numbers are equivalent, NOT if the numbers - * are bitwise equivalent in Script. For instance ScriptNumber(0x01).numEqual(ScriptNumber(0x00000000001)) == true + /** This equality just checks that the underlying scala numbers are + * equivalent, NOT if the numbers are bitwise equivalent in Script. For + * instance ScriptNumber(0x01).numEqual(ScriptNumber(0x00000000001)) == true * but (ScriptNumber(0x01) == (ScriptNumber(0x00000000001))) == false. */ def numEqual(that: ScriptNumber): Boolean = underlying == that.underlying @@ -115,30 +119,34 @@ object ScriptNumber override def fromBytes(bytes: ByteVector) = { if (bytes.isEmpty) zero else if (BitcoinScriptUtil.isShortestEncoding(bytes)) { - //if it's the shortest encoding possible, use our cache + // if it's the shortest encoding possible, use our cache checkCached(ScriptNumberUtil.toLong(bytes)) } else { - //else we need to preserve the byte level encoding - //as Script at the consensus level does not - //enforce minimal encoding of numbers + // else we need to preserve the byte level encoding + // as Script at the consensus level does not + // enforce minimal encoding of numbers ScriptNumberImpl(ScriptNumberUtil.toLong(bytes), bytes) } } def fromBytes( bytes: ByteVector, - requireMinimal: Boolean): Try[ScriptNumber] = { + requireMinimal: Boolean + ): Try[ScriptNumber] = { if (requireMinimal && !BitcoinScriptUtil.isShortestEncoding(bytes)) { - Failure(new IllegalArgumentException( - s"The given hex was not the shortest encoding for the script number: ${bytes.toHex}")) + Failure( + new IllegalArgumentException( + s"The given hex was not the shortest encoding for the script number: ${bytes.toHex}" + ) + ) } else if (requireMinimal) { - //our cache contains minimal encoded script numbers - //so we can check our cache to try and avoid allocating + // our cache contains minimal encoded script numbers + // so we can check our cache to try and avoid allocating val number = ScriptNumberUtil.toLong(bytes) Success(checkCached(number)) } else { - //if minimal encoding is not required, unfortunately we need to - //store the byte representation that came off the wire. + // if minimal encoding is not required, unfortunately we need to + // store the byte representation that came off the wire. Try(fromBytes(bytes)) } } @@ -162,8 +170,8 @@ object ScriptNumber ScriptNumberImpl(long) } - /** Companion object for [[ScriptNumberImpl]] that gives us access to more constructor types for the - * [[ScriptNumberImpl]] case class. + /** Companion object for [[ScriptNumberImpl]] that gives us access to more + * constructor types for the [[ScriptNumberImpl]] case class. */ private object ScriptNumberImpl { @@ -174,8 +182,10 @@ object ScriptNumber ScriptNumberImpl(ScriptNumberUtil.toLong(bytes)) def apply(underlying: Long): ScriptNumber = { - ScriptNumberImpl(underlying, - ScriptNumberUtil.longToByteVector(underlying)) + ScriptNumberImpl( + underlying, + ScriptNumberUtil.longToByteVector(underlying) + ) } def apply(int64: Int64): ScriptNumber = checkCached(int64.toLong) @@ -191,7 +201,8 @@ case object OP_PUSHDATA1 extends ScriptOperation { def max = 255 } -/** The next two bytes contain the number of bytes to be pushed onto the stack. */ +/** The next two bytes contain the number of bytes to be pushed onto the stack. + */ case object OP_PUSHDATA2 extends ScriptOperation { override val opCode: Int = 77 @@ -199,7 +210,8 @@ case object OP_PUSHDATA2 extends ScriptOperation { def max = 65535 } -/** The next four bytes contain the number of bytes to be pushed onto the stack. */ +/** The next four bytes contain the number of bytes to be pushed onto the stack. + */ case object OP_PUSHDATA4 extends ScriptOperation { override val opCode: Int = 78 @@ -207,16 +219,17 @@ case object OP_PUSHDATA4 extends ScriptOperation { def max = 4294967295L } -/** Represents a [[ScriptNumberOperation]] where the the number in the operation is pushed onto the stack - * i.e. OP_0 would be push 0 onto the stack, OP_1 would be push 1 onto the stack. +/** Represents a [[ScriptNumberOperation]] where the the number in the operation + * is pushed onto the stack i.e. OP_0 would be push 0 onto the stack, OP_1 + * would be push 1 onto the stack. */ sealed abstract class ScriptNumberOperation extends ScriptNumber with ScriptOperation { override def hex = opCode.toHexString - /** This is required so that OP_TRUE == OP_1 and - * OP_FALSE == OP_0 will both be true + /** This is required so that OP_TRUE == OP_1 and OP_FALSE == OP_0 will both be + * true */ override def equals(obj: Any): Boolean = { obj match { @@ -228,7 +241,9 @@ sealed abstract class ScriptNumberOperation } } -/** An empty array of bytes is pushed onto the stack. (This is not a no-op: an item is added to the stack.) */ +/** An empty array of bytes is pushed onto the stack. (This is not a no-op: an + * item is added to the stack.) + */ case object OP_0 extends ScriptNumberOperation { override val opCode: Int = 0 @@ -237,7 +252,9 @@ case object OP_0 extends ScriptNumberOperation { override val underlying: Long = 0 } -/** An empty array of bytes is pushed onto the stack. (This is not a no-op: an item is added to the stack.) */ +/** An empty array of bytes is pushed onto the stack. (This is not a no-op: an + * item is added to the stack.) + */ case object OP_FALSE extends ScriptNumberOperation { override val opCode = OP_0.opCode @@ -381,24 +398,26 @@ object ScriptNumberOperation def fromNumber(underlying: Long): Option[ScriptNumberOperation] = operations.find(_.underlying == underlying) - override val operations = Vector(OP_0, - OP_1, - OP_1NEGATE, - OP_2, - OP_3, - OP_4, - OP_5, - OP_6, - OP_7, - OP_8, - OP_9, - OP_10, - OP_11, - OP_12, - OP_13, - OP_14, - OP_15, - OP_16) + override val operations = Vector( + OP_0, + OP_1, + OP_1NEGATE, + OP_2, + OP_3, + OP_4, + OP_5, + OP_6, + OP_7, + OP_8, + OP_9, + OP_10, + OP_11, + OP_12, + OP_13, + OP_14, + OP_15, + OP_16 + ) } diff --git a/core/src/main/scala/org/bitcoins/core/script/constant/ScriptNumberUtil.scala b/core/src/main/scala/org/bitcoins/core/script/constant/ScriptNumberUtil.scala index 485dbe400f..6837c09c7a 100644 --- a/core/src/main/scala/org/bitcoins/core/script/constant/ScriptNumberUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/script/constant/ScriptNumberUtil.scala @@ -3,50 +3,53 @@ package org.bitcoins.core.script.constant import org.bitcoins.core.util.BytesUtil import scodec.bits.ByteVector -/** Created by chris on 6/5/16. - * Numbers in script are unique in the fact that they don't follow a conventional signed numbering system - * such as ones complement or twos complement. The bitcoin protocol uses little endian notation which means the most - * significant bit indicates the sign on the number we are interpreting. The rest of the bits are used to determine - * what that number is. See this irc log for more info +/** Created by chris on 6/5/16. Numbers in script are unique in the fact that + * they don't follow a conventional signed numbering system such as ones + * complement or twos complement. The bitcoin protocol uses little endian + * notation which means the most significant bit indicates the sign on the + * number we are interpreting. The rest of the bits are used to determine what + * that number is. See this irc log for more info * https://botbot.me/freenode/bitcoin-core-dev/2016-06-06/?tz=America/Chicago */ trait ScriptNumberUtil { - /** Takes a hex number and converts it into a signed number - * used in the bitcoin script's numbering system. - * This function interprets the bytes as little endian numbers - * This should only be used for numbers inside of Script + /** Takes a hex number and converts it into a signed number used in the + * bitcoin script's numbering system. This function interprets the bytes as + * little endian numbers This should only be used for numbers inside of + * Script * * @param hex * @return */ def toLong(hex: String): Long = toLong(BytesUtil.decodeHex(hex)) - /** Takes in a hex string and converts it into a signed number - * This function interprets the bytes as little endian numbers - * This should only be used for numbers inside of Script + /** Takes in a hex string and converts it into a signed number This function + * interprets the bytes as little endian numbers This should only be used for + * numbers inside of Script * * @param hex * @return */ def toInt(hex: String): Int = toInt(BytesUtil.decodeHex(hex)) - /** Takes in a sequence of bytes and converts it into a signed number - * This should only be used for numbers inside of Script + /** Takes in a sequence of bytes and converts it into a signed number This + * should only be used for numbers inside of Script * * @param bytes * @return */ def toInt(bytes: ByteVector): Int = { - require(bytes.size <= 4, - "We cannot have an integer with more than 4 bytes (32 bits)") + require( + bytes.size <= 4, + "We cannot have an integer with more than 4 bytes (32 bits)" + ) toLong(bytes).toInt } - /** Takes a sequence of bytes and converts it in to signed number inside of bitcoin - * script's numbering system - * This function interprets the bytes as little endian numbers - * This should only be used for numbers inside of Script + /** Takes a sequence of bytes and converts it in to signed number inside of + * bitcoin script's numbering system This function interprets the bytes as + * little endian numbers This should only be used for numbers inside of + * Script * * @param bytes * @return @@ -54,14 +57,14 @@ trait ScriptNumberUtil { def toLong(bytes: ByteVector): Long = { val reversedBytes = bytes.reverse if (bytes.size == 1 && bytes.head == -128) { - //the case for negative zero + // the case for negative zero 0 } else if (isPositive(bytes)) { if (firstByteAllZeros(reversedBytes) && reversedBytes.size > 1) { parseLong(reversedBytes.slice(1, reversedBytes.size)) } else parseLong(reversedBytes) } else { - //remove the sign bit + // remove the sign bit val removedSignBit = changeSignBitToPositive(reversedBytes) if (firstByteAllZeros(removedSignBit)) -parseLong(removedSignBit.slice(1, removedSignBit.size)) @@ -103,7 +106,8 @@ trait ScriptNumberUtil { private def parseLong(hex: String): Long = java.lang.Long.parseLong(hex, 16) - /** Converts a long number to the representation of number inside of Bitcoin script's number system + /** Converts a long number to the representation of number inside of Bitcoin + * script's number system * * @param long * @return @@ -120,7 +124,7 @@ trait ScriptNumberUtil { bytes.reverse } else { val bytes = toByteVec(long.abs) - //add sign bit + // add sign bit val negativeNumberBytes = changeSignBitToNegative(bytes) negativeNumberBytes.reverse } @@ -157,10 +161,10 @@ trait ScriptNumberUtil { def firstByteAllZeros(hex: String): Boolean = firstByteAllZeros(BytesUtil.decodeHex(hex)) - /** Checks if the two given [[ScriptNumber numbers]] are equivalent to zero - * in Script. Unfortunatey Script is one's complement which means we have - * things like negative zero, and also there isn't an enforcement of a - * minimal representation of zero, which means 0x00 = 0x0000 = 0x0000000.. == OP_0 + /** Checks if the two given [[ScriptNumber numbers]] are equivalent to zero in + * Script. Unfortunatey Script is one's complement which means we have things + * like negative zero, and also there isn't an enforcement of a minimal + * representation of zero, which means 0x00 = 0x0000 = 0x0000000.. == OP_0 */ def isZero(x: ScriptNumber): Boolean = { val xIsFalse = x == ScriptNumber.zero || x == OP_0 diff --git a/core/src/main/scala/org/bitcoins/core/script/constant/StackPushOperationFactory.scala b/core/src/main/scala/org/bitcoins/core/script/constant/StackPushOperationFactory.scala index 6b6e7d387e..cf16db9d1a 100644 --- a/core/src/main/scala/org/bitcoins/core/script/constant/StackPushOperationFactory.scala +++ b/core/src/main/scala/org/bitcoins/core/script/constant/StackPushOperationFactory.scala @@ -6,8 +6,10 @@ trait StackPushOperationFactory { /** Determines if the given token is a stack push operation * - * @param token the token to be checked to see if it is a stack push operation - * @return a boolean indicating if the given token was a stack push operation + * @param token + * the token to be checked to see if it is a stack push operation + * @return + * a boolean indicating if the given token was a stack push operation */ def isPushOperation(token: ScriptToken): Boolean = operations.contains(token) @@ -22,26 +24,28 @@ trait StackPushOperationFactory { */ private val operations = pushDataOperations ++ BytesToPushOntoStack.operations ++ - Seq(OP_0, - OP_1, - OP_1NEGATE, - OP_2, - OP_3, - OP_4, - OP_5, - OP_6, - OP_7, - OP_8, - OP_9, - OP_10, - OP_11, - OP_12, - OP_13, - OP_14, - OP_15, - OP_16, - OP_FALSE, - OP_TRUE) + Seq( + OP_0, + OP_1, + OP_1NEGATE, + OP_2, + OP_3, + OP_4, + OP_5, + OP_6, + OP_7, + OP_8, + OP_9, + OP_10, + OP_11, + OP_12, + OP_13, + OP_14, + OP_15, + OP_16, + OP_FALSE, + OP_TRUE + ) } object StackPushOperationFactory extends StackPushOperationFactory diff --git a/core/src/main/scala/org/bitcoins/core/script/control/ControlOperations.scala b/core/src/main/scala/org/bitcoins/core/script/control/ControlOperations.scala index 31a6e57b9c..a00a87b163 100644 --- a/core/src/main/scala/org/bitcoins/core/script/control/ControlOperations.scala +++ b/core/src/main/scala/org/bitcoins/core/script/control/ControlOperations.scala @@ -10,18 +10,23 @@ sealed abstract class ControlOperations extends ScriptOperation /** Type for { OP_IF, OP_NOTIF } */ sealed abstract class ConditionalOperation extends ControlOperations -/** If the top stack value is not 0, the statements are executed. The top stack value is removed. */ +/** If the top stack value is not 0, the statements are executed. The top stack + * value is removed. + */ case object OP_IF extends ConditionalOperation { override val opCode: Int = 99 } -/** If the top stack value is 0, the statements are executed. The top stack value is removed. */ +/** If the top stack value is 0, the statements are executed. The top stack + * value is removed. + */ case object OP_NOTIF extends ConditionalOperation { override val opCode: Int = 100 } -/** If the preceding `OP_IF` or `OP_NOTIF` or `OP_ELSE` was not executed then these statements are and - * if the preceding `OP_IF` or `OP_NOTIF` or `OP_ELSE` was executed then these statements are not. +/** If the preceding `OP_IF` or `OP_NOTIF` or `OP_ELSE` was not executed then + * these statements are and if the preceding `OP_IF` or `OP_NOTIF` or `OP_ELSE` + * was executed then these statements are not. */ case object OP_ELSE extends ControlOperations { override val opCode: Int = 103 @@ -39,12 +44,13 @@ case object OP_VERIFY extends ControlOperations { override val opCode: Int = 105 } -/** Marks transaction as invalid. A standard way of attaching extra data to transactions is to add a zero-value - * output with a scriptPubKey consisting of `OP_RETURN` followed by exactly one pushdata op. - * Such outputs are provably unspendable, reducing their cost to the network. - * Currently it is usually considered non-standard - * (though valid) for a transaction to have more than one `OP_RETURN` output or an `OP_RETURN` output - * with more than one pushdata op. +/** Marks transaction as invalid. A standard way of attaching extra data to + * transactions is to add a zero-value output with a scriptPubKey consisting of + * `OP_RETURN` followed by exactly one pushdata op. Such outputs are provably + * unspendable, reducing their cost to the network. Currently it is usually + * considered non-standard (though valid) for a transaction to have more than + * one `OP_RETURN` output or an `OP_RETURN` output with more than one pushdata + * op. */ case object OP_RETURN extends ControlOperations { override val opCode: Int = 106 diff --git a/core/src/main/scala/org/bitcoins/core/script/control/ControlOperationsInterpreter.scala b/core/src/main/scala/org/bitcoins/core/script/control/ControlOperationsInterpreter.scala index 543a23f32a..25b4361eae 100644 --- a/core/src/main/scala/org/bitcoins/core/script/control/ControlOperationsInterpreter.scala +++ b/core/src/main/scala/org/bitcoins/core/script/control/ControlOperationsInterpreter.scala @@ -15,10 +15,13 @@ import org.bitcoins.core.util._ sealed abstract class ControlOperationsInterpreter { /** Factors out the similarities between OP_IF and OP_NOTIF */ - private def opConditional(conditional: ConditionalOperation)( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(conditional), - s"Script top was not $conditional") + private def opConditional( + conditional: ConditionalOperation + )(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { + require( + program.script.headOption.contains(conditional), + s"Script top was not $conditional" + ) if (program.isInExecutionBranch) { val sigVersion = program.txSignatureComponent.sigVersion @@ -57,9 +60,10 @@ sealed abstract class ControlOperationsInterpreter { private def isNotMinimalStackTop( stackTop: ScriptToken, sigVersion: SignatureVersion, - minimalIfEnabled: Boolean): Boolean = { - //see: https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L447-L452 - //https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-August/013014.html + minimalIfEnabled: Boolean + ): Boolean = { + // see: https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L447-L452 + // https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-August/013014.html val correctSigVersion = sigVersion == SigVersionWitnessV0 || sigVersion == SigVersionTapscript @@ -67,54 +71,77 @@ sealed abstract class ControlOperationsInterpreter { && !BitcoinScriptUtil.isMinimalToken(stackTop)) } - /** If the top stack value is not 0, the statements are executed. The top stack value is removed. */ + /** If the top stack value is not 0, the statements are executed. The top + * stack value is removed. + */ def opIf(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { opConditional(OP_IF)(program) } - /** If the top stack value is 0, the statements are executed. The top stack value is removed. */ + /** If the top stack value is 0, the statements are executed. The top stack + * value is removed. + */ def opNotIf( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { opConditional(OP_NOTIF)(program) } - /** Evaluates the [[org.bitcoins.core.script.control.OP_ELSE OP_ELSE]] operator. */ + /** Evaluates the [[org.bitcoins.core.script.control.OP_ELSE OP_ELSE]] + * operator. + */ def opElse( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_ELSE), - "First script opt must be OP_ELSE") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_ELSE), + "First script opt must be OP_ELSE" + ) program.updateScript(program.script.tail).invertCondition() } - /** Evaluates an [[org.bitcoins.core.script.control.OP_ENDIF OP_ENDIF]] operator. */ + /** Evaluates an [[org.bitcoins.core.script.control.OP_ENDIF OP_ENDIF]] + * operator. + */ def opEndIf( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_ENDIF), - "Script top must be OP_ENDIF") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_ENDIF), + "Script top must be OP_ENDIF" + ) program.updateScript(program.script.tail).removeCondition() } - /** Marks transaction as invalid. A standard way of attaching extra data to transactions is to add a zero-value output - * with a [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] consisting of - * [[org.bitcoins.core.script.control.OP_RETURN OP_RETURN]] followed by exactly one pushdata op. - * Such outputs are provably unspendable, - * reducing their cost to the network. Currently it is usually considered non-standard (though valid) for - * a transaction to - * have more than one [[org.bitcoins.core.script.control.OP_RETURN OP_RETURN]] output or an - * [[org.bitcoins.core.script.control.OP_RETURN OP_RETURN]] output with more than one pushdata op. + /** Marks transaction as invalid. A standard way of attaching extra data to + * transactions is to add a zero-value output with a + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] consisting + * of [[org.bitcoins.core.script.control.OP_RETURN OP_RETURN]] followed by + * exactly one pushdata op. Such outputs are provably unspendable, reducing + * their cost to the network. Currently it is usually considered non-standard + * (though valid) for a transaction to have more than one + * [[org.bitcoins.core.script.control.OP_RETURN OP_RETURN]] output or an + * [[org.bitcoins.core.script.control.OP_RETURN OP_RETURN]] output with more + * than one pushdata op. */ def opReturn( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { require(program.script.headOption.contains(OP_RETURN)) program.failExecution(ScriptErrorOpReturn) } - /** Marks [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] as invalid if top stack value is not true. */ + /** Marks [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] + * as invalid if top stack value is not true. + */ def opVerify( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_VERIFY), - "Script top must be OP_VERIFY") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_VERIFY), + "Script top must be OP_VERIFY" + ) program.stack.nonEmpty match { case true => if (program.stackTopIsFalse) program.failExecution(ScriptErrorVerify) diff --git a/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoInterpreter.scala b/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoInterpreter.scala index 9f1ba07a33..72642de147 100644 --- a/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoInterpreter.scala +++ b/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoInterpreter.scala @@ -29,55 +29,72 @@ sealed abstract class CryptoInterpreter { /** The input is hashed twice: first with SHA-256 and then with RIPEMD-160. */ def opHash160( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_HASH160), - "Script operation must be OP_HASH160") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_HASH160), + "Script operation must be OP_HASH160" + ) executeHashFunction(program, CryptoUtil.sha256Hash160(_: ByteVector)) } /** The input is hashed using RIPEMD-160. */ def opRipeMd160( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_RIPEMD160), - "Script operation must be OP_RIPEMD160") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_RIPEMD160), + "Script operation must be OP_RIPEMD160" + ) executeHashFunction(program, CryptoUtil.ripeMd160(_: ByteVector)) } /** The input is hashed using SHA-256. */ def opSha256( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_SHA256), - "Script operation must be OP_SHA256") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_SHA256), + "Script operation must be OP_SHA256" + ) executeHashFunction(program, CryptoUtil.sha256(_: ByteVector)) } /** The input is hashed two times with SHA-256. */ def opHash256( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_HASH256), - "Script operation must be OP_HASH256") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_HASH256), + "Script operation must be OP_HASH256" + ) executeHashFunction(program, CryptoUtil.doubleSHA256(_: ByteVector)) } /** The input is hashed using SHA-1. */ def opSha1( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_SHA1), - "Script top must be OP_SHA1") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_SHA1), + "Script top must be OP_SHA1" + ) executeHashFunction(program, CryptoUtil.sha1(_: ByteVector)) } /** The entire transaction's outputs, inputs, and script (from the most - * recently-executed OP_CODESEPARATOR to the end) are hashed. - * The signature used by - * [[org.bitcoins.core.script.crypto.OP_CHECKSIG OP_CHECKSIG]] - * must be a valid signature for this hash and public key. + * recently-executed OP_CODESEPARATOR to the end) are hashed. The signature + * used by [[org.bitcoins.core.script.crypto.OP_CHECKSIG OP_CHECKSIG]] must + * be a valid signature for this hash and public key. * [[https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L880]] */ def opCheckSig( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_CHECKSIG), - "Script top must be OP_CHECKSIG") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_CHECKSIG), + "Script top must be OP_CHECKSIG" + ) if (program.stack.size < 2) { program.failExecution(ScriptErrorInvalidStackOperation) } else { @@ -105,45 +122,52 @@ sealed abstract class CryptoInterpreter { removedOpCodeSeparatorsScript, pubKey, signature, - flags) - handleSignatureValidation(program = updatedProgram, - result = result, - restOfStack = restOfStack, - numOpt = None) + flags + ) + handleSignatureValidation( + program = updatedProgram, + result = result, + restOfStack = restOfStack, + numOpt = None + ) case SigVersionTapscript => - val tapscriptE: Either[ - ScriptError, - TransactionSignatureCheckerResult] = evalChecksigTapscript( - updatedProgram) + val tapscriptE + : Either[ScriptError, TransactionSignatureCheckerResult] = + evalChecksigTapscript(updatedProgram) tapscriptE match { case Left(err) => if ( err == ScriptErrorDiscourageUpgradablePubkeyType && !ScriptFlagUtil .discourageUpgradablePublicKey(flags) ) { - //trivially pass signature validation as required by BIP342 - //when the public key type is not known and the - //SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE is NOT set - handleSignatureValidation(program = updatedProgram, - result = SignatureValidationSuccess, - restOfStack = restOfStack, - numOpt = None) + // trivially pass signature validation as required by BIP342 + // when the public key type is not known and the + // SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE is NOT set + handleSignatureValidation( + program = updatedProgram, + result = SignatureValidationSuccess, + restOfStack = restOfStack, + numOpt = None + ) } else if (err == ScriptErrorEvalFalse) { - //means signature validation failed, don't increment the stack counter + // means signature validation failed, don't increment the stack counter handleSignatureValidation( program = updatedProgram, result = SignatureValidationErrorIncorrectSignatures, restOfStack = restOfStack, - numOpt = None) + numOpt = None + ) } else { updatedProgram.failExecution(err) } case Right(result) => - handleSignatureValidation(program = updatedProgram, - result = result, - restOfStack = restOfStack, - numOpt = None) + handleSignatureValidation( + program = updatedProgram, + result = result, + restOfStack = restOfStack, + numOpt = None + ) } case SigVersionTaprootKeySpend => @@ -153,13 +177,12 @@ sealed abstract class CryptoInterpreter { } } - /** Gets the signature and hash type, returns None - * if the signature is the empty byte vector which trivially - * fails script interpreter validation + /** Gets the signature and hash type, returns None if the signature is the + * empty byte vector which trivially fails script interpreter validation */ - private def getSignatureAndHashType(sigBytes: ByteVector): Either[ - ScriptError, - (SchnorrDigitalSignature, HashType)] = { + private def getSignatureAndHashType( + sigBytes: ByteVector + ): Either[ScriptError, (SchnorrDigitalSignature, HashType)] = { val parseT = Try(if (sigBytes.length == 64) { val sig = SchnorrDigitalSignature.fromBytes(sigBytes) Right((sig, HashType.sigHashDefault)) @@ -176,9 +199,8 @@ sealed abstract class CryptoInterpreter { } private def evalChecksigTapscript( - program: ExecutionInProgressScriptProgram): Either[ - ScriptError, - TransactionSignatureCheckerResult] = { + program: ExecutionInProgressScriptProgram + ): Either[ScriptError, TransactionSignatureCheckerResult] = { val stack = program.stack val pubKeyBytes = stack.head.bytes val isCheckSigAdd = program.script.head == OP_CHECKSIGADD @@ -194,38 +216,40 @@ sealed abstract class CryptoInterpreter { val discourageUpgradablePubKey = ScriptFlagUtil.discourageUpgradablePublicKey(program.flags) - //need to do weight validation + // need to do weight validation if (pubKeyBytes.isEmpty) { - //this failure catches two types of errors, if the pubkey is empty - //and if its using an "upgraded" pubkey from a future soft fork - //from bip342: - //If the public key size is not zero and not 32 bytes, the public key is of an unknown public key type[6] and no actual signature verification is applied. - //During script execution of signature opcodes they behave exactly as known public key types except that signature validation is considered to be successful. - //see: https://github.com/bitcoin/bitcoin/blob/9e4fbebcc8e497016563e46de4c64fa094edab2d/src/script/interpreter.cpp#L374 + // this failure catches two types of errors, if the pubkey is empty + // and if its using an "upgraded" pubkey from a future soft fork + // from bip342: + // If the public key size is not zero and not 32 bytes, the public key is of an unknown public key type[6] and no actual signature verification is applied. + // During script execution of signature opcodes they behave exactly as known public key types except that signature validation is considered to be successful. + // see: https://github.com/bitcoin/bitcoin/blob/9e4fbebcc8e497016563e46de4c64fa094edab2d/src/script/interpreter.cpp#L374 Left(ScriptErrorPubKeyType) } else if (sigBytes.isEmpty) { - //fail if we don't have a signature + // fail if we don't have a signature Left(ScriptErrorEvalFalse) } else if (discourageUpgradablePubKey && xOnlyPubKeyT.isFailure) { Left(ScriptErrorDiscourageUpgradablePubkeyType) } else if (!discourageUpgradablePubKey && pubKeyBytes.length != 32) { // if the public key is not valid, and we aren't discouraging upgradable public keys - //the script trivially succeeds so that we maintain soft fork compatability for - //new public key types in the feature + // the script trivially succeeds so that we maintain soft fork compatability for + // new public key types in the feature Right(SignatureValidationSuccess) } else if (xOnlyPubKeyT.isFailure) { - //how can this key be a failure if its 32 bytes in size? + // how can this key be a failure if its 32 bytes in size? sys.error(s"Invalid pubkey with 32 bytes in size, got=${xOnlyPubKeyT}") } else { val helperE: Either[ScriptError, TapscriptChecksigHelper] = { val sigHashTypeE = getSignatureAndHashType(sigBytes) sigHashTypeE.map { case (signature, hashType) => val restOfStack = - program.stack.tail.tail //remove pubkey, signature - val helper = TapscriptChecksigHelper(pubKey = xOnlyPubKeyT.get, - signature = signature, - hashType = hashType, - restOfStack = restOfStack) + program.stack.tail.tail // remove pubkey, signature + val helper = TapscriptChecksigHelper( + pubKey = xOnlyPubKeyT.get, + signature = signature, + hashType = hashType, + restOfStack = restOfStack + ) helper } } @@ -253,9 +277,12 @@ sealed abstract class CryptoInterpreter { * [[org.bitcoins.core.script.control.OP_VERIFY OP_VERIFY]] afterwards. */ def opCheckSigVerify( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_CHECKSIGVERIFY), - "Script top must be OP_CHECKSIGVERIFY") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_CHECKSIGVERIFY), + "Script top must be OP_CHECKSIGVERIFY" + ) if (program.stack.size < 2) { program.failExecution(ScriptErrorInvalidStackOperation) } else { @@ -276,9 +303,12 @@ sealed abstract class CryptoInterpreter { * [[org.bitcoins.core.script.crypto.OP_CODESEPARATOR OP_CODESEPARATOR]]. */ def opCodeSeparator( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_CODESEPARATOR), - "Script top must be OP_CODESEPARATOR") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_CODESEPARATOR), + "Script top must be OP_CODESEPARATOR" + ) // Filter out the constants for Tapscript OP_CODESEPARATORs // because we only count op codes @@ -297,20 +327,25 @@ sealed abstract class CryptoInterpreter { .updateTapscriptCodeSeparatorIdx(indexOfOpCodeSeparator - constants) } - /** Compares the first signature against each public key until it finds an ECDSA match. - * Starting with the subsequent public key, it compares the second signature against each remaining - * public key until it finds an ECDSA match. The process is repeated until all signatures have been - * checked or not enough public keys remain to produce a successful result. - * All signatures need to match a public key. - * Because public keys are not checked again if they fail any signature comparison, - * signatures must be placed in the scriptSig using the same order as their corresponding public keys - * were placed in the scriptPubKey or redeemScript. If all signatures are valid, 1 is returned, 0 otherwise. - * Due to a bug, one extra unused value is removed from the stack. + /** Compares the first signature against each public key until it finds an + * ECDSA match. Starting with the subsequent public key, it compares the + * second signature against each remaining public key until it finds an ECDSA + * match. The process is repeated until all signatures have been checked or + * not enough public keys remain to produce a successful result. All + * signatures need to match a public key. Because public keys are not checked + * again if they fail any signature comparison, signatures must be placed in + * the scriptSig using the same order as their corresponding public keys were + * placed in the scriptPubKey or redeemScript. If all signatures are valid, 1 + * is returned, 0 otherwise. Due to a bug, one extra unused value is removed + * from the stack. */ final def opCheckMultiSig( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_CHECKMULTISIG), - "Script top must be OP_CHECKMULTISIG") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_CHECKMULTISIG), + "Script top must be OP_CHECKMULTISIG" + ) val flags = program.flags if ( @@ -321,14 +356,15 @@ sealed abstract class CryptoInterpreter { } else if (program.stack.size < 1) { program.failExecution(ScriptErrorInvalidStackOperation) } else { - //these next lines remove the appropriate stack/script values after the signatures have been checked + // these next lines remove the appropriate stack/script values after the signatures have been checked val nPossibleSignatures: ScriptNumber = BitcoinScriptUtil.numPossibleSignaturesOnStack(program) if (nPossibleSignatures < ScriptNumber.zero) { program.failExecution(ScriptErrorPubKeyCount) } else if ( ScriptFlagUtil.requireMinimalData( - flags) && !nPossibleSignatures.isShortestEncoding + flags + ) && !nPossibleSignatures.isShortestEncoding ) { program.failExecution(ScriptErrorUnknownError) } else if (program.stack.size < 2) { @@ -339,7 +375,8 @@ sealed abstract class CryptoInterpreter { if ( ScriptFlagUtil.requireMinimalData( - flags) && !mRequiredSignatures.isShortestEncoding + flags + ) && !mRequiredSignatures.isShortestEncoding ) { return program.failExecution(ScriptErrorUnknownError) } @@ -348,21 +385,24 @@ sealed abstract class CryptoInterpreter { return program.failExecution(ScriptErrorSigCount) } val (pubKeysScriptTokens, stackWithoutPubKeys) = - (program.stack.tail.slice(0, nPossibleSignatures.toInt), - program.stack.tail - .slice(nPossibleSignatures.toInt, program.stack.tail.size)) + ( + program.stack.tail.slice(0, nPossibleSignatures.toInt), + program.stack.tail + .slice(nPossibleSignatures.toInt, program.stack.tail.size) + ) val pubKeys = pubKeysScriptTokens.map(key => ECPublicKeyBytes(key.bytes)) - //+1 is for the fact that we have the # of sigs + the script token indicating the # of sigs + // +1 is for the fact that we have the # of sigs + the script token indicating the # of sigs val signaturesScriptTokens = program.stack.tail.slice( nPossibleSignatures.toInt + 1, - nPossibleSignatures.toInt + mRequiredSignatures.toInt + 1) + nPossibleSignatures.toInt + mRequiredSignatures.toInt + 1 + ) val signatures = signaturesScriptTokens.map(token => ECDigitalSignature(token.bytes)) - //this contains the extra Script OP that is required for OP_CHECKMULTISIG + // this contains the extra Script OP that is required for OP_CHECKMULTISIG val stackWithoutPubKeysAndSignatures = stackWithoutPubKeys.tail .slice(mRequiredSignatures.toInt, stackWithoutPubKeys.tail.size) if (pubKeys.size > Consensus.maxPublicKeysPerMultiSig) { @@ -370,8 +410,8 @@ sealed abstract class CryptoInterpreter { } else if (signatures.size > pubKeys.size) { program.failExecution(ScriptErrorSigCount) } else if (stackWithoutPubKeysAndSignatures.size < 1) { - //this is because of a bug in bitcoin core for the implementation of OP_CHECKMULTISIG - //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L966 + // this is because of a bug in bitcoin core for the implementation of OP_CHECKMULTISIG + // https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L966 program.failExecution(ScriptErrorInvalidStackOperation) } else if ( ScriptFlagUtil.requireNullDummy(flags) && @@ -379,7 +419,7 @@ sealed abstract class CryptoInterpreter { ) { program.failExecution(ScriptErrorSigNullDummy) } else { - //remove the last OP_CODESEPARATOR + // remove the last OP_CODESEPARATOR val removedOpCodeSeparatorsScript = BitcoinScriptUtil.removeOpCodeSeparator(program) val isValidSignatures: TransactionSignatureCheckerResult = @@ -389,27 +429,33 @@ sealed abstract class CryptoInterpreter { signatures, pubKeys, flags, - mRequiredSignatures.toLong) + mRequiredSignatures.toLong + ) - //remove the extra OP_0 (null dummy) for OP_CHECKMULTISIG from the stack + // remove the extra OP_0 (null dummy) for OP_CHECKMULTISIG from the stack val restOfStack = stackWithoutPubKeysAndSignatures.tail - handleSignatureValidation(program = program, - result = isValidSignatures, - restOfStack = restOfStack, - numOpt = None) + handleSignatureValidation( + program = program, + result = isValidSignatures, + restOfStack = restOfStack, + numOpt = None + ) } } } } - /** Runs - * [[org.bitcoins.core.script.crypto.OP_CHECKMULTISIG OP_CHECKMULTISIG]] with an - * [[org.bitcoins.core.script.control.OP_VERIFY OP_VERIFY]] afterwards + /** Runs [[org.bitcoins.core.script.crypto.OP_CHECKMULTISIG OP_CHECKMULTISIG]] + * with an [[org.bitcoins.core.script.control.OP_VERIFY OP_VERIFY]] + * afterwards */ def opCheckMultiSigVerify( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_CHECKMULTISIGVERIFY), - "Script top must be OP_CHECKMULTISIGVERIFY") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_CHECKMULTISIGVERIFY), + "Script top must be OP_CHECKMULTISIGVERIFY" + ) if (program.stack.size < 3) { program.failExecution(ScriptErrorInvalidStackOperation) } else { @@ -426,10 +472,12 @@ sealed abstract class CryptoInterpreter { } def opCheckSigAdd( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { require( program.script.headOption.contains(OP_CHECKSIGADD), - s"Script top must be OP_CHECKSIGADD, got=${program.script.headOption}") + s"Script top must be OP_CHECKSIGADD, got=${program.script.headOption}" + ) program.txSignatureComponent.sigVersion match { case SigVersionBase | SigVersionWitnessV0 => program.failExecution(ScriptErrorBadOpCode) @@ -457,7 +505,7 @@ sealed abstract class CryptoInterpreter { updatedProgram.failExecution(ScriptErrorUnknownError) } else { val restOfStack = - updatedProgram.stack.tail.tail.tail //remove signature, num, pubkey + updatedProgram.stack.tail.tail.tail // remove signature, num, pubkey val tapscriptE = evalChecksigTapscript(updatedProgram) @@ -467,21 +515,23 @@ sealed abstract class CryptoInterpreter { err == ScriptErrorDiscourageUpgradablePubkeyType && !ScriptFlagUtil .discourageUpgradablePublicKey(flags) ) { - //trivially pass signature validation as required by BIP342 - //when the public key type is not known and the - //SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE is NOT set - handleSignatureValidation(program = updatedProgram, - result = - SignatureValidationSuccess, - restOfStack = restOfStack, - numOpt = Some(numT.get)) + // trivially pass signature validation as required by BIP342 + // when the public key type is not known and the + // SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE is NOT set + handleSignatureValidation( + program = updatedProgram, + result = SignatureValidationSuccess, + restOfStack = restOfStack, + numOpt = Some(numT.get) + ) } else if (err == ScriptErrorEvalFalse) { - //means signature validation failed, don't increment the stack counter + // means signature validation failed, don't increment the stack counter handleSignatureValidation( program = updatedProgram, result = SignatureValidationErrorIncorrectSignatures, restOfStack = restOfStack, - numOpt = Some(numT.get)) + numOpt = Some(numT.get) + ) } else { updatedProgram.failExecution(err) } @@ -489,10 +539,12 @@ sealed abstract class CryptoInterpreter { if (result == SignatureValidationErrorIncorrectSignatures) { program.failExecution(ScriptErrorSchnorrSig) } else { - handleSignatureValidation(program = updatedProgram, - result = result, - restOfStack = restOfStack, - numOpt = Some(numT.get)) + handleSignatureValidation( + program = updatedProgram, + result = result, + restOfStack = restOfStack, + numOpt = Some(numT.get) + ) } } @@ -502,30 +554,37 @@ sealed abstract class CryptoInterpreter { } } - /** This is a higher order function designed to execute a hash function on the stack top of the program - * For instance, we could pass in CryptoUtil.sha256 function as the `hashFunction` argument, which would then - * apply sha256 to the stack top - * @param program the script program whose stack top needs to be hashed - * @param hashFunction the hash function which needs to be used on the stack top (sha256,ripemd160,etc..) + /** This is a higher order function designed to execute a hash function on the + * stack top of the program For instance, we could pass in CryptoUtil.sha256 + * function as the `hashFunction` argument, which would then apply sha256 to + * the stack top + * @param program + * the script program whose stack top needs to be hashed + * @param hashFunction + * the hash function which needs to be used on the stack top + * (sha256,ripemd160,etc..) * @return */ private def executeHashFunction( program: ExecutionInProgressScriptProgram, - hashFunction: ByteVector => HashDigest): StartedScriptProgram = { + hashFunction: ByteVector => HashDigest + ): StartedScriptProgram = { if (program.stack.nonEmpty) { val stackTop = program.stack.head val hash = ScriptConstant(hashFunction(stackTop.bytes).bytes) - program.updateStackAndScript(hash :: program.stack.tail, - program.script.tail) + program.updateStackAndScript( + hash :: program.stack.tail, + program.script.tail + ) } else { program.failExecution(ScriptErrorInvalidStackOperation) } } /** Pushes the correct data onto the stack after signature validation - * Pre-tapscript this meant just pushing OP_TRUE/OP_FALSE onto the stack - * With tapscript and OP_CHECKSIGADD we increment the counter and - * push it back onto the stack in case there are more signature operations + * Pre-tapscript this meant just pushing OP_TRUE/OP_FALSE onto the stack With + * tapscript and OP_CHECKSIGADD we increment the counter and push it back + * onto the stack in case there are more signature operations * @param program * @param result * @param restOfStack @@ -536,7 +595,8 @@ sealed abstract class CryptoInterpreter { program: ExecutionInProgressScriptProgram, result: TransactionSignatureCheckerResult, restOfStack: Seq[ScriptToken], - numOpt: Option[ScriptNumber]): StartedScriptProgram = { + numOpt: Option[ScriptNumber] + ): StartedScriptProgram = { val pushOp = { numOpt match { @@ -556,25 +616,25 @@ sealed abstract class CryptoInterpreter { } result match { case SignatureValidationSuccess => - //means that all of the signatures were correctly encoded and - //that all of the signatures were valid signatures for the given - //public keys + // means that all of the signatures were correctly encoded and + // that all of the signatures were valid signatures for the given + // public keys program.updateStackAndScript(pushOp +: restOfStack, program.script.tail) case SignatureValidationErrorNotStrictDerEncoding => - //this means the script fails immediately - //set the valid flag to false on the script - //see BIP66 for more information on this - //https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki#specification + // this means the script fails immediately + // set the valid flag to false on the script + // see BIP66 for more information on this + // https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki#specification program.failExecution(ScriptErrorSigDer) case SignatureValidationErrorIncorrectSignatures => - //this means that signature verification failed, however all signatures were encoded correctly - //just push a OP_FALSE onto the stack + // this means that signature verification failed, however all signatures were encoded correctly + // just push a OP_FALSE onto the stack program.updateStackAndScript(pushOp +: restOfStack, program.script.tail) case SignatureValidationErrorSignatureCount => - //means that we did not have enough signatures for OP_CHECKMULTISIG + // means that we did not have enough signatures for OP_CHECKMULTISIG program.failExecution(ScriptErrorInvalidStackOperation) case SignatureValidationErrorPubKeyEncoding => - //means that a public key was not encoded correctly + // means that a public key was not encoded correctly program.failExecution(ScriptErrorPubKeyType) case SignatureValidationErrorHighSValue => program.failExecution(ScriptErrorSigHighS) @@ -594,4 +654,5 @@ case class TapscriptChecksigHelper( pubKey: XOnlyPubKey, signature: SchnorrDigitalSignature, hashType: HashType, - restOfStack: List[ScriptToken]) + restOfStack: List[ScriptToken] +) diff --git a/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoOperations.scala b/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoOperations.scala index 4795466795..9ad209d349 100644 --- a/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoOperations.scala +++ b/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoOperations.scala @@ -3,8 +3,8 @@ package org.bitcoins.core.script.crypto import org.bitcoins.core.script.ScriptOperationFactory import org.bitcoins.core.script.constant.ScriptOperation -/** Created by chris on 1/6/16. - * Represents an operation where a cryptographic function is applied +/** Created by chris on 1/6/16. Represents an operation where a cryptographic + * function is applied */ sealed trait CryptoOperation extends ScriptOperation @@ -36,16 +36,16 @@ case object OP_HASH256 extends CryptoOperation { override val opCode: Int = 170 } -/** All of the signature checking words will only match signatures to - * the data after the most recently-executed OP_CODESEPARATOR. +/** All of the signature checking words will only match signatures to the data + * after the most recently-executed OP_CODESEPARATOR. */ case object OP_CODESEPARATOR extends CryptoOperation { override val opCode: Int = 171 } -/** The entire transaction's outputs, inputs, and script - * (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. - * The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. +/** The entire transaction's outputs, inputs, and script (from the most + * recently-executed OP_CODESEPARATOR to the end) are hashed. The signature + * used by OP_CHECKSIG must be a valid signature for this hash and public key. * If it is, 1 is returned, 0 otherwise. */ case object OP_CHECKSIG extends CryptoSignatureEvaluation { @@ -57,15 +57,16 @@ case object OP_CHECKSIGVERIFY extends CryptoSignatureEvaluation { override val opCode: Int = 173 } -/** Compares the first signature against each public key until it finds an ECDSA match. - * Starting with the subsequent public key, it compares the second signature against each remaining public key - * until it finds an ECDSA match. - * The process is repeated until all signatures have been checked or not enough public keys remain to produce a successful result. - * All signatures need to match a public key. - * Because public keys are not checked again if they fail any signature comparison, - * signatures must be placed in the scriptSig using the same order as their corresponding public keys - * were placed in the scriptPubKey or redeemScript. If all signatures are valid, 1 is returned, 0 otherwise. - * Due to a bug, one extra unused value is removed from the stack. +/** Compares the first signature against each public key until it finds an ECDSA + * match. Starting with the subsequent public key, it compares the second + * signature against each remaining public key until it finds an ECDSA match. + * The process is repeated until all signatures have been checked or not enough + * public keys remain to produce a successful result. All signatures need to + * match a public key. Because public keys are not checked again if they fail + * any signature comparison, signatures must be placed in the scriptSig using + * the same order as their corresponding public keys were placed in the + * scriptPubKey or redeemScript. If all signatures are valid, 1 is returned, 0 + * otherwise. Due to a bug, one extra unused value is removed from the stack. */ case object OP_CHECKMULTISIG extends CryptoSignatureEvaluation { override val opCode: Int = 174 @@ -77,7 +78,8 @@ case object OP_CHECKMULTISIGVERIFY extends CryptoSignatureEvaluation { } /** Opcode added in taproot soft fork - * @see https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#rules-for-signature-opcodes + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#rules-for-signature-opcodes */ case object OP_CHECKSIGADD extends CryptoSignatureEvaluation { override val opCode: Int = 186 diff --git a/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoSignatureEvaluationFactory.scala b/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoSignatureEvaluationFactory.scala index b85592b553..7e67734e8d 100644 --- a/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoSignatureEvaluationFactory.scala +++ b/core/src/main/scala/org/bitcoins/core/script/crypto/CryptoSignatureEvaluationFactory.scala @@ -9,11 +9,13 @@ trait CryptoSignatureEvaluationFactory /** The current [[CryptoSignatureEvaluation]] operations. */ override val operations = - Vector(OP_CHECKMULTISIG, - OP_CHECKMULTISIGVERIFY, - OP_CHECKSIG, - OP_CHECKSIGVERIFY, - OP_CHECKSIGADD) + Vector( + OP_CHECKMULTISIG, + OP_CHECKMULTISIGVERIFY, + OP_CHECKSIG, + OP_CHECKSIGVERIFY, + OP_CHECKSIGADD + ) } diff --git a/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlagFactory.scala b/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlagFactory.scala index 1d92d09623..7f68102792 100644 --- a/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlagFactory.scala +++ b/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlagFactory.scala @@ -2,9 +2,8 @@ package org.bitcoins.core.script.flag import org.bitcoins.crypto.StringFactory -/** Created by chris on 3/23/16. - * Trait used to create a script flag used to evaluate scripts in a - * certain way +/** Created by chris on 3/23/16. Trait used to create a script flag used to + * evaluate scripts in a certain way */ trait ScriptFlagFactory extends StringFactory[ScriptFlag] { @@ -44,12 +43,12 @@ trait ScriptFlagFactory extends StringFactory[ScriptFlag] { override def fromString(str: String): ScriptFlag = { fromStringOpt(str) match { case Some(flag) => flag - case None => sys.error(s"Could not find ScriptFlag for string=${str}") + case None => sys.error(s"Could not find ScriptFlag for string=${str}") } } - /** Parses the given list into[[ScriptFlag]]s - * the strings that do not match a [[ScriptFlag]] are discarded. + /** Parses the given list into[[ScriptFlag]]s the strings that do not match a + * [[ScriptFlag]] are discarded. */ def fromList(list: Seq[String]): Seq[ScriptFlag] = { list.flatMap(fromStringOpt(_)) diff --git a/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlagUtil.scala b/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlagUtil.scala index 140a07f826..86c6aa6a05 100644 --- a/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlagUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlagUtil.scala @@ -4,8 +4,7 @@ package org.bitcoins.core.script.flag */ trait ScriptFlagUtil { - /** Checks if the strict encoding is required in the set of flags - * given to us + /** Checks if the strict encoding is required in the set of flags given to us * https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#DER_encoding * @param flags * @return @@ -44,9 +43,9 @@ trait ScriptFlagUtil { flags.contains(ScriptVerifyCheckSequenceVerify) } - /** Checks to see if the script flag is set to discourage NOPs that are not in use - * NOPs are used by soft forks to repurpose NOPs to actual functionality such as checklocktimeverify - * See BIP65 for an example of this seq + /** Checks to see if the script flag is set to discourage NOPs that are not in + * use NOPs are used by soft forks to repurpose NOPs to actual functionality + * such as checklocktimeverify See BIP65 for an example of this seq * @param flags * @return */ @@ -62,7 +61,8 @@ trait ScriptFlagUtil { def requireMinimalData(flags: Seq[ScriptFlag]): Boolean = flags.contains(ScriptVerifyMinimalData) - /** Checks to see if the script flag is set to require low s values in digital signatures + /** Checks to see if the script flag is set to require low s values in digital + * signatures * https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#low-s-values-in-signatures * @param flags * @return @@ -70,15 +70,16 @@ trait ScriptFlagUtil { def requireLowSValue(flags: Seq[ScriptFlag]): Boolean = flags.contains(ScriptVerifyLowS) - /** Checks to see if the script flag is set to require we only have push operations inside of a scriptSig + /** Checks to see if the script flag is set to require we only have push + * operations inside of a scriptSig * @param flags * @return */ def requirePushOnly(flags: Seq[ScriptFlag]): Boolean = flags.contains(ScriptVerifySigPushOnly) - /** Checks to see if the script flag is set to require that we need a NULLDUMMY to be OP_0 for - * OP_CHECKMULTISIG operations + /** Checks to see if the script flag is set to require that we need a + * NULLDUMMY to be OP_0 for OP_CHECKMULTISIG operations * @param flags * @return */ @@ -98,8 +99,8 @@ trait ScriptFlagUtil { def requireScriptVerifyWitnessPubKeyType(flags: Seq[ScriptFlag]): Boolean = flags.contains(ScriptVerifyWitnessPubKeyType) - /** Requires that the argument to OP_IF/OP_NOTIF be minimally encoded - * See: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-August/013014.html + /** Requires that the argument to OP_IF/OP_NOTIF be minimally encoded See: + * https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-August/013014.html */ def minimalIfEnabled(flags: Seq[ScriptFlag]): Boolean = flags.contains(ScriptVerifyMinimalIf) diff --git a/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlags.scala b/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlags.scala index b74799a1ec..7d69aaa86c 100644 --- a/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlags.scala +++ b/core/src/main/scala/org/bitcoins/core/script/flag/ScriptFlags.scala @@ -1,7 +1,7 @@ package org.bitcoins.core.script.flag -/** Created by chris on 3/23/16. - * This represents all of the script flags found inside of +/** Created by chris on 3/23/16. This represents all of the script flags found + * inside of * https://github.com/bitcoin/bitcoin/blob/986003aff93c099c400c9285b4a2ed63f4b3f180/src/script/interpreter.h#L42 * these flags indicate how to evaluate a certain script */ @@ -25,45 +25,53 @@ case object ScriptVerifyP2SH extends ScriptFlag { override def name = "P2SH" } -/** Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure. - * Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure. - * (softfork safe, but not used or intended as a consensus rule). +/** Passing a non-strict-DER signature or one with undefined hashtype to a + * checksig operation causes script failure. Evaluating a pubkey that is not + * (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script + * failure. (softfork safe, but not used or intended as a consensus rule). */ case object ScriptVerifyStrictEnc extends ScriptFlag { override def flag = 1 << 1 override def name = "STRICTENC" } -/** Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1). */ +/** Passing a non-strict-DER signature to a checksig operation causes script + * failure (softfork safe, BIP62 rule 1). + */ case object ScriptVerifyDerSig extends ScriptFlag { override def flag = 1 << 2 override def name = "DERSIG" } -/** Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure - * (softfork safe, BIP62 rule 5). +/** Passing a non-strict-DER signature or one with S > order/2 to a checksig + * operation causes script failure (softfork safe, BIP62 rule 5). */ case object ScriptVerifyLowS extends ScriptFlag { override def flag = 1 << 3 override def name = "LOW_S" } -/** Verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7). */ +/** Verify dummy stack item consumed by CHECKMULTISIG is of zero-length + * (softfork safe, BIP62 rule 7). + */ case object ScriptVerifyNullDummy extends ScriptFlag { override def flag = 1 << 4 override def name = "NULLDUMMY" } -/** Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2). */ +/** Using a non-push operator in the scriptSig causes script failure (softfork + * safe, BIP62 rule 2). + */ case object ScriptVerifySigPushOnly extends ScriptFlag { override def flag = 1 << 5 override def name = "SIGPUSHONLY" } -/** Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct - * pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating - * any other push causes the script to fail (BIP62 rule 3). - * In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4). +/** Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE + * where possible, direct pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, + * OP_PUSHDATA2 for anything larger). Evaluating any other push causes the + * script to fail (BIP62 rule 3). In addition, whenever a stack element is + * interpreted as a number, it must be of minimal length (BIP62 rule 4). * (softfork safe). */ case object ScriptVerifyMinimalData extends ScriptFlag { @@ -71,37 +79,42 @@ case object ScriptVerifyMinimalData extends ScriptFlag { override def name = "MINIMALDATA" } -/** Discourage use of NOPs reserved for upgrades (NOP1-10) - * Provided so that nodes can avoid accepting or mining transactions - * containing executed NOP's whose meaning may change after a soft-fork, - * thus rendering the script invalid; with this flag set executing - * discouraged NOPs fails the script. This verification flag will never be - * a mandatory flag applied to scripts in a block. NOPs that are not - * executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected. +/** Discourage use of NOPs reserved for upgrades (NOP1-10) Provided so that + * nodes can avoid accepting or mining transactions containing executed NOP's + * whose meaning may change after a soft-fork, thus rendering the script + * invalid; with this flag set executing discouraged NOPs fails the script. + * This verification flag will never be a mandatory flag applied to scripts in + * a block. NOPs that are not executed, e.g. within an unexecuted IF ENDIF + * block, are *not* rejected. */ case object ScriptVerifyDiscourageUpgradableNOPs extends ScriptFlag { override def flag = 1 << 7 override def name = "DISCOURAGE_UPGRADABLE_NOPS" } -/** Require that only a single stack element remains after evaluation. This changes the success criterion from - * "At least one stack element must remain, and when interpreted as a boolean, it must be true" to - * "Exactly one stack element must remain, and when interpreted as a boolean, it must be true". - * (softfork safe, BIP62 rule 6) - * Note: CLEANSTACK should never be used without P2SH. +/** Require that only a single stack element remains after evaluation. This + * changes the success criterion from "At least one stack element must remain, + * and when interpreted as a boolean, it must be true" to "Exactly one stack + * element must remain, and when interpreted as a boolean, it must be true". + * (softfork safe, BIP62 rule 6) Note: CLEANSTACK should never be used without + * P2SH. */ case object ScriptVerifyCleanStack extends ScriptFlag { override def flag = 1 << 8 override def name = "CLEANSTACK" } -/** See [[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki]] for details. */ +/** See [[https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki]] for + * details. + */ case object ScriptVerifyCheckLocktimeVerify extends ScriptFlag { override def flag = 1 << 9 override def name = "CHECKLOCKTIMEVERIFY" } -/** See https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki for details. */ +/** See https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki for + * details. + */ case object ScriptVerifyCheckSequenceVerify extends ScriptFlag { override def flag = 1 << 10 override def name = "CHECKSEQUENCEVERIFY" @@ -119,7 +132,9 @@ case object ScriptVerifyDiscourageUpgradableWitnessProgram extends ScriptFlag { override def name = "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM" } -/** Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector. */ +/** Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 + * or empty vector. + */ case object ScriptVerifyMinimalIf extends ScriptFlag { override def flag = 1 << 13 override def name = "MINIMALIF" @@ -139,7 +154,7 @@ case object ScriptVerifyWitnessPubKeyType extends ScriptFlag { case object ScriptVerifyConstScriptCode extends ScriptFlag { override val flag: Int = 1 << 16 - override val name = "CONST_SCRIPTCODE" //not sure if this is right + override val name = "CONST_SCRIPTCODE" // not sure if this is right } case object ScriptVerifyTaproot extends ScriptFlag { @@ -171,8 +186,8 @@ case object ScriptVerifyDiscourageUpgradablePubKeyType extends ScriptFlag { object ScriptFlag { - //what is this? - //https://github.com/bitcoin/bitcoin/blob/3820090bd619ac85ab35eff376c03136fe4a9f04/src/test/script_tests.cpp#L1659 + // what is this? + // https://github.com/bitcoin/bitcoin/blob/3820090bd619ac85ab35eff376c03136fe4a9f04/src/test/script_tests.cpp#L1659 val allConsensusFlags = Vector( ScriptVerifyP2SH, ScriptVerifyDerSig, diff --git a/core/src/main/scala/org/bitcoins/core/script/interpreter/ScriptInterpreter.scala b/core/src/main/scala/org/bitcoins/core/script/interpreter/ScriptInterpreter.scala index 372f306245..ee58006b39 100644 --- a/core/src/main/scala/org/bitcoins/core/script/interpreter/ScriptInterpreter.scala +++ b/core/src/main/scala/org/bitcoins/core/script/interpreter/ScriptInterpreter.scala @@ -35,17 +35,17 @@ import scala.util.{Failure, Success, Try} */ sealed abstract class ScriptInterpreter { - /** Currently bitcoin core limits the maximum number of non-push operations per script - * to 201 + /** Currently bitcoin core limits the maximum number of non-push operations + * per script to 201 */ private lazy val MAX_SCRIPT_OPS = 201 /** We cannot push an element larger than 520 bytes onto the stack */ val MAX_PUSH_SIZE: Int = 520 - /** Runs an entire script though our script programming language and - * returns a [[org.bitcoins.core.script.result.ScriptResult ScriptResult]] - * indicating if the script was valid, or if not what error it encountered + /** Runs an entire script though our script programming language and returns a + * [[org.bitcoins.core.script.result.ScriptResult ScriptResult]] indicating + * if the script was valid, or if not what error it encountered */ def run(program: PreExecutionScriptProgram): ScriptResult = { val scriptPubKey = program.txSignatureComponent.scriptPubKey @@ -103,7 +103,8 @@ sealed abstract class ScriptInterpreter { } private def programFlagsViolated( - program: PreExecutionScriptProgram): Option[ScriptError] = { + program: PreExecutionScriptProgram + ): Option[ScriptError] = { val scriptSig = program.txSignatureComponent.scriptSignature val flags = program.flags val p2shEnabled = ScriptFlagUtil.p2shEnabled(flags) @@ -125,17 +126,18 @@ sealed abstract class ScriptInterpreter { private def evaluateExecutedScriptProgram( program: PreExecutionScriptProgram, - executedProgram: ExecutedScriptProgram): ScriptResult = { + executedProgram: ExecutedScriptProgram + ): ScriptResult = { executedProgram.error match { case Some(err) => err case None => if (hasUnexpectedWitness(program)) { - //note: the 'program' value we pass above is intentional, we need to check the original program - //as the 'executedProgram' may have had the scriptPubKey value changed to the rebuilt ScriptPubKey of the witness program + // note: the 'program' value we pass above is intentional, we need to check the original program + // as the 'executedProgram' may have had the scriptPubKey value changed to the rebuilt ScriptPubKey of the witness program ScriptErrorWitnessUnexpected } else if (executedProgram.stackTopIsTrue) { if (program.flags.contains(ScriptVerifyCleanStack)) { - //require that the stack after execution has exactly one element on it + // require that the stack after execution has exactly one element on it if (executedProgram.stack.size == 1) { ScriptOk } else { @@ -150,22 +152,26 @@ sealed abstract class ScriptInterpreter { } } - /** Runs the given [[org.bitcoins.core.script.PreExecutionScriptProgram PreExecutionScriptProgram]] and - * return if that script was valid or not + /** Runs the given + * [[org.bitcoins.core.script.PreExecutionScriptProgram PreExecutionScriptProgram]] + * and return if that script was valid or not */ def runVerify(p: PreExecutionScriptProgram): Boolean = { ScriptInterpreter.run(p) == ScriptOk } - /** Every given [[org.bitcoins.core.script.PreExecutionScriptProgram PreExecutionScriptProgram]] and returns - * it's [[org.bitcoins.core.script.result.ScriptResult ScriptResult]] + /** Every given + * [[org.bitcoins.core.script.PreExecutionScriptProgram PreExecutionScriptProgram]] + * and returns it's + * [[org.bitcoins.core.script.result.ScriptResult ScriptResult]] */ def runAll(programs: Seq[PreExecutionScriptProgram]): Seq[ScriptResult] = { programs.map(p => ScriptInterpreter.run(p)) } - /** Runs all the given [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] and return - * if it is valid or not + /** Runs all the given + * [[org.bitcoins.core.script.ScriptProgram ScriptProgram]] and return if it + * is valid or not */ def runAllVerify(programs: Seq[PreExecutionScriptProgram]): Boolean = { !programs.exists(p => ScriptInterpreter.run(p) != ScriptOk) @@ -175,7 +181,8 @@ sealed abstract class ScriptInterpreter { transaction: Transaction, inputIndex: Long, outputMap: PreviousOutputMap, - prevOut: TransactionOutput): Boolean = { + prevOut: TransactionOutput + ): Boolean = { val sigComponent = TxSigComponent( transaction, UInt32(inputIndex), @@ -188,10 +195,12 @@ sealed abstract class ScriptInterpreter { def verifyTransaction( transaction: Transaction, - outputMap: PreviousOutputMap): Boolean = { + outputMap: PreviousOutputMap + ): Boolean = { require( transaction.inputs.size == outputMap.size, - s"There must be a prevOut for every input in the transaction, got ${outputMap.size}") + s"There must be a prevOut for every input in the transaction, got ${outputMap.size}" + ) outputMap.zipWithIndex.forall { case ((_, prevOut), index) => verifyInputScript(transaction, index, outputMap, prevOut) @@ -201,7 +210,8 @@ sealed abstract class ScriptInterpreter { /** Helper function to actually run a p2sh script */ private def runP2SH( p: ExecutedScriptProgram, - s: ScriptPubKey): ExecutedScriptProgram = { + s: ScriptPubKey + ): ExecutedScriptProgram = { val p2shRedeemScriptProgram = PreExecutionScriptProgram( txSignatureComponent = p.txSignatureComponent, @@ -215,23 +225,29 @@ sealed abstract class ScriptInterpreter { /*ScriptProgram(p.txSignatureComponent, stack.tail,s.asm)*/ if ( ScriptFlagUtil.requirePushOnly( - p2shRedeemScriptProgram.flags) && !BitcoinScriptUtil + p2shRedeemScriptProgram.flags + ) && !BitcoinScriptUtil .isPushOnly(s.asm) ) { p2shRedeemScriptProgram.failExecution(ScriptErrorSigPushOnly) } else executeProgram(p2shRedeemScriptProgram) } - /** P2SH scripts are unique in their evaluation, first the scriptSignature must be added to the stack, next the - * p2sh scriptPubKey must be run to make sure the serialized redeem script hashes to the value found in the p2sh - * scriptPubKey, then finally the serialized redeemScript is decoded and run with the arguments in the p2sh script signature - * a p2sh script returns true if both of those intermediate steps evaluate to true + /** P2SH scripts are unique in their evaluation, first the scriptSignature + * must be added to the stack, next the p2sh scriptPubKey must be run to make + * sure the serialized redeem script hashes to the value found in the p2sh + * scriptPubKey, then finally the serialized redeemScript is decoded and run + * with the arguments in the p2sh script signature a p2sh script returns true + * if both of those intermediate steps evaluate to true * - * @param scriptPubKeyExecutedProgram the program with the script signature pushed onto the stack - * @return the executed program + * @param scriptPubKeyExecutedProgram + * the program with the script signature pushed onto the stack + * @return + * the executed program */ private def executeP2shScript( - scriptPubKeyExecutedProgram: ExecutedScriptProgram): ExecutedScriptProgram = { + scriptPubKeyExecutedProgram: ExecutedScriptProgram + ): ExecutedScriptProgram = { val flags = scriptPubKeyExecutedProgram.flags val segwitEnabled = ScriptFlagUtil.segWitEnabled(flags) @@ -239,8 +255,8 @@ sealed abstract class ScriptInterpreter { val scriptSig = scriptPubKeyExecutedProgram.txSignatureComponent.scriptSignature val scriptSigAsm: Seq[ScriptToken] = scriptSig.asm - //need to check if the scriptSig is push only as required by bitcoin core - //https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L1419 + // need to check if the scriptSig is push only as required by bitcoin core + // https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L1419 if (!BitcoinScriptUtil.isPushOnly(scriptSigAsm)) { scriptPubKeyExecutedProgram.failExecution(ScriptErrorSigPushOnly) } else if (scriptPubKeyExecutedProgram.error.isDefined) { @@ -248,7 +264,7 @@ sealed abstract class ScriptInterpreter { } else { if (scriptPubKeyExecutedProgram.stackTopIsTrue) { - //we need to run the deserialized redeemScript & the scriptSignature without the serialized redeemScript + // we need to run the deserialized redeemScript & the scriptSignature without the serialized redeemScript val stack = scriptPubKeyExecutedProgram.stack val redeemScriptBytes = stack.head.bytes @@ -263,8 +279,8 @@ sealed abstract class ScriptInterpreter { val wtxSigP2SH = scriptPubKeyExecutedProgram.txSignatureComponent .asInstanceOf[WitnessTxSigComponentP2SH] - //for the p2sh(p2wpkh) case - //https://github.com/bitcoin/bitcoin/blob/78dae8caccd82cfbfd76557f1fb7d7557c7b5edb/src/script/interpreter.cpp#L1437 + // for the p2sh(p2wpkh) case + // https://github.com/bitcoin/bitcoin/blob/78dae8caccd82cfbfd76557f1fb7d7557c7b5edb/src/script/interpreter.cpp#L1437 val pushOp = BitcoinScriptUtil.calculatePushOp(redeemScriptBytes) @@ -281,9 +297,10 @@ sealed abstract class ScriptInterpreter { executeSegWitScript(scriptPubKeyExecutedProgram, p2wpkh).get } else if (segwitEnabled) { scriptPubKeyExecutedProgram.failExecution( - ScriptErrorWitnessMalleatedP2SH) + ScriptErrorWitnessMalleatedP2SH + ) } else { - //segwit not enabled, treat as old spk + // segwit not enabled, treat as old spk runP2SH(scriptPubKeyExecutedProgram, p2wpkh) } @@ -299,15 +316,16 @@ sealed abstract class ScriptInterpreter { if (segwitEnabled && isExpectedScriptBytes) { // The scriptSig must be _exactly_ a single push of the redeemScript. Otherwise we // reintroduce malleability. - //TODO: remove .get here + // TODO: remove .get here executeSegWitScript(scriptPubKeyExecutedProgram, p2wsh).get } else if ( segwitEnabled && (scriptSig.asmBytes != expectedScriptBytes) ) { scriptPubKeyExecutedProgram.failExecution( - ScriptErrorWitnessMalleatedP2SH) + ScriptErrorWitnessMalleatedP2SH + ) } else { - //treat the segwit scriptpubkey as any other redeem script + // treat the segwit scriptpubkey as any other redeem script runP2SH(scriptPubKeyExecutedProgram, p2wsh) } case _: TaprootScriptPubKey => @@ -315,9 +333,10 @@ sealed abstract class ScriptInterpreter { flags.exists(_ == ScriptVerifyDiscourageUpgradableWitnessProgram) if (hasUpgradeableFlag) { scriptPubKeyExecutedProgram.failExecution( - ScriptErrorDiscourageUpgradeableWitnessProgram) + ScriptErrorDiscourageUpgradeableWitnessProgram + ) } else { - //trivially passes + // trivially passes scriptPubKeyExecutedProgram } case s @ (_: P2SHScriptPubKey | _: P2PKHScriptPubKey | @@ -334,21 +353,24 @@ sealed abstract class ScriptInterpreter { } } - /** Runs a segwit script through our interpreter, mimics this functionality in bitcoin core: + /** Runs a segwit script through our interpreter, mimics this functionality in + * bitcoin core: * [[https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L1441-L1452]] - * @param scriptPubKeyExecutedProgram the program with the - * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] executed + * @param scriptPubKeyExecutedProgram + * the program with the + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] executed */ private def executeSegWitScript( scriptPubKeyExecutedProgram: ExecutedScriptProgram, - witnessScriptPubKey: WitnessScriptPubKey): Try[ExecutedScriptProgram] = { + witnessScriptPubKey: WitnessScriptPubKey + ): Try[ExecutedScriptProgram] = { scriptPubKeyExecutedProgram.txSignatureComponent match { case w: WitnessTxSigComponent => val scriptSig = scriptPubKeyExecutedProgram.txSignatureComponent.scriptSignature val witness = w.witness - //scriptsig must be empty if we have raw p2wsh - //if script pubkey is a P2SHScriptPubKey then we have P2SH(P2WSH) + // scriptsig must be empty if we have raw p2wsh + // if script pubkey is a P2SHScriptPubKey then we have P2SH(P2WSH) (scriptSig, w.scriptPubKey) match { case (EmptyScriptSignature, _) | (_, _: P2SHScriptPubKey) => verifyWitnessProgram( @@ -360,7 +382,8 @@ sealed abstract class ScriptInterpreter { case (_, _) => Success( scriptPubKeyExecutedProgram.failExecution( - ScriptErrorWitnessMalleated) + ScriptErrorWitnessMalleated + ) ) } case b: BaseTxSigComponent => @@ -387,41 +410,50 @@ sealed abstract class ScriptInterpreter { case (_, _) => Success( scriptPubKeyExecutedProgram.failExecution( - ScriptErrorWitnessMalleated)) + ScriptErrorWitnessMalleated + ) + ) } case _: WitnessTxSigComponentRebuilt => - Failure(new IllegalArgumentException( - "Cannot have a rebuild witness tx sig component here, the witness tx sigcomponent is rebuilt in verifyWitnessProgram")) + Failure( + new IllegalArgumentException( + "Cannot have a rebuild witness tx sig component here, the witness tx sigcomponent is rebuilt in verifyWitnessProgram" + ) + ) } } /** Helper function to run the post segwit execution checks */ private def postSegWitProgramChecks( - evaluated: ExecutedScriptProgram): ExecutedScriptProgram = { + evaluated: ExecutedScriptProgram + ): ExecutedScriptProgram = { if (evaluated.error.isDefined) evaluated else if (evaluated.stack.size != 1) { // Scripts inside witness implicitly require cleanstack behaviour - //https://github.com/bitcoin/bitcoin/blob/561a7d30478b82f5d46dcf0f16e864a9608004f4/src/script/interpreter.cpp#L1464 + // https://github.com/bitcoin/bitcoin/blob/561a7d30478b82f5d46dcf0f16e864a9608004f4/src/script/interpreter.cpp#L1464 evaluated.failExecution(ScriptErrorCleanStack) } else if (evaluated.stackTopIsFalse) evaluated.failExecution(ScriptErrorEvalFalse) else evaluated } - /** Rebuilds a [[WitnessVersion1]] witness program for execution in the script interpreter */ + /** Rebuilds a [[WitnessVersion1]] witness program for execution in the script + * interpreter + */ private def rebuildV1( witness: TaprootWitness, - witnessSPK: WitnessScriptPubKey): Either[ - ScriptError, - (Seq[ScriptToken], ScriptPubKey)] = { - require(witnessSPK.isInstanceOf[TaprootScriptPubKey], - s"WitnessScriptPubKey must be a taproot spk, got=${witnessSPK}") + witnessSPK: WitnessScriptPubKey + ): Either[ScriptError, (Seq[ScriptToken], ScriptPubKey)] = { + require( + witnessSPK.isInstanceOf[TaprootScriptPubKey], + s"WitnessScriptPubKey must be a taproot spk, got=${witnessSPK}" + ) val taprootSPK = witnessSPK.asInstanceOf[TaprootScriptPubKey] val program = witnessSPK.witnessProgram val programBytes = BytesUtil.toByteVector(program) programBytes.size match { case 32 => - //valid p2tr + // valid p2tr if (witness.stack.isEmpty) { Left(ScriptErrorWitnessProgramWitnessEmpty) } else { @@ -439,28 +471,30 @@ sealed abstract class ScriptInterpreter { } } case _ => - //witness version 1 progarms need to be 32 bytes in size + // witness version 1 progarms need to be 32 bytes in size Left(ScriptErrorWitnessProgramWrongLength) } } - /** Verifies a segregated witness program by running it through the interpreter + /** Verifies a segregated witness program by running it through the + * interpreter * [[https://github.com/bitcoin/bitcoin/blob/f8528134fc188abc5c7175a19680206964a8fade/src/script/interpreter.cpp#L1302]] */ private def verifyWitnessProgram( scriptWitness: ScriptWitness, witnessSPK: WitnessScriptPubKey, wTxSigComponent: WitnessTxSigComponent, - scriptPubKeyExecutedProgram: ExecutedScriptProgram): Try[ - ExecutedScriptProgram] = { + scriptPubKeyExecutedProgram: ExecutedScriptProgram + ): Try[ExecutedScriptProgram] = { /** Helper function to run the post segwit execution checks */ def postSegWitProgramChecks( - evaluated: ExecutedScriptProgram): ExecutedScriptProgram = { + evaluated: ExecutedScriptProgram + ): ExecutedScriptProgram = { if (evaluated.error.isDefined) evaluated else if (evaluated.stack.size != 1) { // Scripts inside witness implicitly require cleanstack behaviour - //https://github.com/bitcoin/bitcoin/blob/561a7d30478b82f5d46dcf0f16e864a9608004f4/src/script/interpreter.cpp#L1464 + // https://github.com/bitcoin/bitcoin/blob/561a7d30478b82f5d46dcf0f16e864a9608004f4/src/script/interpreter.cpp#L1464 evaluated.failExecution(ScriptErrorCleanStack) } else if (evaluated.stackTopIsFalse) evaluated.failExecution(ScriptErrorEvalFalse) @@ -469,14 +503,13 @@ sealed abstract class ScriptInterpreter { def rebuildV0( witness: ScriptWitness, - witnessSPKV0: WitnessScriptPubKey): Either[ - ScriptError, - (Seq[ScriptToken], ScriptPubKey)] = { + witnessSPKV0: WitnessScriptPubKey + ): Either[ScriptError, (Seq[ScriptToken], ScriptPubKey)] = { val program = witnessSPKV0.witnessProgram val programBytes = BytesUtil.toByteVector(program) programBytes.size match { case 20 => - //p2wpkh + // p2wpkh if (witness.stack.size != 2) { Left(ScriptErrorWitnessProgramMisMatch) } else { @@ -486,7 +519,7 @@ sealed abstract class ScriptInterpreter { } yield r } case 32 => - //p2wsh + // p2wsh if (scriptWitness.stack.isEmpty) Left(ScriptErrorWitnessProgramWitnessEmpty) else { @@ -497,7 +530,7 @@ sealed abstract class ScriptInterpreter { } } case _ => - //witness version 0 programs need to be 20 bytes or 32 bytes in size + // witness version 0 programs need to be 20 bytes or 32 bytes in size Left(ScriptErrorWitnessProgramWrongLength) } } @@ -516,13 +549,14 @@ sealed abstract class ScriptInterpreter { val newWTxSigComponent = rebuildWTxSigComponent(wTxSigComponent, scriptPubKey) val newProgram = newWTxSigComponent.map { comp => - PreExecutionScriptProgram(txSignatureComponent = comp, - stack = stack.toList, - script = scriptPubKey.asm.toList, - originalScript = - scriptPubKey.asm.toList, - altStack = Nil, - flags = comp.flags) + PreExecutionScriptProgram( + txSignatureComponent = comp, + stack = stack.toList, + script = scriptPubKey.asm.toList, + originalScript = scriptPubKey.asm.toList, + altStack = Nil, + flags = comp.flags + ) } val evaluated = newProgram.map(executeProgram) evaluated.map(e => postSegWitProgramChecks(e)) @@ -545,7 +579,8 @@ sealed abstract class ScriptInterpreter { case trSPK: TaprootScriptPubKey => require( scriptWitness.isInstanceOf[TaprootWitness], - s"witness must be taproot witness for witness version 1 script execution, got=$scriptWitness") + s"witness must be taproot witness for witness version 1 script execution, got=$scriptWitness" + ) val taprootWitness = scriptWitness.asInstanceOf[TaprootWitness] val either: Either[ScriptError, (Seq[ScriptToken], ScriptPubKey)] = rebuildV1(taprootWitness, witnessSPK) @@ -575,8 +610,8 @@ sealed abstract class ScriptInterpreter { } case u: UnassignedWitnessScriptPubKey => if (u.asm.contains(OP_0)) { - //cannot have an v0 unassigned witness as according to BIP141 - //a witness v0 script must be 20 bytes or 32 bytes + // cannot have an v0 unassigned witness as according to BIP141 + // a witness v0 script must be 20 bytes or 32 bytes val program = ExecutedScriptProgram( txSignatureComponent = wTxSigComponent, stack = Nil, @@ -606,7 +641,8 @@ sealed abstract class ScriptInterpreter { } /** Checks if there is an opcode defined as OP_SUCCESSx in BIP342 - * @see https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#specification + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#specification */ private def containsOpSuccess(asm: Vector[ScriptToken]): Boolean = { asm.exists { @@ -622,8 +658,8 @@ sealed abstract class ScriptInterpreter { rebuiltSPK: ScriptPubKey, stack: Vector[ScriptToken], wTxSigComponent: WitnessTxSigComponent, - scriptPubKeyExecutedProgram: ExecutedScriptProgram): Try[ - ExecutedScriptProgram] = { + scriptPubKeyExecutedProgram: ExecutedScriptProgram + ): Try[ExecutedScriptProgram] = { val sigVersion = scriptPubKeyExecutedProgram.txSignatureComponent.sigVersion if (ScriptFlagUtil.taprootEnabled(scriptPubKeyExecutedProgram.flags)) { val containsOPSuccess = containsOpSuccess(rebuiltSPK.asm.toVector) @@ -636,11 +672,12 @@ sealed abstract class ScriptInterpreter { val program = checkSchnorrSignature( keypath, taprootSPK.pubKey.schnorrPublicKey, - program = scriptPubKeyExecutedProgram) + program = scriptPubKeyExecutedProgram + ) Success(program) case _: TaprootUnknownPath => - //is this right? I believe to maintain softfork compatibility we - //just succeed? + // is this right? I believe to maintain softfork compatibility we + // just succeed? Success(scriptPubKeyExecutedProgram) case taprootScriptPath: TaprootScriptPath => require( @@ -652,41 +689,46 @@ sealed abstract class ScriptInterpreter { wTxSigComponent.asInstanceOf[TaprootTxSigComponent] val controlBlock = taprootScriptPath.controlBlock val script = taprootScriptPath.script - //execdata.m_tapleaf_hash = ComputeTapleafHash(control[0] & TAPROOT_LEAF_MASK, exec_script); + // execdata.m_tapleaf_hash = ComputeTapleafHash(control[0] & TAPROOT_LEAF_MASK, exec_script); val leaf = TapLeaf(controlBlock.leafVersion, script) val tapLeafHash = TaprootScriptPath.computeTapleafHash(leaf) val isValidTaprootCommitment = TaprootScriptPath.verifyTaprootCommitment( controlBlock = controlBlock, program = taprootSPK, - tapLeafHash = tapLeafHash) + tapLeafHash = tapLeafHash + ) if (!isValidTaprootCommitment) { val p = scriptPubKeyExecutedProgram.failExecution( - ScriptErrorWitnessProgramMisMatch) + ScriptErrorWitnessProgramMisMatch + ) Success(p) } else { val isDiscouragedTaprootVersion = scriptPubKeyExecutedProgram.flags.exists( - _ == ScriptVerifyDiscourageUpgradableTaprootVersion) + _ == ScriptVerifyDiscourageUpgradableTaprootVersion + ) if (controlBlock.isTapLeafMask) { - //drop the control block & script in the witness + // drop the control block & script in the witness val stackNoControlBlockOrScript = { if (scriptPubKeyExecutedProgram.getAnnexHashOpt.isDefined) { - //if we have an annex we need to drop - //annex,control block, script + // if we have an annex we need to drop + // annex,control block, script stack.tail.tail.tail } else { - //else just drop control block, script + // else just drop control block, script stack.tail.tail } } if ( stackNoControlBlockOrScript.exists( - _.bytes.length > MAX_PUSH_SIZE) + _.bytes.length > MAX_PUSH_SIZE + ) ) { val fail = scriptPubKeyExecutedProgram.failExecution( - ScriptErrorPushSize) + ScriptErrorPushSize + ) Success(fail) } else { val newProgram = PreExecutionScriptProgram( @@ -703,25 +745,26 @@ sealed abstract class ScriptInterpreter { } } else if (isDiscouragedTaprootVersion) { val p = scriptPubKeyExecutedProgram.failExecution( - ScriptErrorDiscourageUpgradableTaprootVersion) + ScriptErrorDiscourageUpgradableTaprootVersion + ) Success(p) } else { - //is this right? I believe to maintain softfork compatibility we - //just succeed? + // is this right? I believe to maintain softfork compatibility we + // just succeed? Success(scriptPubKeyExecutedProgram) } } } } } else { - //if taproot flag not set trivially pass + // if taproot flag not set trivially pass Success(scriptPubKeyExecutedProgram) } } private def handleOpSuccess( - scriptPubKeyExecutedProgram: ExecutedScriptProgram): Try[ - ExecutedScriptProgram] = { + scriptPubKeyExecutedProgram: ExecutedScriptProgram + ): Try[ExecutedScriptProgram] = { val discourageOpSuccess = ScriptFlagUtil.discourageOpSuccess(scriptPubKeyExecutedProgram.flags) val p = if (discourageOpSuccess) { @@ -733,17 +776,20 @@ sealed abstract class ScriptInterpreter { } /** Similar to the check schnorr signature method in bitcoin core - * @see https://github.com/bitcoin/bitcoin/blob/b71d37da2c8c8d2a9cef020731767a6929db54b4/src/script/interpreter.cpp#L1673 + * @see + * https://github.com/bitcoin/bitcoin/blob/b71d37da2c8c8d2a9cef020731767a6929db54b4/src/script/interpreter.cpp#L1673 */ private def checkSchnorrSignature( witness: TaprootKeyPath, pubKey: SchnorrPublicKey, - program: ExecutedScriptProgram): ExecutedScriptProgram = { + program: ExecutedScriptProgram + ): ExecutedScriptProgram = { val scriptResult = TransactionSignatureChecker.checkSchnorrSignature( program.txSignatureComponent, pubKey, witness, - program.taprootSerializationOptions) + program.taprootSerializationOptions + ) scriptResult match { case ScriptOk => // Set stack to OP_TRUE so we don't fail @@ -755,7 +801,8 @@ sealed abstract class ScriptInterpreter { /** Executes a PreExecutionScriptProgram */ private def executeProgram( - program: PreExecutionScriptProgram): ExecutedScriptProgram = { + program: PreExecutionScriptProgram + ): ExecutedScriptProgram = { val scriptByteVector = BytesUtil.toByteVector(program.script) val sigVersion = program.txSignatureComponent.sigVersion val isTaprootSigVersion = @@ -768,12 +815,13 @@ sealed abstract class ScriptInterpreter { } } - /** Finalizes an ExecutesScriptProgram by counting Script Ops - * and giving the ScriptProgram an error if there were too many. + /** Finalizes an ExecutesScriptProgram by counting Script Ops and giving the + * ScriptProgram an error if there were too many. */ @tailrec private def completeProgramExecution( - program: ExecutedScriptProgram): ExecutedScriptProgram = { + program: ExecutedScriptProgram + ): ExecutedScriptProgram = { val countedOps = program.originalScript .count(BitcoinScriptUtil.countsTowardsScriptOpLimit) val sigVersion = program.txSignatureComponent.sigVersion @@ -803,13 +851,17 @@ sealed abstract class ScriptInterpreter { /** The execution loop for a script * - * @param program the program whose script needs to be evaluated - * @return program the final state of the program after being evaluated by the interpreter + * @param program + * the program whose script needs to be evaluated + * @return + * program the final state of the program after being evaluated by the + * interpreter */ @tailrec private def loop( program: ExecutionInProgressScriptProgram, - opCount: Int): ExecutedScriptProgram = { + opCount: Int + ): ExecutedScriptProgram = { val scriptByteVector = BytesUtil.toByteVector(program.script) val sigVersion = program.txSignatureComponent.sigVersion val isTaprootSigVersion = @@ -820,33 +872,33 @@ sealed abstract class ScriptInterpreter { completeProgramExecution(program.failExecution(ScriptErrorScriptSize)) } else { val (nextProgram, nextOpCount) = program.script match { - //if at any time we see that the program is not valid - //cease script execution + // if at any time we see that the program is not valid + // cease script execution case _ if program.script.intersect(badOpCodes).nonEmpty => (program.failExecution(ScriptErrorBadOpCode), opCount) - //disabled operations + // disabled operations case _ if program.script .intersect(disabledOpCodes) .nonEmpty => (program.failExecution(ScriptErrorDisabledOpCode), opCount) - //program cannot contain a push operation > 520 bytes + // program cannot contain a push operation > 520 bytes case _ - if program.script.exists(token => - token.bytes.size > MAX_PUSH_SIZE) => + if program.script + .exists(token => token.bytes.size > MAX_PUSH_SIZE) => (program.failExecution(ScriptErrorPushSize), opCount) - //program stack size cannot be greater than 1000 elements + // program stack size cannot be greater than 1000 elements case _ if (program.stack.size + program.altStack.size) > 1000 => (program.failExecution(ScriptErrorStackSize), opCount) - //no more script operations to run, return whether the program is valid and the final state of the program + // no more script operations to run, return whether the program is valid and the final state of the program case Nil => (program.toExecutedProgram, opCount) case _ if !program.shouldExecuteNextOperation => (program.updateScript(program.script.tail), opCount) - //stack operations + // stack operations case OP_DUP :: _ => val programOrError = StackInterpreter.opDup(program) val newOpCount = @@ -961,7 +1013,7 @@ sealed abstract class ScriptInterpreter { calcOpCount(opCount, OP_2SWAP) (programOrError, newOpCount) - //arithmetic operations + // arithmetic operations case OP_ADD :: _ => val programOrError = ArithmeticInterpreter.opAdd(program) val newOpCount = @@ -1083,7 +1135,7 @@ sealed abstract class ScriptInterpreter { calcOpCount(opCount, OP_WITHIN) (programOrError, newOpCount) - //bitwise operations + // bitwise operations case OP_EQUAL :: _ => val programOrError = BitwiseInterpreter.opEqual(program) val newOpCount = @@ -1107,7 +1159,8 @@ sealed abstract class ScriptInterpreter { val programOrError = program.updateStackAndScript( ScriptNumber(scriptNumberOp.toLong) :: program.stack, - t) + t + ) val newOpCount = calcOpCount(opCount, scriptNumberOp) (programOrError, newOpCount) @@ -1151,7 +1204,7 @@ sealed abstract class ScriptInterpreter { calcOpCount(opCount, x) (programOrError, newOpCount) - //control operations + // control operations case OP_IF :: _ => val programOrError = ControlOperationsInterpreter.opIf(program) val newOpCount = @@ -1188,7 +1241,7 @@ sealed abstract class ScriptInterpreter { calcOpCount(opCount, OP_VERIFY) (programOrError, newOpCount) - //crypto operations + // crypto operations case OP_HASH160 :: _ => val programOrError = CryptoInterpreter.opHash160(program) val newOpCount = @@ -1245,7 +1298,7 @@ sealed abstract class ScriptInterpreter { case OP_CHECKMULTISIG :: _ => CryptoInterpreter.opCheckMultiSig(program) match { case newProgram: ExecutedScriptProgram => - //script was marked invalid for other reasons, don't need to update the opcount + // script was marked invalid for other reasons, don't need to update the opcount (newProgram, opCount) case newProgram: ExecutionInProgressScriptProgram => val programOrError = newProgram @@ -1259,7 +1312,7 @@ sealed abstract class ScriptInterpreter { case OP_CHECKMULTISIGVERIFY :: _ => CryptoInterpreter.opCheckMultiSigVerify(program) match { case newProgram: ExecutedScriptProgram => - //script was marked invalid for other reasons, don't need to update the opcount + // script was marked invalid for other reasons, don't need to update the opcount (newProgram, opCount) case newProgram: ExecutionInProgressScriptProgram => val programOrError = newProgram @@ -1270,19 +1323,21 @@ sealed abstract class ScriptInterpreter { (programOrError, newOpCount) } - //reserved operations + // reserved operations case OP_NOP :: t => - //script discourage upgradeable flag does not apply to a OP_NOP + // script discourage upgradeable flag does not apply to a OP_NOP val programOrError = program.updateScript(t) val newOpCount = calcOpCount(opCount, OP_NOP) (programOrError, newOpCount) - //if we see an OP_NOP and the DISCOURAGE_UPGRADABLE_OP_NOPS flag is set we must fail our program + // if we see an OP_NOP and the DISCOURAGE_UPGRADABLE_OP_NOPS flag is set we must fail our program case (nop: NOP) :: _ if ScriptFlagUtil.discourageUpgradableNOPs(program.flags) => - (program.failExecution(ScriptErrorDiscourageUpgradableNOPs), - calcOpCount(opCount, nop)) + ( + program.failExecution(ScriptErrorDiscourageUpgradableNOPs), + calcOpCount(opCount, nop) + ) case (nop: NOP) :: t => val programOrError = program.updateScript(t) val newOpCount = @@ -1290,31 +1345,41 @@ sealed abstract class ScriptInterpreter { (programOrError, newOpCount) case OP_RESERVED :: _ => - (program.failExecution(ScriptErrorBadOpCode), - calcOpCount(opCount, OP_RESERVED)) + ( + program.failExecution(ScriptErrorBadOpCode), + calcOpCount(opCount, OP_RESERVED) + ) case OP_VER :: _ => - (program.failExecution(ScriptErrorBadOpCode), - calcOpCount(opCount, OP_VER)) + ( + program.failExecution(ScriptErrorBadOpCode), + calcOpCount(opCount, OP_VER) + ) case OP_RESERVED1 :: _ => - (program.failExecution(ScriptErrorBadOpCode), - calcOpCount(opCount, OP_RESERVED1)) + ( + program.failExecution(ScriptErrorBadOpCode), + calcOpCount(opCount, OP_RESERVED1) + ) case OP_RESERVED2 :: _ => - (program.failExecution(ScriptErrorBadOpCode), - calcOpCount(opCount, OP_RESERVED2)) + ( + program.failExecution(ScriptErrorBadOpCode), + calcOpCount(opCount, OP_RESERVED2) + ) case (reservedOperation: ReservedOperation) :: _ => - (program.failExecution(ScriptErrorBadOpCode), - calcOpCount(opCount, reservedOperation)) - //splice operations + ( + program.failExecution(ScriptErrorBadOpCode), + calcOpCount(opCount, reservedOperation) + ) + // splice operations case OP_SIZE :: _ => val programOrError = SpliceInterpreter.opSize(program) val newOpCount = calcOpCount(opCount, OP_SIZE) (programOrError, newOpCount) - //locktime operations + // locktime operations case OP_CHECKLOCKTIMEVERIFY :: _ => - //check if CLTV is enforced yet + // check if CLTV is enforced yet if (ScriptFlagUtil.checkLockTimeVerifyEnabled(program.flags)) { val programOrError = LockTimeInterpreter.opCheckLockTimeVerify(program) @@ -1322,11 +1387,13 @@ sealed abstract class ScriptInterpreter { calcOpCount(opCount, OP_CHECKLOCKTIMEVERIFY) (programOrError, newOpCount) - } //if not, check to see if we should discourage p + } // if not, check to see if we should discourage p else if (ScriptFlagUtil.discourageUpgradableNOPs(program.flags)) { - (program.failExecution(ScriptErrorDiscourageUpgradableNOPs), - calcOpCount(opCount, OP_CHECKLOCKTIMEVERIFY)) - } //in this case, just reat OP_CLTV just like a NOP and remove it from the stack + ( + program.failExecution(ScriptErrorDiscourageUpgradableNOPs), + calcOpCount(opCount, OP_CHECKLOCKTIMEVERIFY) + ) + } // in this case, just reat OP_CLTV just like a NOP and remove it from the stack else { val programOrError = program.updateScript(program.script.tail) val newOpCount = @@ -1335,7 +1402,7 @@ sealed abstract class ScriptInterpreter { } case OP_CHECKSEQUENCEVERIFY :: _ => - //check if CLTV is enforced yet + // check if CLTV is enforced yet if (ScriptFlagUtil.checkSequenceVerifyEnabled(program.flags)) { val programOrError = LockTimeInterpreter.opCheckSequenceVerify(program) @@ -1343,11 +1410,13 @@ sealed abstract class ScriptInterpreter { calcOpCount(opCount, OP_CHECKSEQUENCEVERIFY) (programOrError, newOpCount) - } //if not, check to see if we should discourage p + } // if not, check to see if we should discourage p else if (ScriptFlagUtil.discourageUpgradableNOPs(program.flags)) { - (program.failExecution(ScriptErrorDiscourageUpgradableNOPs), - calcOpCount(opCount, OP_CHECKSEQUENCEVERIFY)) - } //in this case, just read OP_CSV just like a NOP and remove it from the stack + ( + program.failExecution(ScriptErrorDiscourageUpgradableNOPs), + calcOpCount(opCount, OP_CHECKSEQUENCEVERIFY) + ) + } // in this case, just read OP_CSV just like a NOP and remove it from the stack else { val programOrError = program.updateScript(program.script.tail) val newOpCount = @@ -1366,7 +1435,8 @@ sealed abstract class ScriptInterpreter { } } - /** Checks the validity of a transaction in accordance to bitcoin core's CheckTransaction function + /** Checks the validity of a transaction in accordance to bitcoin core's + * CheckTransaction function * https://github.com/bitcoin/bitcoin/blob/f7a21dae5dbf71d5bc00485215e84e6f2b309d0a/src/main.cpp#L939. */ def checkTransaction(transaction: Transaction): Boolean = { @@ -1394,12 +1464,14 @@ sealed abstract class ScriptInterpreter { allOutputsValidMoneyRange && noDuplicateInputs && isValidScriptSigForCoinbaseTx } - /** Determines if the given currency unit is within the valid range for the system */ + /** Determines if the given currency unit is within the valid range for the + * system + */ def validMoneyRange(currencyUnit: CurrencyUnit): Boolean = { currencyUnit >= CurrencyUnits.zero && currencyUnit <= Consensus.maxMoney } - /** Calculates the new op count after the execution of the given + /** Calculates the new op count after the execution of the given * [[org.bitcoins.core.script.constant.ScriptToken ScriptToken]] */ private def calcOpCount(oldOpCount: Int, token: ScriptToken): Int = @@ -1435,31 +1507,39 @@ sealed abstract class ScriptInterpreter { /** Helper function used to rebuild a * [[org.bitcoins.core.crypto.WitnessTxSigComponentRebuilt WitnessTxSigComponentRebuilt]] - * this converts a [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] - * into it's corresponding [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] + * this converts a + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] + * into it's corresponding + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] */ private def rebuildWTxSigComponent( old: WitnessTxSigComponent, - rebuildScriptPubKey: ScriptPubKey): Try[WitnessTxSigComponentRebuilt] = { + rebuildScriptPubKey: ScriptPubKey + ): Try[WitnessTxSigComponentRebuilt] = { val updatedOutput = TransactionOutput(old.output.value, rebuildScriptPubKey) old match { case wTxSigComponentRaw: WitnessTxSigComponentRaw => Success( - WitnessTxSigComponentRebuilt(old.transaction, - old.inputIndex, - updatedOutput, - wTxSigComponentRaw.scriptPubKey, - old.flags)) + WitnessTxSigComponentRebuilt( + old.transaction, + old.inputIndex, + updatedOutput, + wTxSigComponentRaw.scriptPubKey, + old.flags + ) + ) case wTxSigComponentP2SH: WitnessTxSigComponentP2SH => wTxSigComponentP2SH.witnessScriptPubKey.map { wit: WitnessScriptPubKey => val updatedOutput = TransactionOutput(old.output.value, rebuildScriptPubKey) - WitnessTxSigComponentRebuilt(old.transaction, - old.inputIndex, - updatedOutput, - wit, - old.flags) + WitnessTxSigComponentRebuilt( + old.transaction, + old.inputIndex, + updatedOutput, + wit, + old.flags + ) } case _: TaprootTxSigComponent => @@ -1469,7 +1549,8 @@ sealed abstract class ScriptInterpreter { /** Logic to evaluate a witnesss version that has not been assigned yet */ private def evaluateUnassignedWitness( - txSigComponent: TxSigComponent): Try[ExecutedScriptProgram] = { + txSigComponent: TxSigComponent + ): Try[ExecutedScriptProgram] = { val flags = txSigComponent.flags val discourageUpgradableWitnessVersion = ScriptFlagUtil.discourageUpgradableWitnessProgram(flags) @@ -1487,8 +1568,8 @@ sealed abstract class ScriptInterpreter { ) Success(executed) } else { - //if we are not discouraging upgradable ops, we just trivially return the program with an OP_TRUE on the stack - //see: https://github.com/bitcoin/bitcoin/blob/b83264d9c7a8ddb79f64bd9540caddc8632ef31f/src/script/interpreter.cpp#L1386-L1389 + // if we are not discouraging upgradable ops, we just trivially return the program with an OP_TRUE on the stack + // see: https://github.com/bitcoin/bitcoin/blob/b83264d9c7a8ddb79f64bd9540caddc8632ef31f/src/script/interpreter.cpp#L1386-L1389 val inProgress = PreExecutionScriptProgram( txSignatureComponent = txSigComponent, stack = List(OP_TRUE), @@ -1506,22 +1587,24 @@ sealed abstract class ScriptInterpreter { object ScriptInterpreter extends ScriptInterpreter { val bip341DisabledOpCodes = { - Vector(OP_CAT, - OP_SUBSTR, - OP_LEFT, - OP_RIGHT, - OP_INVERT, - OP_AND, - OP_OR, - OP_XOR, - OP_RESERVED1, - OP_RESERVED2, - OP_2MUL, - OP_2DIV, - OP_MUL, - OP_DIV, - OP_MOD, - OP_LSHIFT, - OP_RSHIFT) + Vector( + OP_CAT, + OP_SUBSTR, + OP_LEFT, + OP_RIGHT, + OP_INVERT, + OP_AND, + OP_OR, + OP_XOR, + OP_RESERVED1, + OP_RESERVED2, + OP_2MUL, + OP_2DIV, + OP_MUL, + OP_DIV, + OP_MOD, + OP_LSHIFT, + OP_RSHIFT + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/script/locktime/LockTimeInterpreter.scala b/core/src/main/scala/org/bitcoins/core/script/locktime/LockTimeInterpreter.scala index ba9d99ec1b..ca7ab04de6 100644 --- a/core/src/main/scala/org/bitcoins/core/script/locktime/LockTimeInterpreter.scala +++ b/core/src/main/scala/org/bitcoins/core/script/locktime/LockTimeInterpreter.scala @@ -20,20 +20,23 @@ import scala.annotation.tailrec */ sealed abstract class LockTimeInterpreter { - /** Marks transaction as invalid if the top stack item is greater than the transaction's `nLockTime` field, - * otherwise script evaluation continues as though an `OP_NOP` was executed. Transaction is also invalid if - * 1. the stack is empty; or - * 2. the top stack item is negative; or - * 3. the top stack item is greater than or equal to 500000000 while the transaction's nLockTime field is less than 500000000, - * or vice versa; or - * 4. the input's `nSequence` field is equal to 0xffffffff. - * The precise semantics are described in BIP 0065 + /** Marks transaction as invalid if the top stack item is greater than the + * transaction's `nLockTime` field, otherwise script evaluation continues as + * though an `OP_NOP` was executed. Transaction is also invalid if + * 1. the stack is empty; or 2. the top stack item is negative; or 3. the + * top stack item is greater than or equal to 500000000 while the + * transaction's nLockTime field is less than 500000000, or vice versa; + * or 4. the input's `nSequence` field is equal to 0xffffffff. The + * precise semantics are described in BIP 0065 */ @tailrec final def opCheckLockTimeVerify( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_CHECKLOCKTIMEVERIFY), - "Script top must be OP_CHECKLOCKTIMEVERIFY") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_CHECKLOCKTIMEVERIFY), + "Script top must be OP_CHECKLOCKTIMEVERIFY" + ) val input = program.txSignatureComponent.transaction .inputs(program.txSignatureComponent.inputIndex.toInt) val transaction = program.txSignatureComponent.transaction @@ -47,15 +50,17 @@ sealed abstract class LockTimeInterpreter { program.failExecution(ScriptErrorNegativeLockTime) case s: ScriptNumber if s >= ScriptNumber(500000000) && transaction.lockTime < UInt32( - 500000000) => + 500000000 + ) => program.failExecution(ScriptErrorUnsatisfiedLocktime) case s: ScriptNumber if s < ScriptNumber(500000000) && transaction.lockTime >= UInt32( - 500000000) => + 500000000 + ) => program.failExecution(ScriptErrorUnsatisfiedLocktime) case s: ScriptNumber => if (s.bytes.size > 5) { - //if the number size is larger than 5 bytes the number is invalid + // if the number size is larger than 5 bytes the number is invalid program.failExecution(ScriptErrorUnknownError) } else if (checkLockTime(program, s)) { program.updateScript(program.script.tail) @@ -64,26 +69,29 @@ sealed abstract class LockTimeInterpreter { } case s: ScriptConstant => opCheckLockTimeVerify( - program.updateStack(ScriptNumber(s.hex) :: program.stack.tail)) + program.updateStack(ScriptNumber(s.hex) :: program.stack.tail) + ) case _: ScriptToken => program.failExecution(ScriptErrorUnknownError) } } } - /** When executed, if any of the following conditions are true, the script interpreter will terminate with an error: - * 1.) the stack is empty; or - * 2.) the top item on the stack is less than 0; or - * 3.) the top item on the stack has the disable flag (1 << 31) unset; and - * the transaction version is less than 2; or - * the transaction input sequence number disable flag (1 << 31) is set; or - * the relative lock-time type is not the same; or - * the top stack item is greater than the transaction sequence (when masked according to the BIP68); - * Otherwise, script execution will continue as if a `NOP` had been executed. - * See [[https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP112]] for more information + /** When executed, if any of the following conditions are true, the script + * interpreter will terminate with an error: 1.) the stack is empty; or 2.) + * the top item on the stack is less than 0; or 3.) the top item on the stack + * has the disable flag (1 << 31) unset; and the transaction version is less + * than 2; or the transaction input sequence number disable flag (1 << 31) is + * set; or the relative lock-time type is not the same; or the top stack item + * is greater than the transaction sequence (when masked according to the + * BIP68); Otherwise, script execution will continue as if a `NOP` had been + * executed. See + * [[https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki BIP112]] + * for more information */ @tailrec final def opCheckSequenceVerify( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { if (program.stack.isEmpty) { program.failExecution(ScriptErrorInvalidStackOperation) } else { @@ -92,18 +100,20 @@ sealed abstract class LockTimeInterpreter { program.failExecution(ScriptErrorNegativeLockTime) case s: ScriptNumber if ScriptFlagUtil.requireMinimalData( - program.flags) && !s.isShortestEncoding => + program.flags + ) && !s.isShortestEncoding => program.failExecution(ScriptErrorUnknownError) case s: ScriptNumber if !isLockTimeBitOff(s) => - //see BIP68 for semantic of locktimeDisableFlag + // see BIP68 for semantic of locktimeDisableFlag program.updateScript(program.script.tail) case s: ScriptNumber if isLockTimeBitOff( - s) && program.txSignatureComponent.transaction.version.toUInt32 < TransactionConstants.validLockVersion.toUInt32 => + s + ) && program.txSignatureComponent.transaction.version.toUInt32 < TransactionConstants.validLockVersion.toUInt32 => program.failExecution(ScriptErrorUnsatisfiedLocktime) case s: ScriptNumber => if (s.bytes.size > 5) { - //if the number size is larger than 5 bytes the number is invalid + // if the number size is larger than 5 bytes the number is invalid program.failExecution(ScriptErrorUnknownError) } else if (checkSequence(program, s)) { program.updateScript(program.script.tail) @@ -112,28 +122,37 @@ sealed abstract class LockTimeInterpreter { } case s: ScriptConstant => opCheckSequenceVerify( - program.updateStack(ScriptNumber(s.hex) :: program.stack.tail)) + program.updateStack(ScriptNumber(s.hex) :: program.stack.tail) + ) case token: ScriptToken => throw new RuntimeException( - "Stack top must be either a ScriptConstant or a ScriptNumber, we got: " + token) + "Stack top must be either a ScriptConstant or a ScriptNumber, we got: " + token + ) } } } - /** @see Mimics - * [[https://github.com/bitcoin/bitcoin/blob/e26b62093ae21e89ed7d36a24a6b863f38ec631d/src/script/interpreter.cpp#L1196 this function]] - * inside of Bitcoin Core + /** @see + * Mimics + * [[https://github.com/bitcoin/bitcoin/blob/e26b62093ae21e89ed7d36a24a6b863f38ec631d/src/script/interpreter.cpp#L1196 this function]] + * inside of Bitcoin Core * - * @see [[https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki#specification BIP68]] + * @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki#specification BIP68]] * - * @param program the program whose transaction input's sequence is being compared - * @param nSequence the script number on the stack top to compare to the input's sequence number - * @return if the given script number is valid or not + * @param program + * the program whose transaction input's sequence is being compared + * @param nSequence + * the script number on the stack top to compare to the input's sequence + * number + * @return + * if the given script number is valid or not */ def checkSequence( program: ExecutionInProgressScriptProgram, - nSequence: ScriptNumber): Boolean = { + nSequence: ScriptNumber + ): Boolean = { val inputIndex = program.txSignatureComponent.inputIndex.toInt val transaction = program.txSignatureComponent.transaction @@ -168,7 +187,8 @@ sealed abstract class LockTimeInterpreter { if ( !(isCSVLockByBlockHeight( nSequence, - txToSequence) || isCSVLockByRelativeLockTime(nSequence, txToSequence)) + txToSequence + ) || isCSVLockByRelativeLockTime(nSequence, txToSequence)) ) { return false } @@ -184,12 +204,13 @@ sealed abstract class LockTimeInterpreter { /** Checks if the given * [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and - * [[org.bitcoins.core.number.UInt32 UInt32]] are valid values for spending - * a OP_CSV value by block height + * [[org.bitcoins.core.number.UInt32 UInt32]] are valid values for spending a + * OP_CSV value by block height */ def isCSVLockByBlockHeight( scriptNumber: ScriptNumber, - sequence: UInt32): Boolean = { + sequence: UInt32 + ): Boolean = { isCSVLockByBlockHeight(scriptNumber) && isCSVLockByBlockHeight(sequence) } @@ -199,13 +220,15 @@ sealed abstract class LockTimeInterpreter { def isCSVLockByBlockHeight(scriptNumber: ScriptNumber): Boolean = !isCSVLockByRelativeLockTime(scriptNumber) - /** Checks if the given [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and - * [[org.bitcoins.core.number.UInt32 UInt32]] are valid values - * for spending an OP_CSV value by time based relative lock time + /** Checks if the given + * [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and + * [[org.bitcoins.core.number.UInt32 UInt32]] are valid values for spending + * an OP_CSV value by time based relative lock time */ def isCSVLockByRelativeLockTime( number: ScriptNumber, - sequence: UInt32): Boolean = { + sequence: UInt32 + ): Boolean = { isCSVLockByRelativeLockTime(number) && isCSVLockByRelativeLockTime(sequence) } @@ -220,7 +243,10 @@ sealed abstract class LockTimeInterpreter { result } - /** Masks the given [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] according to BIP112 */ + /** Masks the given + * [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] according + * to BIP112 + */ def maskScriptNumber(scriptNumber: ScriptNumber): ScriptNumber = { val nSequenceMasked: ScriptNumber = scriptNumber & Int64(TransactionConstants.fullSequenceLockTimeMask.toLong) @@ -229,18 +255,21 @@ sealed abstract class LockTimeInterpreter { def maskSequenceNumber(sequence: UInt32): Int64 = { val txToSequenceMasked: Int64 = Int64( - (sequence & TransactionConstants.fullSequenceLockTimeMask).toLong) + (sequence & TransactionConstants.fullSequenceLockTimeMask).toLong + ) txToSequenceMasked } /** Checks the locktime of a transaction. - * @see Mimics - * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1160 this function]] - * inside of Bitcoin Core + * @see + * Mimics + * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1160 this function]] + * inside of Bitcoin Core */ private def checkLockTime( program: ExecutionInProgressScriptProgram, - locktime: ScriptNumber): Boolean = { + locktime: ScriptNumber + ): Boolean = { // There are two kinds of nLockTime: lock-by-blockheight // and lock-by-blocktime, distinguished by whether // nLockTime < LOCKTIME_THRESHOLD. @@ -278,7 +307,9 @@ sealed abstract class LockTimeInterpreter { } else true } - /** The [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] on the stack has the disable flag (1 << 31) unset. */ + /** The [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] on the + * stack has the disable flag (1 << 31) unset. + */ def isLockTimeBitOff(s: ScriptNumber): Boolean = (s.toLong & TransactionConstants.locktimeDisabledFlag.toLong) == 0 diff --git a/core/src/main/scala/org/bitcoins/core/script/locktime/LocktimeOperations.scala b/core/src/main/scala/org/bitcoins/core/script/locktime/LocktimeOperations.scala index c61267bf0a..01604d9a4c 100644 --- a/core/src/main/scala/org/bitcoins/core/script/locktime/LocktimeOperations.scala +++ b/core/src/main/scala/org/bitcoins/core/script/locktime/LocktimeOperations.scala @@ -7,28 +7,28 @@ import org.bitcoins.core.script.constant.ScriptOperation */ sealed trait LocktimeOperation extends ScriptOperation -/** Marks transaction as invalid if the top stack item is greater than the transaction's nLockTime field, - * otherwise script evaluation continues as though an OP_NOP was executed. Transaction is also invalid if - * 1. the stack is empty; or - * 2. the top stack item is negative; or - * 3. the top stack item is greater than or equal to 500000000 while the transaction's nLockTime field is less than 500000000, - * or vice versa; or 4. the input's nSequence field is equal to 0xffffffff. - * The precise semantics are described in BIP 0065 +/** Marks transaction as invalid if the top stack item is greater than the + * transaction's nLockTime field, otherwise script evaluation continues as + * though an OP_NOP was executed. Transaction is also invalid if + * 1. the stack is empty; or 2. the top stack item is negative; or 3. the top + * stack item is greater than or equal to 500000000 while the + * transaction's nLockTime field is less than 500000000, or vice versa; or + * 4. the input's nSequence field is equal to 0xffffffff. The precise + * semantics are described in BIP 0065 */ case object OP_CHECKLOCKTIMEVERIFY extends LocktimeOperation { override val opCode: Int = 177 } -/** When executed, if any of the following conditions are true, the script interpreter will terminate with an error: - * 1.) the stack is empty; or - * 2.) the top item on the stack is less than 0; or - * 3.) the top item on the stack has the disable flag (1 << 31) unset; and - * the transaction version is less than 2; or - * the transaction input sequence number disable flag (1 << 31) is set; or - * the relative lock-time type is not the same; or - * the top stack item is greater than the transaction sequence (when masked according to the BIP68); - * Otherwise, script execution will continue as if a NOP had been executed. - * See BIP112 for more information +/** When executed, if any of the following conditions are true, the script + * interpreter will terminate with an error: 1.) the stack is empty; or 2.) the + * top item on the stack is less than 0; or 3.) the top item on the stack has + * the disable flag (1 << 31) unset; and the transaction version is less than + * 2; or the transaction input sequence number disable flag (1 << 31) is set; + * or the relative lock-time type is not the same; or the top stack item is + * greater than the transaction sequence (when masked according to the BIP68); + * Otherwise, script execution will continue as if a NOP had been executed. See + * BIP112 for more information * https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki */ case object OP_CHECKSEQUENCEVERIFY extends LocktimeOperation { diff --git a/core/src/main/scala/org/bitcoins/core/script/reserved/ReservedOperations.scala b/core/src/main/scala/org/bitcoins/core/script/reserved/ReservedOperations.scala index 61251457c8..ad7be31e7e 100644 --- a/core/src/main/scala/org/bitcoins/core/script/reserved/ReservedOperations.scala +++ b/core/src/main/scala/org/bitcoins/core/script/reserved/ReservedOperations.scala @@ -5,8 +5,8 @@ import org.bitcoins.core.script.constant.ScriptOperation /** Created by chris on 1/22/16. */ -/** Reserved words - * Any opcode not assigned is also reserved. Using an unassigned opcode makes the transaction invalid. +/** Reserved words Any opcode not assigned is also reserved. Using an unassigned + * opcode makes the transaction invalid. * https://en.bitcoin.it/wiki/Script#Reserved_words */ sealed trait ReservedOperation extends ScriptOperation @@ -29,7 +29,7 @@ case object OP_VERIF extends ReservedOperation { override val opCode: Int = 101 } -/** Transaction is invalid even when occuring in an unexecuted OP_IF branch +/** Transaction is invalid even when occuring in an unexecuted OP_IF branch */ case object OP_VERNOTIF extends ReservedOperation { override val opCode: Int = 102 @@ -47,8 +47,7 @@ case object OP_RESERVED2 extends ReservedOperation { override val opCode: Int = 138 } -/** Represents an operation that means - * nothing inside the Script language +/** Represents an operation that means nothing inside the Script language */ sealed trait NOP extends ReservedOperation @@ -94,20 +93,22 @@ object ReservedOperation extends ScriptOperationFactory[ReservedOperation] { lazy val undefinedOpCodes = for { i <- 0xbb to 0xff } yield UndefinedOP_NOP(i) override val operations = - Vector(OP_RESERVED, - OP_VER, - OP_VERIF, - OP_VERNOTIF, - OP_RESERVED, - OP_RESERVED1, - OP_RESERVED2, - OP_NOP, - OP_NOP1, - OP_NOP4, - OP_NOP5, - OP_NOP6, - OP_NOP7, - OP_NOP8, - OP_NOP9, - OP_NOP10) ++ undefinedOpCodes + Vector( + OP_RESERVED, + OP_VER, + OP_VERIF, + OP_VERNOTIF, + OP_RESERVED, + OP_RESERVED1, + OP_RESERVED2, + OP_NOP, + OP_NOP1, + OP_NOP4, + OP_NOP5, + OP_NOP6, + OP_NOP7, + OP_NOP8, + OP_NOP9, + OP_NOP10 + ) ++ undefinedOpCodes } diff --git a/core/src/main/scala/org/bitcoins/core/script/splice/SpliceInterpreter.scala b/core/src/main/scala/org/bitcoins/core/script/splice/SpliceInterpreter.scala index d414feb903..2a705a8811 100644 --- a/core/src/main/scala/org/bitcoins/core/script/splice/SpliceInterpreter.scala +++ b/core/src/main/scala/org/bitcoins/core/script/splice/SpliceInterpreter.scala @@ -11,11 +11,16 @@ import org.bitcoins.core.script.{ */ sealed abstract class SpliceInterpreter { - /** Pushes the string length of the top element of the stack (without popping it). */ + /** Pushes the string length of the top element of the stack (without popping + * it). + */ def opSize( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_SIZE), - "Script top must be OP_SIZE") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_SIZE), + "Script top must be OP_SIZE" + ) if (program.stack.nonEmpty) { if (program.stack.head == OP_0) { program.updateStackAndScript(OP_0 :: program.stack, program.script.tail) @@ -24,8 +29,10 @@ sealed abstract class SpliceInterpreter { case ScriptNumber.zero => ScriptNumber.zero case x: ScriptToken => ScriptNumber(x.bytes.size) } - program.updateStackAndScript(scriptNumber :: program.stack, - program.script.tail) + program.updateStackAndScript( + scriptNumber :: program.stack, + program.script.tail + ) } } else { program.failExecution(ScriptErrorInvalidStackOperation) diff --git a/core/src/main/scala/org/bitcoins/core/script/stack/StackInterpreter.scala b/core/src/main/scala/org/bitcoins/core/script/stack/StackInterpreter.scala index 8d9ce07b39..42f90c02cf 100644 --- a/core/src/main/scala/org/bitcoins/core/script/stack/StackInterpreter.scala +++ b/core/src/main/scala/org/bitcoins/core/script/stack/StackInterpreter.scala @@ -10,18 +10,19 @@ import org.bitcoins.core.script.{ import scala.util.{Failure, Success, Try} -/** Created by chris on 1/6/16. - * Stack operations implemented in the script programming language - * https://en.bitcoin.it/wiki/Script#Stack +/** Created by chris on 1/6/16. Stack operations implemented in the script + * programming language https://en.bitcoin.it/wiki/Script#Stack */ sealed abstract class StackInterpreter { - /** Duplicates the element on top of the stack - * expects the first element in script to be the OP_DUP operation. + /** Duplicates the element on top of the stack expects the first element in + * script to be the OP_DUP operation. */ def opDup(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_DUP), - "Top of the script stack must be OP_DUP") + require( + program.script.headOption.contains(OP_DUP), + "Top of the script stack must be OP_DUP" + ) program.stack match { case h :: _ => program.updateStackAndScript(h :: program.stack, program.script.tail) @@ -32,14 +33,19 @@ sealed abstract class StackInterpreter { /** If the top stack value is not 0, duplicate it. */ def opIfDup( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_IFDUP), - "Top of the script stack must be OP_DUP") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_IFDUP), + "Top of the script stack must be OP_DUP" + ) if (program.stack.nonEmpty) { if (program.stack.head == ScriptNumber.zero) return program.updateScript(program.script.tail) - program.updateStackAndScript(program.stack.head :: program.stack, - program.script.tail) + program.updateStackAndScript( + program.stack.head :: program.stack, + program.script.tail + ) } else { program.failExecution(ScriptErrorInvalidStackOperation) } @@ -47,20 +53,30 @@ sealed abstract class StackInterpreter { /** Puts the number of stack items onto the stack. */ def opDepth( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_DEPTH), - "Top of script stack must be OP_DEPTH") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_DEPTH), + "Top of script stack must be OP_DEPTH" + ) val stackSize = program.stack.size val numberToPush: ScriptNumber = ScriptNumber(stackSize) - program.updateStackAndScript(numberToPush :: program.stack, - program.script.tail) + program.updateStackAndScript( + numberToPush :: program.stack, + program.script.tail + ) } - /** Puts the input onto the top of the alt stack. Removes it from the main stack. */ + /** Puts the input onto the top of the alt stack. Removes it from the main + * stack. + */ def opToAltStack( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_TOALTSTACK), - "Top of script stack must be OP_TOALTSTACK") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_TOALTSTACK), + "Top of script stack must be OP_TOALTSTACK" + ) if (program.stack.nonEmpty) { program .updateStack(program.stack.tail) @@ -71,11 +87,16 @@ sealed abstract class StackInterpreter { } } - /** Puts the input onto the top of the main stack. Removes it from the alt stack. */ + /** Puts the input onto the top of the main stack. Removes it from the alt + * stack. + */ def opFromAltStack( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_FROMALTSTACK), - "Top of script stack must be OP_FROMALTSTACK") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_FROMALTSTACK), + "Top of script stack must be OP_FROMALTSTACK" + ) if (program.altStack.nonEmpty) { program .updateStack(program.altStack.head :: program.stack) @@ -88,9 +109,12 @@ sealed abstract class StackInterpreter { /** Removes the top stack item. */ def opDrop( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_DROP), - "Top of script stack must be OP_DROP") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_DROP), + "Top of script stack must be OP_DROP" + ) if (program.stack.nonEmpty) { program.updateStackAndScript(program.stack.tail, program.script.tail) } else { @@ -100,8 +124,10 @@ sealed abstract class StackInterpreter { /** Removes the second-to-top stack item. */ def opNip(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_NIP), - "Top of script stack must be OP_NIP") + require( + program.script.headOption.contains(OP_NIP), + "Top of script stack must be OP_NIP" + ) program.stack match { case h :: _ :: t => program.updateStackAndScript(h :: t, program.script.tail) @@ -114,9 +140,12 @@ sealed abstract class StackInterpreter { /** Copies the second-to-top stack item to the top. */ def opOver( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_OVER), - "Top of script stack must be OP_OVER") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_OVER), + "Top of script stack must be OP_OVER" + ) program.stack match { case _ :: h1 :: _ => program.updateStackAndScript(h1 :: program.stack, program.script.tail) @@ -129,21 +158,26 @@ sealed abstract class StackInterpreter { /** The item n back in the stack is copied to the top. */ def opPick( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_PICK), - "Top of script stack must be OP_PICK") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_PICK), + "Top of script stack must be OP_PICK" + ) executeOpWithStackTopAsNumberArg( program, { number: ScriptNumber => - //check if n is within the bound of the script + // check if n is within the bound of the script if (program.stack.size < 2) program.failExecution(ScriptErrorInvalidStackOperation) else if ( number.toLong >= 0 && number.toLong < program.stack.tail.size ) { val newStackTop = program.stack.tail(number.toInt) - program.updateStackAndScript(newStackTop :: program.stack.tail, - program.script.tail) + program.updateStackAndScript( + newStackTop :: program.stack.tail, + program.script.tail + ) } else { program.failExecution(ScriptErrorInvalidStackOperation) } @@ -153,9 +187,12 @@ sealed abstract class StackInterpreter { /** The item n back in the stack is moved to the top. */ def opRoll( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_ROLL), - "Top of script stack must be OP_ROLL") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_ROLL), + "Top of script stack must be OP_ROLL" + ) executeOpWithStackTopAsNumberArg( program, (number: ScriptNumber) => @@ -165,7 +202,7 @@ sealed abstract class StackInterpreter { number.toLong >= 0 && number.toLong < program.stack.tail.size ) { val newStackTop = program.stack.tail(number.toInt) - //removes the old instance of the stack top, appends the new index to the head + // removes the old instance of the stack top, appends the new index to the head val newStack = newStackTop :: program.stack.tail .diff(List(newStackTop)) program.updateStackAndScript(newStack, program.script.tail) @@ -175,12 +212,14 @@ sealed abstract class StackInterpreter { ) } - /** The top three items on the stack are rotated to the left. - * Ex: x1 x2 x3 -> x2 x3 x1 + /** The top three items on the stack are rotated to the left. Ex: x1 x2 x3 -> + * x2 x3 x1 */ def opRot(program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_ROT), - "Top of script stack must be OP_ROT") + require( + program.script.headOption.contains(OP_ROT), + "Top of script stack must be OP_ROT" + ) program.stack match { case h :: h1 :: h2 :: t => val newStack = h2 :: h :: h1 :: t @@ -190,13 +229,16 @@ sealed abstract class StackInterpreter { } } - /** The fifth and sixth items back are moved to the top of the stack. - * Ex. x1 x2 x3 x4 x5 x6 -> x3 x4 x5 x6 x1 x2 + /** The fifth and sixth items back are moved to the top of the stack. Ex. x1 + * x2 x3 x4 x5 x6 -> x3 x4 x5 x6 x1 x2 */ def op2Rot( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_2ROT), - "Top of script stack must be OP_2ROT") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_2ROT), + "Top of script stack must be OP_2ROT" + ) program.stack match { case h :: h1 :: h2 :: h3 :: h4 :: h5 :: t => val newStack = h4 :: h5 :: h :: h1 :: h2 :: h3 :: t @@ -208,9 +250,12 @@ sealed abstract class StackInterpreter { /** Removes the top two stack items. */ def op2Drop( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_2DROP), - "Top of script stack must be OP_2DROP") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_2DROP), + "Top of script stack must be OP_2DROP" + ) if (program.stack.size > 1) { program.updateStackAndScript(program.stack.tail.tail, program.script.tail) } else { @@ -220,9 +265,12 @@ sealed abstract class StackInterpreter { /** The top two items on the stack are swapped. */ def opSwap( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_SWAP), - "Top of script stack must be OP_SWAP") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_SWAP), + "Top of script stack must be OP_SWAP" + ) if (program.stack.size > 1) { val newStack = program.stack.tail.head :: program.stack.head :: program.stack.tail.tail @@ -232,11 +280,16 @@ sealed abstract class StackInterpreter { } } - /** The item at the top of the stack is copied and inserted before the second-to-top item. */ + /** The item at the top of the stack is copied and inserted before the + * second-to-top item. + */ def opTuck( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_TUCK), - "Top of script stack must be OP_TUCK") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_TUCK), + "Top of script stack must be OP_TUCK" + ) program.stack match { case h :: h1 :: t => val newStack = h :: h1 :: h :: t @@ -248,9 +301,12 @@ sealed abstract class StackInterpreter { /** Duplicates the top two stack items. */ def op2Dup( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_2DUP), - "Top of script stack must be OP_2DUP") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_2DUP), + "Top of script stack must be OP_2DUP" + ) program.stack match { case h :: h1 :: t => val newStack = h :: h1 :: h :: h1 :: t @@ -262,9 +318,12 @@ sealed abstract class StackInterpreter { /** Duplicates the top three stack items. */ def op3Dup( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_3DUP), - "Top of script stack must be OP_3DUP") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_3DUP), + "Top of script stack must be OP_3DUP" + ) program.stack match { case h :: h1 :: h2 :: t => val newStack = h :: h1 :: h2 :: h :: h1 :: h2 :: t @@ -276,9 +335,12 @@ sealed abstract class StackInterpreter { /** Copies the pair of items two spaces back in the stack to the front. */ def op2Over( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_2OVER), - "Top of script stack must be OP_2OVER") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_2OVER), + "Top of script stack must be OP_2OVER" + ) program.stack match { case h :: h1 :: h2 :: h3 :: t => val newStack = h2 :: h3 :: h :: h1 :: h2 :: h3 :: t @@ -290,9 +352,12 @@ sealed abstract class StackInterpreter { /** Swaps the top two pairs of items. */ def op2Swap( - program: ExecutionInProgressScriptProgram): StartedScriptProgram = { - require(program.script.headOption.contains(OP_2SWAP), - "Top of script stack must be OP_2SWAP") + program: ExecutionInProgressScriptProgram + ): StartedScriptProgram = { + require( + program.script.headOption.contains(OP_2SWAP), + "Top of script stack must be OP_2SWAP" + ) program.stack match { case h :: h1 :: h2 :: h3 :: t => val newStack = h2 :: h3 :: h :: h1 :: t @@ -302,21 +367,29 @@ sealed abstract class StackInterpreter { } } - /** Executes an operation with the stack top inside of the program as the argument - * @param program the program whose stack top is used as an argument for the operation - * @param op the operation that is executed with the script number on the top of the stack - * @return the program with the result of the op pushed onto to the top of the stack + /** Executes an operation with the stack top inside of the program as the + * argument + * @param program + * the program whose stack top is used as an argument for the operation + * @param op + * the operation that is executed with the script number on the top of the + * stack + * @return + * the program with the result of the op pushed onto to the top of the + * stack */ private def executeOpWithStackTopAsNumberArg( program: ExecutionInProgressScriptProgram, - op: ScriptNumber => StartedScriptProgram): StartedScriptProgram = { + op: ScriptNumber => StartedScriptProgram + ): StartedScriptProgram = { program.stack.head match { case scriptNum: ScriptNumber => op(scriptNum) case _: ScriptToken => - //interpret the stack top as a number + // interpret the stack top as a number val number: Try[ScriptNumber] = ScriptNumber( program.stack.head.bytes, - ScriptFlagUtil.requireMinimalData(program.flags)) + ScriptFlagUtil.requireMinimalData(program.flags) + ) number match { case Success(n) => op(n) case Failure(_) => diff --git a/core/src/main/scala/org/bitcoins/core/script/stack/StackOperations.scala b/core/src/main/scala/org/bitcoins/core/script/stack/StackOperations.scala index e50e926cc1..44ff828f51 100644 --- a/core/src/main/scala/org/bitcoins/core/script/stack/StackOperations.scala +++ b/core/src/main/scala/org/bitcoins/core/script/stack/StackOperations.scala @@ -7,13 +7,15 @@ import org.bitcoins.core.script.constant.ScriptOperation */ sealed trait StackOperation extends ScriptOperation -/** Puts the input onto the top of the alt stack. Removes it from the main stack. +/** Puts the input onto the top of the alt stack. Removes it from the main + * stack. */ case object OP_TOALTSTACK extends StackOperation { override val opCode: Int = 107 } -/** Puts the input onto the top of the main stack. Removes it from the alt stack. +/** Puts the input onto the top of the main stack. Removes it from the alt + * stack. */ case object OP_FROMALTSTACK extends StackOperation { override val opCode: Int = 108 @@ -37,7 +39,7 @@ case object OP_DROP extends StackOperation { override val opCode: Int = 117 } -/** Duplicates the top stack item. +/** Duplicates the top stack item. */ case object OP_DUP extends StackOperation { override val opCode: Int = 118 @@ -49,7 +51,7 @@ case object OP_NIP extends StackOperation { override val opCode: Int = 119 } -/** Copies the second-to-top stack item to the top. +/** Copies the second-to-top stack item to the top. */ case object OP_OVER extends StackOperation { override val opCode: Int = 120 @@ -73,19 +75,20 @@ case object OP_ROT extends StackOperation { override val opCode: Int = 123 } -/** The top two items on the stack are swapped. +/** The top two items on the stack are swapped. */ case object OP_SWAP extends StackOperation { override val opCode: Int = 124 } -/** The item at the top of the stack is copied and inserted before the second-to-top item. +/** The item at the top of the stack is copied and inserted before the + * second-to-top item. */ case object OP_TUCK extends StackOperation { override val opCode: Int = 125 } -/** Removes the top two stack items. +/** Removes the top two stack items. */ case object OP_2DROP extends StackOperation { override val opCode: Int = 109 @@ -115,7 +118,7 @@ case object OP_2ROT extends StackOperation { override val opCode: Int = 113 } -/** Swaps the top two pairs of items. +/** Swaps the top two pairs of items. */ case object OP_2SWAP extends StackOperation { override val opCode: Int = 114 diff --git a/core/src/main/scala/org/bitcoins/core/script/util/PreviousOutputMap.scala b/core/src/main/scala/org/bitcoins/core/script/util/PreviousOutputMap.scala index c28a8e3aa2..736a68233b 100644 --- a/core/src/main/scala/org/bitcoins/core/script/util/PreviousOutputMap.scala +++ b/core/src/main/scala/org/bitcoins/core/script/util/PreviousOutputMap.scala @@ -5,8 +5,8 @@ import org.bitcoins.core.util.MapWrapper import org.bitcoins.core.wallet.utxo._ case class PreviousOutputMap( - outputMap: Map[TransactionOutPoint, TransactionOutput]) - extends MapWrapper[TransactionOutPoint, TransactionOutput] { + outputMap: Map[TransactionOutPoint, TransactionOutput] +) extends MapWrapper[TransactionOutPoint, TransactionOutput] { override protected val wrapped: Map[TransactionOutPoint, TransactionOutput] = outputMap @@ -17,7 +17,8 @@ object PreviousOutputMap { val empty: PreviousOutputMap = PreviousOutputMap(Map.empty) def fromScriptSignatureParams( - inputInfos: Seq[ScriptSignatureParams[InputInfo]]): PreviousOutputMap = { + inputInfos: Seq[ScriptSignatureParams[InputInfo]] + ): PreviousOutputMap = { fromInputInfos(inputInfos.map(_.inputInfo)) } diff --git a/core/src/main/scala/org/bitcoins/core/serializers/PicklerKeys.scala b/core/src/main/scala/org/bitcoins/core/serializers/PicklerKeys.scala index ab6366bfd2..1354f30ea7 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/PicklerKeys.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/PicklerKeys.scala @@ -17,7 +17,7 @@ object PicklerKeys { final val addressKey = "address" final val memoKey = "memo" - //chain + // chain final val rawKey: String = "raw" final val hashKey: String = "hash" final val confirmationsKey: String = "confirmations" @@ -56,17 +56,17 @@ object PicklerKeys { final val syncKey: String = "syncing" final val isInitialBlockDownload: String = "isinitialblockdownload" - //tlv points + // tlv points final val pointsKey = "points" final val payoutKey: String = "payout" final val extraPrecisionKey: String = "extraPrecision" final val isEndpointKey: String = "isEndpoint" - //offers + // offers final val protocolVersionKey: String = "protocolVersion" final val tempContractIdKey: String = "temporaryContractId" - //accepts + // accepts final val fundingPubKeyKey: String = "fundingPubkey" final val acceptCollateralKey: String = "acceptCollateral" final val payoutSpkKey: String = "payoutSpk" @@ -76,7 +76,7 @@ object PicklerKeys { final val changeSerialIdKey: String = "changeSerialId" final val negotiationFieldsKey: String = "negotiationFields" - //contract info + // contract info final val totalCollateralKey = "totalCollateral" final val contractDescriptorKey = "contractDescriptor" final val oracleInfoKey = "oracleInfo" @@ -92,7 +92,7 @@ object PicklerKeys { val numericOutcomeContractDescriptorKey = "numericOutcomeContractDescriptor" val payoutsKey = "payouts" - //numeric contract descriptor + // numeric contract descriptor val numDigitsKey = "numDigits" val payFunctionKey = "payoutFunction" val payoutFunctionPiecesKey = "payoutFunctionPieces" @@ -165,7 +165,7 @@ object PicklerKeys { val witnessKey = "witness" val serializedKey = "serialized" - //ws types + // ws types final val typeKey: String = "type" final val payloadKey: String = "payload" diff --git a/core/src/main/scala/org/bitcoins/core/serializers/RawBitcoinSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/RawBitcoinSerializer.scala index a23a2163dc..75509f88de 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/RawBitcoinSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/RawBitcoinSerializer.scala @@ -3,17 +3,20 @@ package org.bitcoins.core.serializers import org.bitcoins.core.util.BytesUtil import scodec.bits.ByteVector -/** Created by chris on 1/11/16. - * A common trait for reading/writing bitcoin objects to/from bytes/hex +/** Created by chris on 1/11/16. A common trait for reading/writing bitcoin + * objects to/from bytes/hex */ abstract class RawBitcoinSerializer[T] { - /** Reads a hexadecimal value and transforms it into the native scala type T. */ + /** Reads a hexadecimal value and transforms it into the native scala type T. + */ def read(hex: String): T = read(BytesUtil.decodeHex(hex)) /** Reads in bytes and transforms it into the appropriate scala type T. */ def read(bytes: ByteVector): T - /** Takes a type T and writes it into the appropriate hexadecimal serialization for type T. */ + /** Takes a type T and writes it into the appropriate hexadecimal + * serialization for type T. + */ def write(t: T): ByteVector } diff --git a/core/src/main/scala/org/bitcoins/core/serializers/RawBitcoinSerializerHelper.scala b/core/src/main/scala/org/bitcoins/core/serializers/RawBitcoinSerializerHelper.scala index 49a8435fe0..2d90b46f06 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/RawBitcoinSerializerHelper.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/RawBitcoinSerializerHelper.scala @@ -11,12 +11,14 @@ import scala.annotation.tailrec */ sealed abstract class RawSerializerHelper { - /** Used parse a byte sequence to a Seq[TransactionInput], Seq[TransactionOutput], etc - * Makes sure that we parse the correct amount of elements + /** Used parse a byte sequence to a Seq[TransactionInput], + * Seq[TransactionOutput], etc Makes sure that we parse the correct amount of + * elements */ final def parseCmpctSizeUIntSeq[T <: NetworkElement]( bytes: ByteVector, - constructor: ByteVector => T): (Seq[T], ByteVector) = { + constructor: ByteVector => T + ): (Seq[T], ByteVector) = { val count = CompactSizeUInt.parse(bytes) val (_, payload) = bytes.splitAt(count.byteSize.toInt) var counter = 0 @@ -40,22 +42,29 @@ sealed abstract class RawSerializerHelper { val result = b.result() require( result.size == count.num.toInt, - s"Could not parse the amount of required elements, got: ${result.size} required: ${count}") + s"Could not parse the amount of required elements, got: ${result.size} required: ${count}" + ) (result, remaining) } - /** Writes a Seq[TransactionInput]/Seq[TransactionOutput]/Seq[Transaction] -> ByteVector */ + /** Writes a Seq[TransactionInput]/Seq[TransactionOutput]/Seq[Transaction] -> + * ByteVector + */ final def writeCmpctSizeUInt[T]( ts: Seq[T], - serializer: T => ByteVector): ByteVector = { + serializer: T => ByteVector + ): ByteVector = { val serialized = write(ts, serializer) val cmpct = CompactSizeUInt(UInt64(ts.size)) cmpct.bytes ++ serialized } - /** Serializes a [[scala.Seq Seq]] of [[NetworkElement]] to a [[scodec.bits.ByteVector]] */ + /** Serializes a [[scala.Seq Seq]] of [[NetworkElement]] to a + * [[scodec.bits.ByteVector]] + */ final def writeNetworkElements[T <: NetworkElement]( - ts: Seq[T]): ByteVector = { + ts: Seq[T] + ): ByteVector = { val f = { t: T => t.bytes } diff --git a/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawBlockHeaderSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawBlockHeaderSerializer.scala index 79a7acd08b..04936dbfa7 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawBlockHeaderSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawBlockHeaderSerializer.scala @@ -6,8 +6,7 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.crypto.DoubleSha256Digest import scodec.bits.ByteVector -/** Created by chris on 5/19/16. - * Serializes block headers +/** Created by chris on 5/19/16. Serializes block headers * https://bitcoin.org/en/developer-reference#block-headers */ sealed abstract class RawBlockHeaderSerializer @@ -15,22 +14,23 @@ sealed abstract class RawBlockHeaderSerializer /** Converts a list of bytes into a block header */ def read(bytes: ByteVector): BlockHeader = { - //version first 4 bytes + // version first 4 bytes val version = Int32(bytes.take(4).reverse) - //previous header hash next 32 bytes + // previous header hash next 32 bytes val prevBlockHashBytes = bytes.slice(4, 36) val prevBlockHash: DoubleSha256Digest = DoubleSha256Digest( - prevBlockHashBytes) - //merkle hash next 32 bytes + prevBlockHashBytes + ) + // merkle hash next 32 bytes val merkleRootBytes = bytes.slice(36, 68) val merkleRoot: DoubleSha256Digest = DoubleSha256Digest(merkleRootBytes) - //time 4 bytes + // time 4 bytes val timeBytes = bytes.slice(68, 72) val time = UInt32(timeBytes.reverse) - //nbits 4 bytes + // nbits 4 bytes val nBitsBytes = bytes.slice(72, 76) val nBits = UInt32(nBitsBytes.reverse) - //nonce 4 bytes + // nonce 4 bytes val nonceBytes = bytes.slice(76, 80) val nonce = UInt32(nonceBytes.reverse) BlockHeader(version, prevBlockHash, merkleRoot, time, nBits, nonce) diff --git a/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawBlockSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawBlockSerializer.scala index d50b815d37..f9cd8abcb6 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawBlockSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawBlockSerializer.scala @@ -5,9 +5,8 @@ import org.bitcoins.core.protocol.transaction.Transaction import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper} import scodec.bits.ByteVector -/** Created by chris on 5/20/16. - * Responsible for serializing blocks in our blockchain - * https://bitcoin.org/en/developer-reference#serialized-blocks +/** Created by chris on 5/20/16. Responsible for serializing blocks in our + * blockchain https://bitcoin.org/en/developer-reference#serialized-blocks */ sealed abstract class RawBlockSerializer extends RawBitcoinSerializer[Block] { @@ -23,10 +22,12 @@ sealed abstract class RawBlockSerializer extends RawBitcoinSerializer[Block] { /** Takes in a block and converts it to a byte array */ def write(block: Block): ByteVector = { val writtenHeader = block.blockHeader.bytes - val txBytes = RawSerializerHelper.writeCmpctSizeUInt(block.transactions, - { tx: Transaction => - tx.bytes - }) + val txBytes = RawSerializerHelper.writeCmpctSizeUInt( + block.transactions, + { tx: Transaction => + tx.bytes + } + ) writtenHeader ++ txBytes } diff --git a/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawMerkleBlockSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawMerkleBlockSerializer.scala index 4204bdb88c..5a3724799c 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawMerkleBlockSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/blockchain/RawMerkleBlockSerializer.scala @@ -54,7 +54,8 @@ sealed abstract class RawMerkleBlockSerializer .foldLeft(ByteVector.empty)(_ ++ _.bytes) } val flagCount = CompactSizeUInt( - UInt64(Math.ceil(partialMerkleTree.bits.size.toDouble / 8).toInt)) + UInt64(Math.ceil(partialMerkleTree.bits.size.toDouble / 8).toInt) + ) val hashes: ByteVector = BytesUtil.toByteVector(merkleBlock.hashes) merkleBlock.blockHeader.bytes ++ merkleBlock.transactionCount.bytes.reverse ++ @@ -62,27 +63,34 @@ sealed abstract class RawMerkleBlockSerializer hashes ++ flagCount.bytes ++ byteVectors } - /** Parses a sequence of transactions hashes from inside of a merkle block message - * @param bytes the bytes from which the tx hashes are parsed from - * @param hashCount the amount of tx hashes we need to parse from bytes - * @return the sequence of tx hashes and the remaining bytes to be parsed into a MerkleBlockMessage + /** Parses a sequence of transactions hashes from inside of a merkle block + * message + * @param bytes + * the bytes from which the tx hashes are parsed from + * @param hashCount + * the amount of tx hashes we need to parse from bytes + * @return + * the sequence of tx hashes and the remaining bytes to be parsed into a + * MerkleBlockMessage */ private def parseTransactionHashes( bytes: ByteVector, - hashCount: CompactSizeUInt): (Seq[DoubleSha256Digest], ByteVector) = { + hashCount: CompactSizeUInt + ): (Seq[DoubleSha256Digest], ByteVector) = { @tailrec def loop( remainingHashes: Long, remainingBytes: ByteVector, - accum: List[DoubleSha256Digest]): ( - Seq[DoubleSha256Digest], - ByteVector) = { + accum: List[DoubleSha256Digest] + ): (Seq[DoubleSha256Digest], ByteVector) = { if (remainingHashes <= 0) (accum.reverse, remainingBytes) else { val (hashBytes, newRemainingBytes) = remainingBytes.splitAt(32) - loop(remainingHashes - 1, - newRemainingBytes, - DoubleSha256Digest(hashBytes) :: accum) + loop( + remainingHashes - 1, + newRemainingBytes, + DoubleSha256Digest(hashBytes) :: accum + ) } } loop(hashCount.num.toInt, bytes, Nil) diff --git a/core/src/main/scala/org/bitcoins/core/serializers/bloom/RawBloomFilterSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/bloom/RawBloomFilterSerializer.scala index 901ce15d3e..d3f9b9b313 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/bloom/RawBloomFilterSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/bloom/RawBloomFilterSerializer.scala @@ -14,11 +14,14 @@ sealed abstract class RawBloomFilterSerializer override def read(bytes: ByteVector): BloomFilter = { val filterSize = CompactSizeUInt.parseCompactSizeUInt(bytes) - val filter = bytes.slice(filterSize.byteSize.toInt, - filterSize.byteSize.toInt + filterSize.num.toInt) + val filter = bytes.slice( + filterSize.byteSize.toInt, + filterSize.byteSize.toInt + filterSize.num.toInt + ) val hashFuncsIndex = (filterSize.byteSize + filterSize.num.toInt).toInt val hashFuncs = UInt32( - bytes.slice(hashFuncsIndex, hashFuncsIndex + 4).reverse) + bytes.slice(hashFuncsIndex, hashFuncsIndex + 4).reverse + ) val tweakIndex = hashFuncsIndex + 4 val tweak = UInt32(bytes.slice(tweakIndex, tweakIndex + 4).reverse) val flags = BloomFlag(bytes(tweakIndex + 4)) diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/RawNetworkIpAddressSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/RawNetworkIpAddressSerializer.scala index a7f577cf82..31264352dc 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/RawNetworkIpAddressSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/RawNetworkIpAddressSerializer.scala @@ -5,8 +5,10 @@ import org.bitcoins.core.p2p._ import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector -/** Responsible for serializing and deserializing network ip address objects on the p2p network - * @see https://bitcoin.org/en/developer-reference#addr +/** Responsible for serializing and deserializing network ip address objects on + * the p2p network + * @see + * https://bitcoin.org/en/developer-reference#addr */ trait RawNetworkIpAddressSerializer extends RawBitcoinSerializer[NetworkIpAddress] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/RawNetworkMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/RawNetworkMessageSerializer.scala index 952a0bf116..972546be9e 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/RawNetworkMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/RawNetworkMessageSerializer.scala @@ -7,12 +7,13 @@ import scodec.bits.ByteVector trait RawNetworkMessageSerializer extends RawBitcoinSerializer[NetworkMessage] { def read(bytes: ByteVector): NetworkMessage = { - //first 24 bytes are the header + // first 24 bytes are the header val (headerBytes, payloadBytes) = bytes.splitAt(24) val header = NetworkHeader.fromBytes(headerBytes) if (header.payloadSize.toInt > payloadBytes.length) { throw new RuntimeException( - s"We do not have enough bytes for payload! Expected=${header.payloadSize.toInt} got=${payloadBytes.length}") + s"We do not have enough bytes for payload! Expected=${header.payloadSize.toInt} got=${payloadBytes.length}" + ) } else { val payload = NetworkPayload(header, payloadBytes) val n = NetworkMessage(header, payload) diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/headers/RawNetworkHeaderSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/headers/RawNetworkHeaderSerializer.scala index e64fad8eb1..9f8477b50f 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/headers/RawNetworkHeaderSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/headers/RawNetworkHeaderSerializer.scala @@ -7,20 +7,24 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector /** Reads and writes a message header on the peer-to-peer network - * @see https://bitcoin.org/en/developer-reference#message-headers + * @see + * https://bitcoin.org/en/developer-reference#message-headers */ trait RawNetworkHeaderSerializer extends RawBitcoinSerializer[NetworkHeader] { /** Transforms a sequence of bytes into a message header - * @param bytes the byte representation for a MessageHeader on the peer-to-peer network - * @return the native object for the MessageHeader + * @param bytes + * the byte representation for a MessageHeader on the peer-to-peer network + * @return + * the native object for the MessageHeader */ def read(bytes: ByteVector): NetworkHeader = { require( bytes.length == 24, - s"Got bytes.length=${bytes.length} when NetworkHeader expects 24 bytes") + s"Got bytes.length=${bytes.length} when NetworkHeader expects 24 bytes" + ) val network = Networks.magicToNetwork(bytes.take(4)) - //.trim removes the null characters appended to the command name + // .trim removes the null characters appended to the command name val commandName = bytes.slice(4, 16).toArray.map(_.toChar).mkString.trim val payloadSize = UInt32(bytes.slice(16, 20).reverse) val checksum = bytes.slice(20, 24) @@ -28,13 +32,15 @@ trait RawNetworkHeaderSerializer extends RawBitcoinSerializer[NetworkHeader] { } /** Takes in a message header and serializes it to hex - * @param messageHeader the message header to be serialized - * @return the hexadecimal representation of the message header + * @param messageHeader + * the message header to be serialized + * @return + * the hexadecimal representation of the message header */ def write(messageHeader: NetworkHeader): ByteVector = { val network = messageHeader.network val commandNameNoPadding = messageHeader.commandName.map(_.toByte) - //command name needs to be 12 bytes in size, or 24 chars in hex + // command name needs to be 12 bytes in size, or 24 chars in hex val commandName = ByteVector(commandNameNoPadding).padRight(12) val checksum = messageHeader.checksum network.magicBytes ++ diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrMessageSerializer.scala index f0f756e614..d025829df2 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawAddrMessageSerializer.scala @@ -9,7 +9,8 @@ import scodec.bits.ByteVector import scala.annotation.tailrec /** Responsible for the serialization and deserialization of AddrMessages - * @see https://bitcoin.org/en/developer-reference#addr + * @see + * https://bitcoin.org/en/developer-reference#addr */ trait RawAddrMessageSerializer extends RawBitcoinSerializer[AddrMessage] { @@ -23,33 +24,41 @@ trait RawAddrMessageSerializer extends RawBitcoinSerializer[AddrMessage] { override def write(addrMessage: AddrMessage): ByteVector = { addrMessage.ipCount.bytes ++ - RawSerializerHelper.write(ts = addrMessage.addresses, - serializer = - RawNetworkIpAddressSerializer.write) + RawSerializerHelper.write( + ts = addrMessage.addresses, + serializer = RawNetworkIpAddressSerializer.write + ) } /** Parses ip addresses inside of an AddrMessage - * @param ipCount the number of ip addresses we need to parse from the AddrMessage - * @param bytes the bytes from which we need to parse the ip addresses - * @return the parsed ip addresses and the remaining bytes + * @param ipCount + * the number of ip addresses we need to parse from the AddrMessage + * @param bytes + * the bytes from which we need to parse the ip addresses + * @return + * the parsed ip addresses and the remaining bytes */ private def parseNetworkIpAddresses( ipCount: CompactSizeUInt, - bytes: ByteVector): (Seq[NetworkIpAddress], ByteVector) = { + bytes: ByteVector + ): (Seq[NetworkIpAddress], ByteVector) = { @tailrec def loop( remainingAddresses: BigInt, remainingBytes: ByteVector, - accum: List[NetworkIpAddress]): (Seq[NetworkIpAddress], ByteVector) = { + accum: List[NetworkIpAddress] + ): (Seq[NetworkIpAddress], ByteVector) = { if (remainingAddresses <= 0) (accum.reverse, remainingBytes) else { val networkIpAddress = RawNetworkIpAddressSerializer.read(remainingBytes) val newRemainingBytes = remainingBytes.slice(networkIpAddress.byteSize, remainingBytes.size) - loop(remainingAddresses - 1, - newRemainingBytes, - networkIpAddress :: accum) + loop( + remainingAddresses - 1, + newRemainingBytes, + networkIpAddress :: accum + ) } } loop(ipCount.num.toInt, bytes, List()) diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterCheckpointMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterCheckpointMessageSerializer.scala index ae427260a3..105b0449f2 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterCheckpointMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterCheckpointMessageSerializer.scala @@ -7,7 +7,8 @@ import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper} import org.bitcoins.crypto.DoubleSha256Digest import scodec.bits.ByteVector -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfcheckpt BIP-157 ]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfcheckpt BIP-157]] */ object RawCompactFilterCheckpointMessageSerializer extends RawBitcoinSerializer[CompactFilterCheckPointMessage] { @@ -25,7 +26,8 @@ object RawCompactFilterCheckpointMessageSerializer afterStopHash, { bytes => DoubleSha256Digest.fromBytes(bytes.take(32)) - }) + } + ) require( headers.length == filterHeadersLength.toInt, @@ -39,10 +41,12 @@ object RawCompactFilterCheckpointMessageSerializer val filterType = message.filterType.bytes val stopHash = message.stopHash.bytes val filterHeaders = - RawSerializerHelper.writeCmpctSizeUInt(message.filterHeaders, - { fh: DoubleSha256Digest => - fh.bytes - }) + RawSerializerHelper.writeCmpctSizeUInt( + message.filterHeaders, + { fh: DoubleSha256Digest => + fh.bytes + } + ) filterType ++ stopHash ++ filterHeaders } } diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterHeadersMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterHeadersMessageSerializer.scala index 65df7d89c8..a4374aa0ac 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterHeadersMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterHeadersMessageSerializer.scala @@ -6,7 +6,8 @@ import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper} import org.bitcoins.crypto.DoubleSha256Digest import scodec.bits.ByteVector -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfheaders BIP157]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfheaders BIP157]] */ object RawCompactFilterHeadersMessageSerializer extends RawBitcoinSerializer[CompactFilterHeadersMessage] { @@ -27,12 +28,15 @@ object RawCompactFilterHeadersMessageSerializer afterPreviousFilterHeader, { bytes => DoubleSha256Digest.fromBytes(bytes.take(32)) - }) + } + ) - val message = CompactFilterHeadersMessage(filterType, - stopHash, - previousFilterHeaderHash, - hashes.toVector) + val message = CompactFilterHeadersMessage( + filterType, + stopHash, + previousFilterHeaderHash, + hashes.toVector + ) message } @@ -42,10 +46,12 @@ object RawCompactFilterHeadersMessageSerializer val stopHash = message.stopHash.bytes val previousFilterHeader = message.previousFilterHeader.bytes val filterHashes = - RawSerializerHelper.writeCmpctSizeUInt(message.filterHashes, - { fh: DoubleSha256Digest => - fh.bytes - }) + RawSerializerHelper.writeCmpctSizeUInt( + message.filterHashes, + { fh: DoubleSha256Digest => + fh.bytes + } + ) filterType ++ stopHash ++ previousFilterHeader ++ filterHashes } diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterMessageSerializer.scala index 025c7e0ee2..0119eb2bfa 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawCompactFilterMessageSerializer.scala @@ -8,7 +8,8 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.crypto.DoubleSha256Digest import scodec.bits.ByteVector -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfilter BIP157]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#cfilter BIP157]] */ object RawCompactFilterMessageSerializer extends RawBitcoinSerializer[CompactFilterMessage] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterAddMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterAddMessageSerializer.scala index bc92a96279..59cc0a0903 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterAddMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterAddMessageSerializer.scala @@ -5,8 +5,10 @@ import org.bitcoins.core.protocol.CompactSizeUInt import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector -/** Responsible for serializing and deserializing a [[org.bitcoins.core.p2p.FilterAddMessage FilterAddMessage]] - * @see [[https://bitcoin.org/en/developer-reference#filteradd]] +/** Responsible for serializing and deserializing a + * [[org.bitcoins.core.p2p.FilterAddMessage FilterAddMessage]] + * @see + * [[https://bitcoin.org/en/developer-reference#filteradd]] */ trait RawFilterAddMessageSerializer extends RawBitcoinSerializer[FilterAddMessage] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterLoadMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterLoadMessageSerializer.scala index 62676c29c7..b3e2dc8a61 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterLoadMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawFilterLoadMessageSerializer.scala @@ -5,8 +5,10 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.core.serializers.bloom.RawBloomFilterSerializer import scodec.bits.ByteVector -/** Serializes and deserializes a [[org.bitcoins.core.p2p.FilterLoadMessage FilterLoadMessage]] - * @see [[https://bitcoin.org/en/developer-reference#filterload]] +/** Serializes and deserializes a + * [[org.bitcoins.core.p2p.FilterLoadMessage FilterLoadMessage]] + * @see + * [[https://bitcoin.org/en/developer-reference#filterload]] */ trait RawFilterLoadMessageSerializer extends RawBitcoinSerializer[FilterLoadMessage] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetBlocksMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetBlocksMessageSerializer.scala index 35c2004f9e..1c0629f725 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetBlocksMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetBlocksMessageSerializer.scala @@ -10,7 +10,8 @@ import scala.annotation.tailrec /** This trait is responsible for the serialization and deserialization of * getblocks messages in on the p2p network - * @see https://bitcoin.org/en/developer-reference#getblocks + * @see + * https://bitcoin.org/en/developer-reference#getblocks */ trait RawGetBlocksMessageSerializer extends RawBitcoinSerializer[GetBlocksMessage] { @@ -31,33 +32,40 @@ trait RawGetBlocksMessageSerializer getBlocksMessage.protocolVersion.bytes ++ getBlocksMessage.hashCount.bytes ++ RawSerializerHelper.writeNetworkElements( - getBlocksMessage.blockHeaderHashes) ++ + getBlocksMessage.blockHeaderHashes + ) ++ getBlocksMessage.stopHash.bytes } - /** Helper function to parse block headers from a sequence of bytes - * Hashes are 32 bytes - * @param bytes the bytes which need to be parsed into BlockHeader hashes - * @param compactSizeUInt the p2p network object used to indicate how many block header hashes there are - * @return the sequence of hashes and the remaining bytes that need to be parsed + /** Helper function to parse block headers from a sequence of bytes Hashes are + * 32 bytes + * @param bytes + * the bytes which need to be parsed into BlockHeader hashes + * @param compactSizeUInt + * the p2p network object used to indicate how many block header hashes + * there are + * @return + * the sequence of hashes and the remaining bytes that need to be parsed */ private def parseBlockHeaders( bytes: ByteVector, - compactSizeUInt: CompactSizeUInt): ( - List[DoubleSha256Digest], - ByteVector) = { + compactSizeUInt: CompactSizeUInt + ): (List[DoubleSha256Digest], ByteVector) = { @tailrec def loop( remainingHeaders: Long, accum: List[DoubleSha256Digest], - remainingBytes: ByteVector): (List[DoubleSha256Digest], ByteVector) = { + remainingBytes: ByteVector + ): (List[DoubleSha256Digest], ByteVector) = { if (remainingHeaders <= 0) (accum.reverse, remainingBytes) else { val dsha256 = DoubleSha256Digest(remainingBytes.slice(0, 32)) val rem = remainingBytes.slice(32, remainingBytes.size) - loop(remainingHeaders = remainingHeaders - 1, - accum = dsha256 :: accum, - remainingBytes = rem) + loop( + remainingHeaders = remainingHeaders - 1, + accum = dsha256 :: accum, + remainingBytes = rem + ) } } loop(compactSizeUInt.num.toInt, List.empty, bytes) diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterCheckpointMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterCheckpointMessageSerializer.scala index e86b2f34f4..5f239e216d 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterCheckpointMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterCheckpointMessageSerializer.scala @@ -6,7 +6,8 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.crypto.DoubleSha256Digest import scodec.bits.ByteVector -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfcheckpt BIP157]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfcheckpt BIP157]] */ object RawGetCompactFilterCheckpointMessageSerializer extends RawBitcoinSerializer[GetCompactFilterCheckPointMessage] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterHeadersMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterHeadersMessageSerializer.scala index 0eb5ab5adf..9e5bf43b19 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterHeadersMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFilterHeadersMessageSerializer.scala @@ -7,7 +7,8 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.crypto.DoubleSha256Digest import scodec.bits.ByteVector -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfheaders BIP157]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfheaders BIP157]] */ object RawGetCompactFilterHeadersMessageSerializer extends RawBitcoinSerializer[GetCompactFilterHeadersMessage] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFiltersMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFiltersMessageSerializer.scala index 3f2dd96baa..25710c9066 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFiltersMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetCompactFiltersMessageSerializer.scala @@ -7,7 +7,8 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.crypto.DoubleSha256Digest import scodec.bits.ByteVector -/** @see [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfilters BIP157]] +/** @see + * [[https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#getcfilters BIP157]] */ object RawGetCompactFiltersMessageSerializer extends RawBitcoinSerializer[GetCompactFiltersMessage] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetDataMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetDataMessageSerializer.scala index b1327f2e9d..4675edfdf3 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetDataMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetDataMessageSerializer.scala @@ -4,11 +4,12 @@ import org.bitcoins.core.p2p.{GetDataMessage, InventoryMessage} import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector -/** @see https://bitcoin.org/en/developer-reference#getdata +/** @see + * https://bitcoin.org/en/developer-reference#getdata */ trait RawGetDataMessageSerializer extends RawBitcoinSerializer[GetDataMessage] { - //InventoryMessages & GetDataMessages have the same structure and are serialized the same - //so we can piggy back off of the serialilzers for InventoryMessages + // InventoryMessages & GetDataMessages have the same structure and are serialized the same + // so we can piggy back off of the serialilzers for InventoryMessages def read(bytes: ByteVector): GetDataMessage = { val inv = InventoryMessage(bytes) @@ -16,8 +17,10 @@ trait RawGetDataMessageSerializer extends RawBitcoinSerializer[GetDataMessage] { } def write(getDataMessage: GetDataMessage): ByteVector = { - val inv = InventoryMessage(getDataMessage.inventoryCount, - getDataMessage.inventories) + val inv = InventoryMessage( + getDataMessage.inventoryCount, + getDataMessage.inventories + ) inv.bytes } } diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetHeadersMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetHeadersMessageSerializer.scala index 1a70e84f79..f1670a9794 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetHeadersMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawGetHeadersMessageSerializer.scala @@ -31,20 +31,23 @@ trait RawGetHeadersMessageSerializer /** Parses hashes inside of [[GetHeadersMessage]] * - * @param bytes the bytes which the hashes are parsed from - * @param numHashes the number of hases that need to be parsed - * @return the parsed hases and the remaining bytes in the network message + * @param bytes + * the bytes which the hashes are parsed from + * @param numHashes + * the number of hases that need to be parsed + * @return + * the parsed hases and the remaining bytes in the network message */ private def parseHashes( bytes: ByteVector, - numHashes: CompactSizeUInt): (List[DoubleSha256Digest], ByteVector) = { + numHashes: CompactSizeUInt + ): (List[DoubleSha256Digest], ByteVector) = { @tailrec def loop( remainingBytes: ByteVector, remainingHashes: Long, - accum: List[DoubleSha256Digest]): ( - List[DoubleSha256Digest], - ByteVector) = { + accum: List[DoubleSha256Digest] + ): (List[DoubleSha256Digest], ByteVector) = { if (remainingHashes <= 0) (accum, remainingBytes) else { val hash = DoubleSha256Digest(remainingBytes.take(32)) diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawHeadersMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawHeadersMessageSerializer.scala index b3b3696475..e0288a904d 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawHeadersMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawHeadersMessageSerializer.scala @@ -29,22 +29,27 @@ trait RawHeadersMessageSerializer extends RawBitcoinSerializer[HeadersMessage] { private def parseBlockHeaders( bytes: ByteVector, - compactSizeUInt: CompactSizeUInt): Vector[BlockHeader] = { + compactSizeUInt: CompactSizeUInt + ): Vector[BlockHeader] = { @tailrec def loop( remainingBytes: ByteVector, remainingHeaders: Long, - accum: List[BlockHeader]): List[BlockHeader] = { + accum: List[BlockHeader] + ): List[BlockHeader] = { if (remainingHeaders <= 0) accum - //81 is because HeadersMessage appends 0x00 at the end of every block header for some reason - //read https://bitcoin.org/en/developer-reference#headers + // 81 is because HeadersMessage appends 0x00 at the end of every block header for some reason + // read https://bitcoin.org/en/developer-reference#headers else { require( remainingBytes.size >= 80, - "We do not have enough bytes for another block header, this probably means a tcp frame was not aligned") - loop(remainingBytes = remainingBytes.slice(81, remainingBytes.length), - remainingHeaders = remainingHeaders - 1, - accum = BlockHeader(remainingBytes.take(80)) :: accum) + "We do not have enough bytes for another block header, this probably means a tcp frame was not aligned" + ) + loop( + remainingBytes = remainingBytes.slice(81, remainingBytes.length), + remainingHeaders = remainingHeaders - 1, + accum = BlockHeader(remainingBytes.take(80)) :: accum + ) } } loop(bytes, compactSizeUInt.num.toInt, List.empty).reverse.toVector diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawInventoryMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawInventoryMessageSerializer.scala index f7a17dee93..7fb8e0cf7a 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawInventoryMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawInventoryMessageSerializer.scala @@ -8,7 +8,8 @@ import scodec.bits.ByteVector import scala.annotation.tailrec /** Serializes and deserializes inventory objects on the peer-to-peer network - * @see https://bitcoin.org/en/developer-reference#inv + * @see + * https://bitcoin.org/en/developer-reference#inv */ trait RawInventoryMessageSerializer extends RawBitcoinSerializer[InventoryMessage] { @@ -31,25 +32,33 @@ trait RawInventoryMessageSerializer inventoryMessage.inventoryCount.bytes ++ msgBytes } - /** Parses the sequence of bytes into a sequence of inventories inside of the inventory message - * @param bytes the bytes that need to be parsed into Inventories - * @param requiredInventories the num of inventories inside this sequence of bytes - * @return the sequence of inventories and the remaining bytes + /** Parses the sequence of bytes into a sequence of inventories inside of the + * inventory message + * @param bytes + * the bytes that need to be parsed into Inventories + * @param requiredInventories + * the num of inventories inside this sequence of bytes + * @return + * the sequence of inventories and the remaining bytes */ private def parseInventories( bytes: ByteVector, - requiredInventories: CompactSizeUInt): (List[Inventory], ByteVector) = { + requiredInventories: CompactSizeUInt + ): (List[Inventory], ByteVector) = { @tailrec def loop( remainingInventories: Long, remainingBytes: ByteVector, - accum: List[Inventory]): (List[Inventory], ByteVector) = { + accum: List[Inventory] + ): (List[Inventory], ByteVector) = { if (remainingInventories <= 0) (accum.reverse, remainingBytes) else { val inventory = RawInventorySerializer.read(remainingBytes.slice(0, 36)) - loop(remainingInventories - 1, - remainingBytes.slice(36, remainingBytes.size), - inventory :: accum) + loop( + remainingInventories - 1, + remainingBytes.slice(36, remainingBytes.size), + inventory :: accum + ) } } loop(requiredInventories.num.toInt, bytes, List.empty) diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawInventorySerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawInventorySerializer.scala index 05c0f9b641..b8a08593fa 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawInventorySerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawInventorySerializer.scala @@ -6,7 +6,8 @@ import org.bitcoins.crypto.DoubleSha256Digest import scodec.bits.ByteVector /** Serializes/deserializes a inventory - * @see https://bitcoin.org/en/developer-reference#term-inventory + * @see + * https://bitcoin.org/en/developer-reference#term-inventory */ trait RawInventorySerializer extends RawBitcoinSerializer[Inventory] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawMerkleBlockMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawMerkleBlockMessageSerializer.scala index c07698f403..82bd76c555 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawMerkleBlockMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawMerkleBlockMessageSerializer.scala @@ -6,7 +6,8 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector /** Responsible for serialization and deserialization of MerkleBlockMessages - * @see https://bitcoin.org/en/developer-reference#merkleblock + * @see + * https://bitcoin.org/en/developer-reference#merkleblock */ trait RawMerkleBlockMessageSerializer extends RawBitcoinSerializer[MerkleBlockMessage] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawNotFoundMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawNotFoundMessageSerializer.scala index 1af39207bb..847ebb3f7b 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawNotFoundMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawNotFoundMessageSerializer.scala @@ -4,28 +4,34 @@ import org.bitcoins.core.p2p.{InventoryMessage, NotFoundMessage} import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector -/** Responsible for the serialization and deserialization of a NotFound message on the p2p network - * @see https://bitcoin.org/en/developer-reference#notfound +/** Responsible for the serialization and deserialization of a NotFound message + * on the p2p network + * @see + * https://bitcoin.org/en/developer-reference#notfound */ trait RawNotFoundMessageSerializer extends RawBitcoinSerializer[NotFoundMessage] { override def read(bytes: ByteVector): NotFoundMessage = { - //this seems funky, but according to the documentation inventory messages - //and NotFoundMessages have the same structure, therefore we can piggy back - //off of the serializer used by InventoryMessage + // this seems funky, but according to the documentation inventory messages + // and NotFoundMessages have the same structure, therefore we can piggy back + // off of the serializer used by InventoryMessage val inventoryMessage = InventoryMessage(bytes) - NotFoundMessage(inventoryMessage.inventoryCount, - inventoryMessage.inventories) + NotFoundMessage( + inventoryMessage.inventoryCount, + inventoryMessage.inventories + ) } override def write(notFoundMessage: NotFoundMessage): ByteVector = { - //Since InventoryMessages and NotFoundMessages have the same format - //we can just create an inventory message then piggy back off of the - //serializer used by inventory message - val inventoryMessage = InventoryMessage(notFoundMessage.inventoryCount, - notFoundMessage.inventories) + // Since InventoryMessages and NotFoundMessages have the same format + // we can just create an inventory message then piggy back off of the + // serializer used by inventory message + val inventoryMessage = InventoryMessage( + notFoundMessage.inventoryCount, + notFoundMessage.inventories + ) inventoryMessage.bytes } diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawPingMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawPingMessageSerializer.scala index 35916bef9d..f4e338efcb 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawPingMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawPingMessageSerializer.scala @@ -5,7 +5,8 @@ import org.bitcoins.core.p2p.PingMessage import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector -/** @see https://bitcoin.org/en/developer-reference#ping +/** @see + * https://bitcoin.org/en/developer-reference#ping */ trait RawPingMessageSerializer extends RawBitcoinSerializer[PingMessage] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawRejectMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawRejectMessageSerializer.scala index bc95a78dee..2f3674a660 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawRejectMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawRejectMessageSerializer.scala @@ -10,22 +10,27 @@ trait RawRejectMessageSerializer extends RawBitcoinSerializer[RejectMessage] { def read(bytes: ByteVector): RejectMessage = { val messageSize = CompactSizeUInt.parseCompactSizeUInt(bytes) val message: String = bytes - .slice(messageSize.byteSize.toInt, - messageSize.byteSize.toInt + - messageSize.num.toInt) + .slice( + messageSize.byteSize.toInt, + messageSize.byteSize.toInt + + messageSize.num.toInt + ) .toArray .map(_.toChar) .mkString val code: Char = bytes( - messageSize.byteSize.toInt + messageSize.num.toInt).toChar + messageSize.byteSize.toInt + messageSize.num.toInt + ).toChar val reasonSizeStartIndex = messageSize.byteSize.toInt + messageSize.num.toInt + 1 val reasonSize = CompactSizeUInt.parseCompactSizeUInt( - bytes.slice(reasonSizeStartIndex.toInt, bytes.size)) + bytes.slice(reasonSizeStartIndex.toInt, bytes.size) + ) val reason = bytes .slice( (reasonSizeStartIndex + reasonSize.byteSize).toInt, - (reasonSizeStartIndex + reasonSize.byteSize.toInt + reasonSize.num.toInt)) + (reasonSizeStartIndex + reasonSize.byteSize.toInt + reasonSize.num.toInt) + ) .toArray .map(_.toChar) .mkString diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawServiceIdentifierSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawServiceIdentifierSerializer.scala index 3e0e89b524..58e5fd8ac4 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawServiceIdentifierSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawServiceIdentifierSerializer.scala @@ -5,16 +5,17 @@ import org.bitcoins.core.p2p.ServiceIdentifier import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector -/** Responsible for serializing and deserializing the - * service identifier in a network message - * @see https://bitcoin.org/en/developer-reference#version +/** Responsible for serializing and deserializing the service identifier in a + * network message + * @see + * https://bitcoin.org/en/developer-reference#version */ trait RawServiceIdentifierSerializer extends RawBitcoinSerializer[ServiceIdentifier] { override def read(bytes: ByteVector): ServiceIdentifier = { val serviceBytes = bytes.take(8) - //since bitcoin uses big endian for numbers, we need to convert to little endian + // since bitcoin uses big endian for numbers, we need to convert to little endian ServiceIdentifier(UInt64(serviceBytes.reverse)) } diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawTransactionMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawTransactionMessageSerializer.scala index 1f1f2cd724..ca818d01b0 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawTransactionMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawTransactionMessageSerializer.scala @@ -5,8 +5,10 @@ import org.bitcoins.core.protocol.transaction.Transaction import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector -/** Responsible for serializing and deserializing TransactionMessage network objects - * @see https://bitcoin.org/en/developer-reference#tx +/** Responsible for serializing and deserializing TransactionMessage network + * objects + * @see + * https://bitcoin.org/en/developer-reference#tx */ trait RawTransactionMessageSerializer extends RawBitcoinSerializer[TransactionMessage] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawTypeIdentifierSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawTypeIdentifierSerializer.scala index f322678b62..bcc73c1f23 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawTypeIdentifierSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawTypeIdentifierSerializer.scala @@ -5,8 +5,8 @@ import org.bitcoins.core.p2p.TypeIdentifier import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector -/** Created by chris on 5/31/16. - * Reads and writes a type identifier on a peer-to-peer network +/** Created by chris on 5/31/16. Reads and writes a type identifier on a + * peer-to-peer network * https://bitcoin.org/en/developer-reference#data-messages */ trait RawTypeIdentifierSerializer extends RawBitcoinSerializer[TypeIdentifier] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawVersionMessageSerializer.scala b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawVersionMessageSerializer.scala index c0ff333ccb..65182c5029 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawVersionMessageSerializer.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/p2p/messages/RawVersionMessageSerializer.scala @@ -6,8 +6,10 @@ import org.bitcoins.core.protocol.CompactSizeUInt import org.bitcoins.core.serializers.RawBitcoinSerializer import scodec.bits.ByteVector -/** Responsible for serialization and deserialization of VersionMessages on the p2p network - * @see https://bitcoin.org/en/developer-reference#version +/** Responsible for serialization and deserialization of VersionMessages on the + * p2p network + * @see + * https://bitcoin.org/en/developer-reference#version */ trait RawVersionMessageSerializer extends RawBitcoinSerializer[VersionMessage] { @@ -41,7 +43,8 @@ trait RawVersionMessageSerializer extends RawBitcoinSerializer[VersionMessage] { val userAgentBytes = bytes.slice( userAgentBytesStartIndex, - userAgentBytesStartIndex + userAgentSize.num.toInt) + userAgentBytesStartIndex + userAgentSize.num.toInt + ) val userAgent = userAgentBytes.toArray.map(_.toChar).mkString @@ -49,7 +52,8 @@ trait RawVersionMessageSerializer extends RawBitcoinSerializer[VersionMessage] { userAgentBytesStartIndex + userAgentSize.num.toInt val startHeight = Int32( - bytes.slice(startHeightStartIndex, startHeightStartIndex + 4).reverse) + bytes.slice(startHeightStartIndex, startHeightStartIndex + 4).reverse + ) val relay = bytes(startHeightStartIndex + 4) != 0 @@ -76,13 +80,13 @@ trait RawVersionMessageSerializer extends RawBitcoinSerializer[VersionMessage] { versionMessage.timestamp.bytes.reverse ++ versionMessage.addressReceiveServices.bytes ++ NetworkIpAddress.writeAddress(versionMessage.addressReceiveIpAddress) ++ - //encode hex returns 8 characters, but we only need the last 4 since port number is a uint16 - //check for precision loss here? + // encode hex returns 8 characters, but we only need the last 4 since port number is a uint16 + // check for precision loss here? ByteVector.fromShort(versionMessage.addressReceivePort.toShort) ++ versionMessage.addressTransServices.bytes ++ NetworkIpAddress.writeAddress(versionMessage.addressTransIpAddress) ++ - //encode hex returns 8 characters, but we only need the last 4 since port number is a uint16 - //check for precision loss here? + // encode hex returns 8 characters, but we only need the last 4 since port number is a uint16 + // check for precision loss here? ByteVector.fromShort(versionMessage.addressTransPort.toShort) ++ versionMessage.nonce.bytes ++ versionMessage.userAgentSize.bytes ++ diff --git a/core/src/main/scala/org/bitcoins/core/serializers/script/RawScriptWitnessParser.scala b/core/src/main/scala/org/bitcoins/core/serializers/script/RawScriptWitnessParser.scala index 4d7384da40..aae5815d7b 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/script/RawScriptWitnessParser.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/script/RawScriptWitnessParser.scala @@ -14,14 +14,15 @@ sealed abstract class RawScriptWitnessParser extends RawBitcoinSerializer[ScriptWitness] { override def read(bytes: ByteVector): ScriptWitness = { - //first byte is the number of stack items + // first byte is the number of stack items val stackSize = CompactSizeUInt.parseCompactSizeUInt(bytes) val (_, stackBytes) = bytes.splitAt(stackSize.byteSize.toInt) @tailrec def loop( remainingBytes: ByteVector, accum: Seq[ByteVector], - remainingStackItems: UInt64): Seq[ByteVector] = { + remainingStackItems: UInt64 + ): Seq[ByteVector] = { if (remainingStackItems <= UInt64.zero) accum else { val elementSize = CompactSizeUInt.parseCompactSizeUInt(remainingBytes) @@ -30,12 +31,14 @@ sealed abstract class RawScriptWitnessParser val stackElement = stackElementBytes.take(elementSize.num.toInt) val (_, newRemainingBytes) = stackElementBytes.splitAt(stackElement.size) - loop(newRemainingBytes, - stackElement +: accum, - remainingStackItems - UInt64.one) + loop( + newRemainingBytes, + stackElement +: accum, + remainingStackItems - UInt64.one + ) } } - //note there is no 'reversing' the accum, in bitcoin-s we assume the top of the stack is the 'head' element in the sequence + // note there is no 'reversing' the accum, in bitcoin-s we assume the top of the stack is the 'head' element in the sequence val stack = loop(stackBytes, Nil, stackSize.num) val witness = ScriptWitness(stack) witness @@ -45,7 +48,8 @@ sealed abstract class RawScriptWitnessParser @tailrec def loop( remainingStack: Seq[ByteVector], - accum: Vector[ByteVector]): Vector[ByteVector] = { + accum: Vector[ByteVector] + ): Vector[ByteVector] = { if (remainingStack.isEmpty) accum.reverse else { val compactSizeUInt: CompactSizeUInt = diff --git a/core/src/main/scala/org/bitcoins/core/serializers/script/ScriptParser.scala b/core/src/main/scala/org/bitcoins/core/serializers/script/ScriptParser.scala index ffb77111d3..ee61f19fda 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/script/ScriptParser.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/script/ScriptParser.scala @@ -22,9 +22,10 @@ sealed abstract class ScriptParser scriptTokens } - /** Parses an asm output script of a transaction - * example: "OP_DUP OP_HASH160 e2e7c1ab3f807151e832dd1accb3d4f5d7d19b4b OP_EQUALVERIFY OP_CHECKSIG" - * example: ["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok if not executed)"] (from script_valid.json) + /** Parses an asm output script of a transaction example: "OP_DUP OP_HASH160 + * e2e7c1ab3f807151e832dd1accb3d4f5d7d19b4b OP_EQUALVERIFY OP_CHECKSIG" + * example: ["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok + * if not executed)"] (from script_valid.json) */ override def fromString(str: String): Vector[ScriptToken] = { if ( @@ -32,8 +33,8 @@ sealed abstract class ScriptParser .split(" ") .size == 1 ) { - //parse this as a byte array that is led with a 0x for example - //0x4e03000000ffff + // parse this as a byte array that is led with a 0x for example + // 0x4e03000000ffff val hex = str.substring(2, str.size) fromBytes(BytesUtil.decodeHex(hex)) } else { @@ -42,9 +43,10 @@ sealed abstract class ScriptParser } } - /** Parses a string to a sequence of script tokens - * example: "OP_DUP OP_HASH160 e2e7c1ab3f807151e832dd1accb3d4f5d7d19b4b OP_EQUALVERIFY OP_CHECKSIG" - * example: ["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok if not executed)"] (from script_valid.json) + /** Parses a string to a sequence of script tokens example: "OP_DUP OP_HASH160 + * e2e7c1ab3f807151e832dd1accb3d4f5d7d19b4b OP_EQUALVERIFY OP_CHECKSIG" + * example: ["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok + * if not executed)"] (from script_valid.json) */ private def parse(str: String): Vector[ScriptToken] = { @tailrec @@ -52,8 +54,8 @@ sealed abstract class ScriptParser /* logger.debug("Attempting to parse: " + operations.headOption) logger.debug("Accum: " + accum)*/ operations match { - //for parsing strings like 'Az', need to remove single quotes - //example: [[https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json#L24]] + // for parsing strings like 'Az', need to remove single quotes + // example: [[https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json#L24]] case h +: t if h.nonEmpty && h.head == '\'' && h.last == '\'' => val strippedQuotes = h.replace("\'", "") if (strippedQuotes.isEmpty) { @@ -69,7 +71,9 @@ sealed abstract class ScriptParser case true => val scriptNumber = ScriptNumber( BytesUtil.flipEndianness( - ScriptNumberUtil.longToHex(bytes.size))) + ScriptNumberUtil.longToHex(bytes.size) + ) + ) bytes.size match { case size if size < Byte.MaxValue => Vector(scriptNumber, OP_PUSHDATA1) @@ -86,13 +90,15 @@ sealed abstract class ScriptParser val aggregation: ByteVector = bytes ++ pushOpBytes ++ accum loop(t, aggregation) } - //if we see a byte constant in the form of "0x09adb" + // if we see a byte constant in the form of "0x09adb" case h +: t if h.size > 1 && h.substring(0, 2) == "0x" => - loop(t, - BytesUtil - .decodeHex(h.substring(2, h.size).toLowerCase) - .reverse ++ accum) - //skip the empty string + loop( + t, + BytesUtil + .decodeHex(h.substring(2, h.size).toLowerCase) + .reverse ++ accum + ) + // skip the empty string case h +: t if h == "" => loop(t, accum) case h +: t if h == "0" => loop(t, OP_0.bytes ++ accum) @@ -103,54 +109,59 @@ sealed abstract class ScriptParser val hexLong = BytesUtil.flipEndianness(ScriptNumberUtil.longToHex(h.toLong)) val bytesToPushOntoStack = BytesToPushOntoStack(hexLong.size / 2) - //convert the string to int, then convert to hex - loop(t, - BytesUtil - .decodeHex(hexLong) ++ bytesToPushOntoStack.bytes ++ accum) - //means that it must be a BytesToPushOntoStack followed by a script constant + // convert the string to int, then convert to hex + loop( + t, + BytesUtil + .decodeHex(hexLong) ++ bytesToPushOntoStack.bytes ++ accum + ) + // means that it must be a BytesToPushOntoStack followed by a script constant case h +: t => - //find the size of the string in bytes + // find the size of the string in bytes val bytesToPushOntoStack = BytesToPushOntoStack(h.size / 2) - loop(t, - BytesUtil - .decodeHex( - BytesUtil.flipEndianness( - h)) ++ bytesToPushOntoStack.bytes ++ accum) + loop( + t, + BytesUtil + .decodeHex( + BytesUtil.flipEndianness(h) + ) ++ bytesToPushOntoStack.bytes ++ accum + ) case _: Vector[_] => accum } } if (tryParsingLong(str) && str.size > 1 && str.substring(0, 2) != "0x") { - //for the case when there is just a single decimal constant - //i.e. "8388607" + // for the case when there is just a single decimal constant + // i.e. "8388607" val scriptNumber = ScriptNumber(parseLong(str)) val bytesToPushOntoStack = BytesToPushOntoStack(scriptNumber.bytes.size) Vector(bytesToPushOntoStack, scriptNumber) } else if (BytesUtil.isHex(str) && str.toLowerCase == str) { - //if the given string is hex, it is pretty straight forward to parse it - //convert the hex string to a byte array and parse it + // if the given string is hex, it is pretty straight forward to parse it + // convert the hex string to a byte array and parse it val bytes = BytesUtil.decodeHex(str) parse(bytes) } else { - //this handles weird cases for parsing with various formats in bitcoin core. - //take a look at https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/core_read.cpp#L53-L88 - //for the offical parsing algorithm, for examples of weird formats look inside of - //[[https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json]] + // this handles weird cases for parsing with various formats in bitcoin core. + // take a look at https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/core_read.cpp#L53-L88 + // for the offical parsing algorithm, for examples of weird formats look inside of + // [[https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json]] val parsedBytesFromString = loop(str.split(" ").toVector, ByteVector.empty).reverse parse(parsedBytesFromString) } } - /** Parses a byte array into a the asm operations for a script - * will throw an exception if it fails to parse a op code + /** Parses a byte array into a the asm operations for a script will throw an + * exception if it fails to parse a op code */ private def parse(bytes: ByteVector): Vector[ScriptToken] = { @tailrec def loop( bytes: ByteVector, - accum: Vector[ScriptToken]): Vector[ScriptToken] = { - //logger.debug("Byte to be parsed: " + bytes.headOption) + accum: Vector[ScriptToken] + ): Vector[ScriptToken] = { + // logger.debug("Byte to be parsed: " + bytes.headOption) if (bytes.nonEmpty) { val op = ScriptOperation.fromByte(bytes.head) val parsingHelper: ParsingHelper = @@ -170,31 +181,33 @@ sealed abstract class ScriptParser redeemScript } - /** Slices the amount of bytes specified in the bytesToPushOntoStack parameter and then creates a script constant - * from those bytes. Returns the script constant and the byte array without the script constant + /** Slices the amount of bytes specified in the bytesToPushOntoStack parameter + * and then creates a script constant from those bytes. Returns the script + * constant and the byte array without the script constant */ private def sliceConstant( bytesToPushOntoStack: BytesToPushOntoStack, - data: ByteVector): (ByteVector, ByteVector) = { + data: ByteVector + ): (ByteVector, ByteVector) = { val finalIndex = bytesToPushOntoStack.opCode val dataConstant = data.slice(0, finalIndex) (dataConstant, data.slice(finalIndex, data.size)) } /** Parses the bytes in string format, an example input would look like this - * "0x09 0x00000000 0x00000000 0x10" - * see [[https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json#L21-L25]] + * "0x09 0x00000000 0x00000000 0x10" see + * [[https://github.com/bitcoin/bitcoin/blob/master/src/test/data/script_valid.json#L21-L25]] * for examples of this */ def parseBytesFromString(s: String): Vector[ScriptConstant] = { - //logger.debug("Parsing bytes from string " + s) + // logger.debug("Parsing bytes from string " + s) val scriptConstants = raw"\b0x([0-9a-f]+)\b".r .findAllMatchIn(s.toLowerCase) .map(g => // 1 hex = 4 bits therefore 16 hex characters * 4 bits = 64 // if it is not smaller than 16 hex characters it cannot - //fit inside of a scala long - //therefore store it as a script constant + // fit inside of a scala long + // therefore store it as a script constant if (g.group(1).size <= 16) { ScriptNumber(g.group(1)) } else { @@ -205,22 +218,24 @@ sealed abstract class ScriptParser sealed private case class ParsingHelper( tail: ByteVector, - accum: Vector[ScriptToken]) + accum: Vector[ScriptToken] + ) - /** Parses an operation if the tail is a scodec.bits.ByteVector - * If the operation is a bytesToPushOntoStack, it pushes the number of bytes onto the stack - * specified by the bytesToPushOntoStack - * i.e. If the operation was BytesToPushOntoStackImpl(5), it would slice 5 bytes off of the tail and + /** Parses an operation if the tail is a scodec.bits.ByteVector If the + * operation is a bytesToPushOntoStack, it pushes the number of bytes onto + * the stack specified by the bytesToPushOntoStack i.e. If the operation was + * BytesToPushOntoStackImpl(5), it would slice 5 bytes off of the tail and * places them into a ScriptConstant and add them to the accumulator. */ private def parseOperationByte( op: ScriptOperation, accum: Vector[ScriptToken], - tail: ByteVector): ParsingHelper = { + tail: ByteVector + ): ParsingHelper = { op match { case bytesToPushOntoStack: BytesToPushOntoStack => - //logger.debug("Parsing operation byte: " +bytesToPushOntoStack ) - //means that we need to push x amount of bytes on to the stack + // logger.debug("Parsing operation byte: " +bytesToPushOntoStack ) + // means that we need to push x amount of bytes on to the stack val (constant, newTail) = sliceConstant(bytesToPushOntoStack, tail) val scriptConstant = ScriptConstant(constant) ParsingHelper(newTail, scriptConstant +: bytesToPushOntoStack +: accum) @@ -228,29 +243,34 @@ sealed abstract class ScriptParser case OP_PUSHDATA2 => parseOpPushData(op, accum, tail) case OP_PUSHDATA4 => parseOpPushData(op, accum, tail) case _ => - //means that we need to push the operation onto the stack + // means that we need to push the operation onto the stack ParsingHelper(tail, op +: accum) } } - /** Parses OP_PUSHDATA operations correctly. Slices the appropriate amount of bytes off of the tail and pushes - * them onto the accumulator. - * @param op the script operation that is being parsed, this should be OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4 or else it throws an exception - * @param accum the parsed script tokens so far - * @param tail the bytes to be parsed still + /** Parses OP_PUSHDATA operations correctly. Slices the appropriate amount of + * bytes off of the tail and pushes them onto the accumulator. + * @param op + * the script operation that is being parsed, this should be OP_PUSHDATA1, + * OP_PUSHDATA2, OP_PUSHDATA4 or else it throws an exception + * @param accum + * the parsed script tokens so far + * @param tail + * the bytes to be parsed still * @return */ private def parseOpPushData( op: ScriptOperation, accum: Vector[ScriptToken], - tail: ByteVector): ParsingHelper = { + tail: ByteVector + ): ParsingHelper = { def parseOpPushDataHelper(numBytes: Int): ParsingHelper = { - //next numBytes is the size of the script constant + // next numBytes is the size of the script constant val scriptConstantHex = tail.slice(0, numBytes) val uInt32Push = UInt32(BytesUtil.flipEndianness(scriptConstantHex)) - //need this for the case where we have an OP_PUSHDATA4 with a number larger than a int32 can hold - //TODO: Review this more, see this transaction's scriptSig as an example: b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + // need this for the case where we have an OP_PUSHDATA4 with a number larger than a int32 can hold + // TODO: Review this more, see this transaction's scriptSig as an example: b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val bytesForPushOp: Long = Try(uInt32Push.toLong).getOrElse(tail.length) val bytesToPushOntoStack = ScriptConstant(scriptConstantHex) val endIndex = { @@ -260,11 +280,13 @@ sealed abstract class ScriptParser val scriptConstantBytes = tail.slice(numBytes, endIndex) val scriptConstant = ScriptConstant(scriptConstantBytes) val restOfBytes = tail.slice(endIndex, tail.size) - buildParsingHelper(op, - bytesToPushOntoStack, - scriptConstant, - restOfBytes, - accum) + buildParsingHelper( + op, + bytesToPushOntoStack, + scriptConstant, + restOfBytes, + accum + ) } op match { @@ -276,16 +298,25 @@ sealed abstract class ScriptParser parseOpPushDataHelper(4) case _: ScriptToken => throw new RuntimeException( - "parseOpPushData can only parse OP_PUSHDATA operations") + "parseOpPushData can only parse OP_PUSHDATA operations" + ) } } - /** Helper function to build the parsing helper for parsing an OP_PUSHDATA operation - * @param op the OP_PUSHDATA operation being added to the accum - * @param bytesToPushOntoStack the number of bytes that are pushed onto the stack by the OP_PUSHDATA operation - * @param scriptConstant the constant that is being pushed onto the stack by the OP_PUSHDATA operation - * @param restOfBytes the remaining bytes that need to be parsed - * @param accum the accumulator filled with script tokens that have already been parsed + /** Helper function to build the parsing helper for parsing an OP_PUSHDATA + * operation + * @param op + * the OP_PUSHDATA operation being added to the accum + * @param bytesToPushOntoStack + * the number of bytes that are pushed onto the stack by the OP_PUSHDATA + * operation + * @param scriptConstant + * the constant that is being pushed onto the stack by the OP_PUSHDATA + * operation + * @param restOfBytes + * the remaining bytes that need to be parsed + * @param accum + * the accumulator filled with script tokens that have already been parsed * @return */ private def buildParsingHelper( @@ -293,13 +324,16 @@ sealed abstract class ScriptParser bytesToPushOntoStack: ScriptConstant, scriptConstant: ScriptConstant, restOfBytes: ByteVector, - accum: Vector[ScriptToken]): ParsingHelper = { + accum: Vector[ScriptToken] + ): ParsingHelper = { if (bytesToPushOntoStack.hex == "00") { - //if we need to push 0 bytes onto the stack we do not add the script constant + // if we need to push 0 bytes onto the stack we do not add the script constant ParsingHelper(restOfBytes, bytesToPushOntoStack +: op +: accum) } else - ParsingHelper(restOfBytes, - scriptConstant +: bytesToPushOntoStack +: op +: accum) + ParsingHelper( + restOfBytes, + scriptConstant +: bytesToPushOntoStack +: op +: accum + ) } /** Checks if a string can be cast to an int */ diff --git a/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParser.scala b/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParser.scala index 056f8ad442..b9a71fda09 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParser.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionInputParser.scala @@ -10,8 +10,7 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.core.serializers.script.RawScriptSignatureParser import scodec.bits.ByteVector -/** Created by chris on 1/13/16. - * https://bitcoin.org/en/developer-reference#txin +/** Created by chris on 1/13/16. https://bitcoin.org/en/developer-reference#txin */ sealed abstract class RawTransactionInputParser extends RawBitcoinSerializer[TransactionInput] { diff --git a/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutPointParser.scala b/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutPointParser.scala index 66c3eecfd7..57df097ee0 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutPointParser.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutPointParser.scala @@ -9,8 +9,7 @@ import org.bitcoins.core.serializers.RawBitcoinSerializer import org.bitcoins.crypto.DoubleSha256Digest import scodec.bits.ByteVector -/** Source for serialization - * https://bitcoin.org/en/developer-reference#outpoint +/** Source for serialization https://bitcoin.org/en/developer-reference#outpoint */ sealed abstract class RawTransactionOutPointParser extends RawBitcoinSerializer[TransactionOutPoint] { @@ -23,10 +22,10 @@ sealed abstract class RawTransactionOutPointParser } def write(outPoint: TransactionOutPoint): ByteVector = { - //UInt32s cannot hold negative numbers, but sometimes the Bitcoin Protocol requires the vout to be -1, which is serialized - //as "0xFFFFFFFF". - //https://github.com/bitcoin/bitcoin/blob/d612837814020ae832499d18e6ee5eb919a87907/src/primitives/transaction.h - //http://stackoverflow.com/questions/2711522/what-happens-if-i-assign-a-negative-value-to-an-unsigned-variable + // UInt32s cannot hold negative numbers, but sometimes the Bitcoin Protocol requires the vout to be -1, which is serialized + // as "0xFFFFFFFF". + // https://github.com/bitcoin/bitcoin/blob/d612837814020ae832499d18e6ee5eb919a87907/src/primitives/transaction.h + // http://stackoverflow.com/questions/2711522/what-happens-if-i-assign-a-negative-value-to-an-unsigned-variable val idxBytes = outPoint match { case EmptyTransactionOutPoint => UInt32.max.bytes case outPoint: TransactionOutPoint => outPoint.vout.bytes diff --git a/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutputParser.scala b/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutputParser.scala index b6f24cca83..5d0af045d9 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutputParser.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionOutputParser.scala @@ -23,13 +23,14 @@ sealed abstract class RawTransactionOutputParser /** Reads a single output from the given bytes, note this is different than * [[org.bitcoins.core.serializers.transaction.RawTransactionOutputParser.read RawTransactionOutputParser.read]] - * because it does NOT expect a [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] - * to be the first element in the byte array indicating how many outputs we have + * because it does NOT expect a + * [[org.bitcoins.core.protocol.CompactSizeUInt CompactSizeUInt]] to be the + * first element in the byte array indicating how many outputs we have */ override def read(bytes: ByteVector): TransactionOutput = { val satoshisBytes = bytes.take(8) val satoshis = RawSatoshisSerializer.read(satoshisBytes) - //it doesn't include itself towards the size, thats why it is incremented by one + // it doesn't include itself towards the size, thats why it is incremented by one val scriptPubKeyBytes = bytes.slice(8, bytes.size) val scriptPubKey = RawScriptPubKeyParser.read(scriptPubKeyBytes) val parsedOutput = TransactionOutput(satoshis, scriptPubKey) diff --git a/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionWitnessParser.scala b/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionWitnessParser.scala index 509754a79a..e54bdd7b1f 100644 --- a/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionWitnessParser.scala +++ b/core/src/main/scala/org/bitcoins/core/serializers/transaction/RawTransactionWitnessParser.scala @@ -7,23 +7,25 @@ import scodec.bits.ByteVector import scala.annotation.tailrec -/** Created by chris on 11/21/16. - * Serialization of - * [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] as defined inside of +/** Created by chris on 11/21/16. Serialization of + * [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] + * as defined inside of * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#specification BIP141]] * [[https://github.com/bitcoin/bitcoin/blob/b4e4ba475a5679e09f279aaf2a83dcf93c632bdb/src/primitives/transaction.h#L232-L268]] */ sealed abstract class RawTransactionWitnessParser { - /** We can only tell how many [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] - * we have if we have the number of inputs the transaction creates + /** We can only tell how many + * [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] we have + * if we have the number of inputs the transaction creates */ def read(bytes: ByteVector, numInputs: Int): TransactionWitness = { @tailrec def loop( remainingBytes: ByteVector, remainingInputs: Int, - accum: Vector[ScriptWitness]): Vector[ScriptWitness] = { + accum: Vector[ScriptWitness] + ): Vector[ScriptWitness] = { if (remainingInputs != 0) { val w = RawScriptWitnessParser.read(remainingBytes) val (_, newRemainingBytes) = remainingBytes.splitAt(w.bytes.size) diff --git a/core/src/main/scala/org/bitcoins/core/util/Base58.scala b/core/src/main/scala/org/bitcoins/core/util/Base58.scala index 4a7bdf5881..d53a038da0 100644 --- a/core/src/main/scala/org/bitcoins/core/util/Base58.scala +++ b/core/src/main/scala/org/bitcoins/core/util/Base58.scala @@ -8,8 +8,8 @@ import scodec.bits.ByteVector import scala.annotation.tailrec import scala.util.{Failure, Success, Try} -/** Created by chris on 5/16/16. - * source of values: [[https://en.bitcoin.it/wiki/Base58Check_encoding]] +/** Created by chris on 5/16/16. source of values: + * [[https://en.bitcoin.it/wiki/Base58Check_encoding]] */ sealed abstract class Base58 { import Base58Type._ @@ -18,8 +18,9 @@ sealed abstract class Base58 { "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" val base58Pairs: Map[Char, Int] = base58Characters.zipWithIndex.toMap - /** Verifies a given [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] - * string against its checksum (last 4 decoded bytes). + /** Verifies a given + * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] string + * against its checksum (last 4 decoded bytes). */ def decodeCheck(input: String): Try[ByteVector] = { val decodedTry: Try[ByteVector] = Try(decode(input)) @@ -38,7 +39,9 @@ sealed abstract class Base58 { } } - /** Encodes a sequence of bytes to a [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] string. */ + /** Encodes a sequence of bytes to a + * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] string. + */ def encode(bytes: ByteVector): String = { val ones: String = bytes.toSeq.takeWhile(_ == 0).map(_ => '1').mkString @tailrec @@ -60,14 +63,18 @@ sealed abstract class Base58 { } } - /** Encodes a hex string to its [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] representation. */ + /** Encodes a hex string to its + * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] + * representation. + */ def encode(hex: String): String = { val bytes = BytesUtil.decodeHex(hex) encode(bytes) } /** Encodes a [[scala.Byte Byte]] to its - * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] representation. + * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] + * representation. */ def encode(byte: Byte): String = encode(ByteVector.fromByte(byte)) @@ -84,15 +91,19 @@ sealed abstract class Base58 { else zeroes ++ ByteVector(decoded.toByteArray.dropWhile(_ == 0)) } - /** Determines if a string is a valid [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] string. */ + /** Determines if a string is a valid + * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] string. + */ def isValid(base58: String): Boolean = validityChecks(base58) match { case Success(bool) => bool case Failure(_) => false } - /** Checks a private key that begins with a symbol corresponding that private key to a compressed public key ('K', 'L', 'c'). - * In a Base58-encoded private key corresponding to a compressed public key, the 5th-to-last byte should be 0x01. + /** Checks a private key that begins with a symbol corresponding that private + * key to a compressed public key ('K', 'L', 'c'). In a Base58-encoded + * private key corresponding to a compressed public key, the 5th-to-last byte + * should be 0x01. */ private def checkCompressedPubKeyValidity(base58: String): Boolean = { val decoded = Base58.decode(base58) @@ -100,8 +111,8 @@ sealed abstract class Base58 { compressedByte == 0x01.toByte } - /** Checks if the string begins with an Address prefix byte/character. - * ('1', '3', 'm', 'n', '2') + /** Checks if the string begins with an Address prefix byte/character. ('1', + * '3', 'm', 'n', '2') */ private def isValidAddressPreFixByte(byte: Byte): Boolean = { val validAddressPreFixBytes: ByteVector = @@ -122,11 +133,15 @@ sealed abstract class Base58 { validSecretKeyPreFixBytes.toSeq.contains(byte) } - /** Checks the validity of a [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] string. - * A [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] string must not contain ('0', 'O', 'l', 'I'). - * If the string is an address: it must have a valid address prefix byte and must be between 26-35 characters in length. - * If the string is a private key: it must have a valid private key prefix byte and must have a byte size of 32. - * If the string is a private key corresponding to a compressed public key, the 5th-to-last byte must be 0x01. + /** Checks the validity of a + * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] string. A + * [[org.bitcoins.core.protocol.blockchain.Base58Type Base58Type]] string + * must not contain ('0', 'O', 'l', 'I'). If the string is an address: it + * must have a valid address prefix byte and must be between 26-35 characters + * in length. If the string is a private key: it must have a valid private + * key prefix byte and must have a byte size of 32. If the string is a + * private key corresponding to a compressed public key, the 5th-to-last byte + * must be 0x01. */ private def validityChecks(base58: String): Try[Boolean] = Try { diff --git a/core/src/main/scala/org/bitcoins/core/util/Bech32.scala b/core/src/main/scala/org/bitcoins/core/util/Bech32.scala index 8b1bd4ee54..cf9abd8e41 100644 --- a/core/src/main/scala/org/bitcoins/core/util/Bech32.scala +++ b/core/src/main/scala/org/bitcoins/core/util/Bech32.scala @@ -8,13 +8,16 @@ import scala.annotation.tailrec import scala.util.{Failure, Success, Try} /** There exists 2 different kinds of bech32 encodings: bech32 & bech32m - * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki - * @see https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki */ sealed abstract class Bech32Encoding { /** The constant that is XORed into the checksum - * @see https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki#bech32m + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki#bech32m */ def constant: Int } @@ -30,8 +33,8 @@ object Bech32Encoding { } } -/** A abstract class representing basic utility functions of Bech32 - * For more information on Bech32 please see BIP173 +/** A abstract class representing basic utility functions of Bech32 For more + * information on Bech32 please see BIP173 * [[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki]] */ sealed abstract class Bech32 { @@ -44,16 +47,17 @@ sealed abstract class Bech32 { */ def createChecksum( u5s: Vector[UInt5], - encoding: Bech32Encoding): Vector[UInt5] = { + encoding: Bech32Encoding + ): Vector[UInt5] = { val z = UInt5.zero val polymod: Long = polyMod(u5s ++ Array(z, z, z, z, z, z)) ^ encoding.constant - //[(polymod >> 5 * (5 - i)) & 31 for i in range(6)] + // [(polymod >> 5 * (5 - i)) & 31 for i in range(6)] val result: Vector[UInt5] = 0 .until(6) .map { i => - //((polymod >> five * (five - u)) & UInt8(31.toShort)) + // ((polymod >> five * (five - u)) & UInt8(31.toShort)) UInt5((polymod >> 5 * (5 - i)) & 31) } .toVector @@ -81,10 +85,10 @@ sealed abstract class Bech32 { var chk: Long = 1 bytes.foreach { v => val b = chk >> 25 - //chk = (chk & 0x1ffffff) << 5 ^ v + // chk = (chk & 0x1ffffff) << 5 ^ v chk = (chk & 0x1ffffff) << 5 ^ v.toLong 0.until(5).foreach { i: Int => - //chk ^= GEN[i] if ((b >> i) & 1) else 0 + // chk ^= GEN[i] if ((b >> i) & 1) else 0 if (((b >> i) & 1) == 1) { chk = chk ^ generators(i) } @@ -103,23 +107,28 @@ sealed abstract class Bech32 { remaining: List[Char], accum: List[Char], isLower: Boolean, - isUpper: Boolean): Try[Seq[Char]] = + isUpper: Boolean + ): Try[Seq[Char]] = remaining match { case h :: t => if (!isInHrpRange(h)) { Failure( new IllegalArgumentException( - "Invalid character range for hrp, got: " + hrp)) + "Invalid character range for hrp, got: " + hrp + ) + ) } else if (isLower && isUpper) { Failure( - new IllegalArgumentException("HRP had mixed case, got: " + hrp)) + new IllegalArgumentException("HRP had mixed case, got: " + hrp) + ) } else { loop(t, h +: accum, h.isLower || isLower, h.isUpper || isUpper) } case Nil => if (isLower && isUpper) { Failure( - new IllegalArgumentException("HRP had mixed case, got: " + hrp)) + new IllegalArgumentException("HRP had mixed case, got: " + hrp) + ) } else { Success(accum.reverse) } @@ -134,18 +143,21 @@ sealed abstract class Bech32 { } } - /** Checks the validity of the HRP against bech32 and the given [[StringFactory]] */ + /** Checks the validity of the HRP against bech32 and the given + * [[StringFactory]] + */ def checkHrpValidity[T <: Bech32HumanReadablePart]( hrp: String, - factory: StringFactory[T]): Try[T] = { + factory: StringFactory[T] + ): Try[T] = { checkHrpValidity(hrp) .flatMap(str => factory.fromStringT(str)) } def isInHrpRange(char: Char): Boolean = char >= 33 && char <= 126 - /** Takes in the data portion of a bech32 address and decodes it to a byte array - * It also checks the validity of the data portion according to BIP173 + /** Takes in the data portion of a bech32 address and decodes it to a byte + * array It also checks the validity of the data portion according to BIP173 */ def checkDataValidity(data: String): Try[Vector[UInt5]] = { @tailrec @@ -153,47 +165,54 @@ sealed abstract class Bech32 { remaining: List[Char], accum: Vector[UInt5], hasUpper: Boolean, - hasLower: Boolean): Try[Vector[UInt5]] = + hasLower: Boolean + ): Try[Vector[UInt5]] = remaining match { case Nil => Success(accum.reverse) case h :: t => if ((h.isUpper && hasLower) || (h.isLower && hasUpper)) { Failure( new IllegalArgumentException( - "Cannot have mixed case for bech32 address")) + "Cannot have mixed case for bech32 address" + ) + ) } else { val value = Bech32.charsetReversed(h.toInt) if (value == -1) { Failure( new IllegalArgumentException( - "Invalid character in data of bech32 address, got: " + h)) + "Invalid character in data of bech32 address, got: " + h + ) + ) } else { - loop(remaining = t, - accum = UInt5.fromByte(value.toByte) +: accum, - hasUpper = h.isUpper || hasUpper, - hasLower = h.isLower || hasLower) + loop( + remaining = t, + accum = UInt5.fromByte(value.toByte) +: accum, + hasUpper = h.isUpper || hasUpper, + hasLower = h.isLower || hasLower + ) } } } - val payload: Try[Vector[UInt5]] = loop(data.toCharArray.toList, - Vector.empty, - hasUpper = false, - hasLower = false) + val payload: Try[Vector[UInt5]] = loop( + data.toCharArray.toList, + Vector.empty, + hasUpper = false, + hasLower = false + ) payload } - /** Converts a byte vector to 5bit vector - * and then serializes to bech32 + /** Converts a byte vector to 5bit vector and then serializes to bech32 */ def encode8bitToString(bytes: ByteVector): String = { val vec = UInt8.toUInt8s(bytes) encode8bitToString(vec) } - /** Converts a byte vector to 5bit vector - * and then serializes to bech32 + /** Converts a byte vector to 5bit vector and then serializes to bech32 */ def encode8bitToString(bytes: Vector[UInt8]): String = { val b = from8bitTo5bit(bytes) @@ -223,16 +242,18 @@ sealed abstract class Bech32 { NumberUtil.convertUInt5sToUInt8(b, pad) } - /** Validate a Bech32 string, and determine HRP and data. - * Fails if HRP is not LN or BTC compatible. + /** Validate a Bech32 string, and determine HRP and data. Fails if HRP is not + * LN or BTC compatible. * - * @see Mimics - * [[https://github.com/sipa/bech32/blob/master/ref/python/segwit_addr.py#L62 this function]] - * by Sipa + * @see + * Mimics + * [[https://github.com/sipa/bech32/blob/master/ref/python/segwit_addr.py#L62 this function]] + * by Sipa */ def splitToHrpAndData( bech32: String, - encoding: Bech32Encoding): Try[(String, Vector[UInt5])] = { + encoding: Bech32Encoding + ): Try[(String, Vector[UInt5])] = { val sepIndexes = bech32.zipWithIndex.filter { case (sep, _) => sep == Bech32.separator } @@ -250,11 +271,15 @@ sealed abstract class Bech32 { if (length > maxLength || length < 8) { Failure( new IllegalArgumentException( - "Bech32 payloads must be between 8 and 90 chars, got: " + length)) + "Bech32 payloads must be between 8 and 90 chars, got: " + length + ) + ) } else if (sepIndexes.isEmpty) { Failure( new IllegalArgumentException( - "Bech32 payload did not have the correct separator")) + "Bech32 payload did not have the correct separator" + ) + ) } else { val (_, sepIndex) = sepIndexes.last val hrpStr = bech32.take(sepIndex) @@ -275,7 +300,9 @@ sealed abstract class Bech32 { } else Failure( new IllegalArgumentException( - s"Checksum was invalid on bech32 string $bech32")) + s"Checksum was invalid on bech32 string $bech32" + ) + ) } } yield (hrpString, dataNoCheck) } @@ -285,7 +312,8 @@ sealed abstract class Bech32 { def splitToHrpAndData[T <: Bech32HumanReadablePart]( bech32: String, encoding: Bech32Encoding, - factory: StringFactory[T]): Try[(T, Vector[UInt5])] = { + factory: StringFactory[T] + ): Try[(T, Vector[UInt5])] = { splitToHrpAndData(bech32, encoding).flatMap { case (hrpString, data) => factory @@ -297,7 +325,8 @@ sealed abstract class Bech32 { def verifyChecksum( hrp: Seq[UInt5], u5s: Seq[UInt5], - encoding: Bech32Encoding): Boolean = { + encoding: Bech32Encoding + ): Boolean = { val data = hrp ++ u5s val checksum = Bech32.polyMod(data.toVector) checksum == encoding.constant @@ -309,8 +338,10 @@ sealed abstract class Bech32 { .map(_.toLower) .map { char => val index = Bech32.charset.indexOf(char) - require(index >= 0, - s"$char (${char.toInt}) is not part of the Bech32 charset!") + require( + index >= 0, + s"$char (${char.toInt}) is not part of the Bech32 charset!" + ) UInt5(index) } .toVector @@ -326,12 +357,14 @@ object Bech32 extends Bech32 { * See [[https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32 BIP173]] * for more */ - val charset: Vector[Char] = Vector('q', 'p', 'z', 'r', 'y', '9', 'x', '8', - 'g', 'f', '2', 't', 'v', 'd', 'w', '0', 's', '3', 'j', 'n', '5', '4', 'k', - 'h', 'c', 'e', '6', 'm', 'u', 'a', '7', 'l') + val charset: Vector[Char] = + Vector('q', 'p', 'z', 'r', 'y', '9', 'x', '8', 'g', 'f', '2', 't', 'v', 'd', + 'w', '0', 's', '3', 'j', 'n', '5', '4', 'k', 'h', 'c', 'e', '6', 'm', + 'u', 'a', '7', 'l') /** The Bech32 character set for decoding. - * @see https://github.com/sipa/bech32/blob/master/ref/c%2B%2B/bech32.cpp#L33 + * @see + * https://github.com/sipa/bech32/blob/master/ref/c%2B%2B/bech32.cpp#L33 */ val charsetReversed: Vector[Int] = Vector( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -345,11 +378,15 @@ object Bech32 extends Bech32 { } abstract class Bech32HumanReadablePart { - require(chars.forall(Bech32.isInHrpRange), - s"Some characters in $chars were not in valid HRP range ([33-126])") + require( + chars.forall(Bech32.isInHrpRange), + s"Some characters in $chars were not in valid HRP range ([33-126])" + ) def chars: String - /** Expands this HRP into a vector of UInt5s, in accordance with the Bech32 spec */ + /** Expands this HRP into a vector of UInt5s, in accordance with the Bech32 + * spec + */ def expand: Vector[UInt5] = Bech32.hrpExpand(chars) } diff --git a/core/src/main/scala/org/bitcoins/core/util/BinaryTree.scala b/core/src/main/scala/org/bitcoins/core/util/BinaryTree.scala index 2a975e73c5..fff069ee17 100644 --- a/core/src/main/scala/org/bitcoins/core/util/BinaryTree.scala +++ b/core/src/main/scala/org/bitcoins/core/util/BinaryTree.scala @@ -27,15 +27,16 @@ trait BinaryTree[+T] { case Empty => None } - /** Creates a sequence with only the leaf values - * evaluates as depth first from left to right. + /** Creates a sequence with only the leaf values evaluates as depth first from + * left to right. */ def toSeqLeafValues: Seq[T] = { @tailrec def loop( tree: BinaryTree[T], accum: List[T], - remainder: List[BinaryTree[T]]): Seq[T] = + remainder: List[BinaryTree[T]] + ): Seq[T] = tree match { case Leaf(x) => if (remainder.isEmpty) x :: accum @@ -51,12 +52,14 @@ trait BinaryTree[+T] { /** A function to find the first occurrence of a predicate inside a * [[org.bitcoins.core.util.BinaryTree BinaryTree]]. */ - def findFirstDFS[T](t: T)(f: T => Boolean = (x: T) => x == t)(implicit - tree: BinaryTree[T] = this): Option[BinaryTree[T]] = { + def findFirstDFS[T](t: T)( + f: T => Boolean = (x: T) => x == t + )(implicit tree: BinaryTree[T] = this): Option[BinaryTree[T]] = { @tailrec def loop( subTree: BinaryTree[T], - remainder: List[BinaryTree[T]]): Option[BinaryTree[T]] = { + remainder: List[BinaryTree[T]] + ): Option[BinaryTree[T]] = { subTree match { case Empty => if (remainder.isEmpty) None else loop(remainder.head, remainder.tail) @@ -72,42 +75,50 @@ trait BinaryTree[+T] { loop(tree, List()) } - /** Checks if the [[org.bitcoins.core.util.BinaryTree BinaryTree]] contains a certain element. */ + /** Checks if the [[org.bitcoins.core.util.BinaryTree BinaryTree]] contains a + * certain element. + */ def contains[T](t: T)(f: T => Boolean = (x: T) => x == t)(implicit - tree: BinaryTree[T] = this): Boolean = + tree: BinaryTree[T] = this + ): Boolean = findFirstDFS(t)(f)(tree).isDefined def count[T](t: T): Int = toSeq.count(_ == t) - /** Inserts an element into one of the two branches in a [[org.bitcoins.core.util.BinaryTree BinaryTree]]. - * If it cannot insert it because the branches are not empty, - * it throws a [[scala.RuntimeException RuntimeException]]. + /** Inserts an element into one of the two branches in a + * [[org.bitcoins.core.util.BinaryTree BinaryTree]]. If it cannot insert it + * because the branches are not empty, it throws a + * [[scala.RuntimeException RuntimeException]]. */ def insert[T](t: T)(implicit tree: BinaryTree[T] = this): BinaryTree[T] = { insert(Leaf(t))(tree) } - /** Inserts a tree into one of the two branches in a [[org.bitcoins.core.util.BinaryTree BinaryTree]] - * If it cannot insert it because the branches are not empty, - * it throws a [[scala.RuntimeException RuntimeException]]. + /** Inserts a tree into one of the two branches in a + * [[org.bitcoins.core.util.BinaryTree BinaryTree]] If it cannot insert it + * because the branches are not empty, it throws a + * [[scala.RuntimeException RuntimeException]]. */ - def insert[T](subTree: BinaryTree[T])(implicit - parentTree: BinaryTree[T]): BinaryTree[T] = + def insert[T]( + subTree: BinaryTree[T] + )(implicit parentTree: BinaryTree[T]): BinaryTree[T] = parentTree match { case n: Node[T] => if (n.l == Empty) Node[T](n.v, subTree, n.r) else if (n.r == Empty) Node[T](n.v, n.l, subTree) else throw new RuntimeException( - "There was no empty branch to insert the new t: " + subTree + "inside of tree: " + parentTree) + "There was no empty branch to insert the new t: " + subTree + "inside of tree: " + parentTree + ) case l: Leaf[T] => Node(l.v, subTree, Empty) case Empty => subTree } /** Removes the subTree from the parentTree. */ - def remove[T](subTree: BinaryTree[T])( - parentTree: BinaryTree[T] = this): BinaryTree[T] = { - //TODO: Optimize into a tail recursive function + def remove[T]( + subTree: BinaryTree[T] + )(parentTree: BinaryTree[T] = this): BinaryTree[T] = { + // TODO: Optimize into a tail recursive function parentTree match { case Empty => Empty case l: Leaf[T] => if (l == subTree) Empty else l @@ -119,17 +130,20 @@ trait BinaryTree[+T] { /** Replaces all instances of the original tree with the replacement tree. */ def replace[T](originalTree: BinaryTree[T], replacementTree: BinaryTree[T])( - implicit parentTree: BinaryTree[T] = this): BinaryTree[T] = { - //TODO: Optimize this into a tail recursive function + implicit parentTree: BinaryTree[T] = this + ): BinaryTree[T] = { + // TODO: Optimize this into a tail recursive function parentTree match { case Empty => if (originalTree == Empty) replacementTree else Empty case l: Leaf[T] => if (l == originalTree) replacementTree else l case n: Node[T] => if (n == originalTree) replacementTree else - Node(n.v, - replace(originalTree, replacementTree)(n.l), - replace(originalTree, replacementTree)(n.r)) + Node( + n.v, + replace(originalTree, replacementTree)(n.l), + replace(originalTree, replacementTree)(n.r) + ) } } @@ -138,7 +152,8 @@ trait BinaryTree[+T] { def loop( tree: BinaryTree[T], accum: List[T], - remainder: List[BinaryTree[T]]): List[T] = + remainder: List[BinaryTree[T]] + ): List[T] = tree match { case Leaf(x) => if (remainder.isEmpty) accum ++ List(x) diff --git a/core/src/main/scala/org/bitcoins/core/util/BitcoinScriptUtil.scala b/core/src/main/scala/org/bitcoins/core/util/BitcoinScriptUtil.scala index b7a49523c3..1eb084eac4 100644 --- a/core/src/main/scala/org/bitcoins/core/util/BitcoinScriptUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/util/BitcoinScriptUtil.scala @@ -46,7 +46,9 @@ import scala.util.{Failure, Success, Try} */ trait BitcoinScriptUtil { - /** Takes in a sequence of script tokens and converts them to their hexadecimal value */ + /** Takes in a sequence of script tokens and converts them to their + * hexadecimal value + */ def asmToHex(asm: Seq[ScriptToken]): String = { val hex = asm.map(_.hex).mkString hex @@ -56,15 +58,15 @@ trait BitcoinScriptUtil { def asmToBytes(asm: Seq[ScriptToken]): ByteVector = BytesUtil.decodeHex(asmToHex(asm)) - /** Filters out push operations in our sequence of script tokens - * this removes + /** Filters out push operations in our sequence of script tokens this removes * [[org.bitcoins.core.script.constant.OP_PUSHDATA1 OP_PUSHDATA1]], * [[org.bitcoins.core.script.constant.OP_PUSHDATA2 OP_PUSHDATA2]], - * [[org.bitcoins.core.script.constant.OP_PUSHDATA4 OP_PUSHDATA4]], - * and all [[org.bitcoins.core.script.constant.BytesToPushOntoStack ByteToPushOntoStack]] tokens + * [[org.bitcoins.core.script.constant.OP_PUSHDATA4 OP_PUSHDATA4]], and all + * [[org.bitcoins.core.script.constant.BytesToPushOntoStack ByteToPushOntoStack]] + * tokens */ def filterPushOps(asm: Seq[ScriptToken]): Seq[ScriptToken] = { - //TODO: This does not remove the following script number after a OP_PUSHDATA + // TODO: This does not remove the following script number after a OP_PUSHDATA asm.filterNot(op => op.isInstanceOf[BytesToPushOntoStack] || op == OP_PUSHDATA1 @@ -72,7 +74,9 @@ trait BitcoinScriptUtil { || op == OP_PUSHDATA4) } - /** Returns only the data ScriptTokens in a script that are pushed onto the stack */ + /** Returns only the data ScriptTokens in a script that are pushed onto the + * stack + */ def getDataTokens(asm: Seq[ScriptToken]): Seq[ScriptToken] = { val builder = Vector.newBuilder[ScriptToken] @@ -92,8 +96,8 @@ trait BitcoinScriptUtil { builder.result() } - /** Returns true if the given script token counts towards our max script operations in a script - * See + /** Returns true if the given script token counts towards our max script + * operations in a script See * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L269-L271 interpreter.cpp#L269-L271]] * which is how Bitcoin Core handles this */ @@ -113,8 +117,10 @@ trait BitcoinScriptUtil { /** Counts the amount of sigops in a script. * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/script.cpp#L156-L202 Bitcoin Core script.cpp]] - * @param script the script whose sigops are being counted - * @return the number of signature operations in the script + * @param script + * the script whose sigops are being counted + * @return + * the number of signature operations in the script */ def countSigOps(script: Seq[ScriptToken]): Long = { val checkSigCount = @@ -133,14 +139,14 @@ trait BitcoinScriptUtil { checkSigCount + multiSigCount } - /** Parses the number of signatures on the stack - * This can only be called when an [[org.bitcoins.core.script.crypto.OP_CHECKMULTISIG OP_CHECKMULTISIG]] - * operation is about to be executed - * on the stack - * For instance if this was a 2/3 multisignature script, it would return the number 3 + /** Parses the number of signatures on the stack This can only be called when + * an [[org.bitcoins.core.script.crypto.OP_CHECKMULTISIG OP_CHECKMULTISIG]] + * operation is about to be executed on the stack For instance if this was a + * 2/3 multisignature script, it would return the number 3 */ def numPossibleSignaturesOnStack( - program: ExecutionInProgressScriptProgram): ScriptNumber = { + program: ExecutionInProgressScriptProgram + ): ScriptNumber = { require( program.script.headOption .contains(OP_CHECKMULTISIG) || program.script.headOption @@ -152,16 +158,18 @@ trait BitcoinScriptUtil { case s: ScriptConstant => ScriptNumber(s.bytes) case _: ScriptToken => throw new RuntimeException( - "n must be a script number or script constant for OP_CHECKMULTISIG") + "n must be a script number or script constant for OP_CHECKMULTISIG" + ) } nPossibleSignatures } - /** Returns the number of required signatures on the stack, for instance if this was a - * 2/3 multisignature script, it would return the number 2 + /** Returns the number of required signatures on the stack, for instance if + * this was a 2/3 multisignature script, it would return the number 2 */ def numRequiredSignaturesOnStack( - program: ExecutionInProgressScriptProgram): ScriptNumber = { + program: ExecutionInProgressScriptProgram + ): ScriptNumber = { require( program.script.headOption .contains(OP_CHECKMULTISIG) || program.script.headOption @@ -176,13 +184,14 @@ trait BitcoinScriptUtil { case s: ScriptConstant => ScriptNumber(s.bytes) case _: ScriptToken => throw new RuntimeException( - "m must be a script number or script constant for OP_CHECKMULTISIG") + "m must be a script number or script constant for OP_CHECKMULTISIG" + ) } mRequiredSignatures } - /** Determines if a script contains only script operations - * This is equivalent to + /** Determines if a script contains only script operations This is equivalent + * to * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/script.cpp#L213 Bitcoin Core script.cpp#L213]] */ def isPushOnly(script: Seq[ScriptToken]): Boolean = { @@ -205,11 +214,13 @@ trait BitcoinScriptUtil { loop(script) } - /** Determines if the token being pushed onto the stack is being pushed by the SMALLEST push operation possible - * This is equivalent to + /** Determines if the token being pushed onto the stack is being pushed by the + * SMALLEST push operation possible This is equivalent to * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L209 Bitcoin Core interpreter.cpp#L209]] - * @param pushOp the operation that is pushing the data onto the stack - * @param token the token that is being pushed onto the stack by the pushOp + * @param pushOp + * the operation that is pushing the data onto the stack + * @param token + * the token that is being pushed onto the stack by the pushOp * @return */ def isMinimalPush(pushOp: ScriptToken, token: ScriptToken): Boolean = @@ -217,14 +228,14 @@ trait BitcoinScriptUtil { case scriptNumOp: ScriptNumberOperation => scriptNumOp == pushOp case ScriptConstant.zero | ScriptConstant.negativeZero => - //weird case where OP_0 pushes an empty byte vector on the stack, NOT "00" or "81" - //so we can push the constant "00" or "81" onto the stack with a BytesToPushOntoStack pushop + // weird case where OP_0 pushes an empty byte vector on the stack, NOT "00" or "81" + // so we can push the constant "00" or "81" onto the stack with a BytesToPushOntoStack pushop pushOp == BytesToPushOntoStack(1) case _: ScriptToken if token.bytes.size == 1 && ScriptNumberOperation .fromNumber(token.toLong.toInt) .isDefined => - //could have used the ScriptNumberOperation to push the number onto the stack + // could have used the ScriptNumberOperation to push the number onto the stack false case token: ScriptToken => token.bytes.size match { @@ -233,14 +244,16 @@ trait BitcoinScriptUtil { case size if size <= 255 => pushOp == OP_PUSHDATA1 case size if size <= 65535 => pushOp == OP_PUSHDATA2 case _: Long => - //default case is true because we have to use the largest push op as possible which is OP_PUSHDATA4 + // default case is true because we have to use the largest push op as possible which is OP_PUSHDATA4 true } } - /** Calculates the push operation for the given [[org.bitcoins.core.script.constant.ScriptToken ScriptToken]] */ + /** Calculates the push operation for the given + * [[org.bitcoins.core.script.constant.ScriptToken ScriptToken]] + */ def calculatePushOp(scriptToken: ScriptToken): Seq[ScriptToken] = { - //push ops following an OP_PUSHDATA operation are interpreted as unsigned numbers + // push ops following an OP_PUSHDATA operation are interpreted as unsigned numbers val scriptTokenSize = UInt32(scriptToken.bytes.size) val bytes = scriptTokenSize.bytes if ( @@ -251,29 +264,33 @@ trait BitcoinScriptUtil { else if (scriptTokenSize <= UInt32(75)) Seq(BytesToPushOntoStack(scriptToken.bytes.size)) else if (scriptTokenSize <= UInt32(OP_PUSHDATA1.max)) { - //we need the push op to be only 1 byte in size + // we need the push op to be only 1 byte in size val pushConstant = ScriptConstant( - BytesUtil.flipEndianness(bytes.slice(bytes.length - 1, bytes.length))) + BytesUtil.flipEndianness(bytes.slice(bytes.length - 1, bytes.length)) + ) Seq(OP_PUSHDATA1, pushConstant) } else if (scriptTokenSize <= UInt32(OP_PUSHDATA2.max)) { - //we need the push op to be only 2 bytes in size + // we need the push op to be only 2 bytes in size val pushConstant = ScriptConstant( - BytesUtil.flipEndianness(bytes.slice(bytes.length - 2, bytes.length))) + BytesUtil.flipEndianness(bytes.slice(bytes.length - 2, bytes.length)) + ) Seq(OP_PUSHDATA2, pushConstant) } else if (scriptTokenSize <= UInt32(OP_PUSHDATA4.max)) { val pushConstant = ScriptConstant(BytesUtil.flipEndianness(bytes)) Seq(OP_PUSHDATA4, pushConstant) } else throw new IllegalArgumentException( - "ScriptToken is to large for pushops, size: " + scriptTokenSize) + "ScriptToken is to large for pushops, size: " + scriptTokenSize + ) } def calculatePushOp(bytes: ByteVector): Seq[ScriptToken] = calculatePushOp(ScriptConstant(bytes)) - /** Whenever a [[org.bitcoins.core.script.constant.ScriptConstant ScriptConstant]] is interpreted to a number - * BIP62 could enforce that number to be encoded - * in the smallest encoding possible + /** Whenever a + * [[org.bitcoins.core.script.constant.ScriptConstant ScriptConstant]] is + * interpreted to a number BIP62 could enforce that number to be encoded in + * the smallest encoding possible * [[https://github.com/bitcoin/bitcoin/blob/a6a860796a44a2805a58391a009ba22752f64e32/src/script/script.h#L220-L237]] */ def isShortestEncoding(constant: ScriptConstant): Boolean = @@ -295,8 +312,8 @@ trait BitcoinScriptUtil { } else true } - /** Whenever a script constant is interpreted to a number BIP62 should enforce that number to be encoded - * in the smallest encoding possible + /** Whenever a script constant is interpreted to a number BIP62 should enforce + * that number to be encoded in the smallest encoding possible * [[https://github.com/bitcoin/bitcoin/blob/a6a860796a44a2805a58391a009ba22752f64e32/src/script/script.h#L220-L237]] */ def isShortestEncoding(hex: String): Boolean = @@ -304,8 +321,8 @@ trait BitcoinScriptUtil { /** Checks if the token is minimially encoded */ def isMinimalToken(token: ScriptToken): Boolean = { - //see: https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L447-L452 - //https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-August/013014.html + // see: https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L447-L452 + // https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-August/013014.html val tooBig = token.bytes.size > 1 val sizeZero = token.bytes.isEmpty lazy val startsWithOne = token.bytes.head == 1 @@ -313,17 +330,20 @@ trait BitcoinScriptUtil { !tooBig && (sizeZero || startsWithOne) } - /** Checks the [[org.bitcoins.crypto.ECPublicKey ECPublicKey]] encoding according to bitcoin core's function: + /** Checks the [[org.bitcoins.crypto.ECPublicKey ECPublicKey]] encoding + * according to bitcoin core's function: * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L202]]. */ def checkPubKeyEncoding( key: ECPublicKeyBytes, - program: ExecutionInProgressScriptProgram): Boolean = + program: ExecutionInProgressScriptProgram + ): Boolean = checkPubKeyEncoding(key, program.flags) def checkPubKeyEncoding( key: ECPublicKeyBytes, - flags: Seq[ScriptFlag]): Boolean = { + flags: Seq[ScriptFlag] + ): Boolean = { if ( ScriptFlagUtil.requireStrictEncoding(flags) && !isCompressedOrUncompressedPubKey(key) @@ -333,8 +353,10 @@ trait BitcoinScriptUtil { /** Returns true if the key is compressed or uncompressed, false otherwise * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L66]] - * @param key the public key that is being checked - * @return true if the key is compressed/uncompressed otherwise false + * @param key + * the public key that is being checked + * @return + * true if the key is compressed/uncompressed otherwise false */ def isCompressedOrUncompressedPubKey(key: ECPublicKeyBytes): Boolean = { if (key.bytes.size < 33) { @@ -366,15 +388,16 @@ trait BitcoinScriptUtil { } /** Determines if the given pubkey is valid in accordance to the given - * [[org.bitcoins.core.script.flag.ScriptFlag ScriptFlag]]s - * and [[org.bitcoins.core.protocol.script.SignatureVersion SignatureVersion]]. + * [[org.bitcoins.core.script.flag.ScriptFlag ScriptFlag]]s and + * [[org.bitcoins.core.protocol.script.SignatureVersion SignatureVersion]]. * Mimics this function inside of Bitcoin Core * [[https://github.com/bitcoin/bitcoin/blob/528472111b4965b1a99c4bcf08ac5ec93d87f10f/src/script/interpreter.cpp#L214-L223]] */ def isValidPubKeyEncoding( pubKey: ECPublicKeyBytes, sigVersion: SignatureVersion, - flags: Seq[ScriptFlag]): Option[ScriptError] = { + flags: Seq[ScriptFlag] + ): Option[ScriptError] = { if ( ScriptFlagUtil.requireStrictEncoding(flags) && !BitcoinScriptUtil.isCompressedOrUncompressedPubKey(pubKey) @@ -383,26 +406,32 @@ trait BitcoinScriptUtil { } else if ( ScriptFlagUtil.requireScriptVerifyWitnessPubKeyType(flags) && !BitcoinScriptUtil.isCompressedPubKey( - pubKey) && sigVersion == SigVersionWitnessV0 + pubKey + ) && sigVersion == SigVersionWitnessV0 ) { Some(ScriptErrorWitnessPubKeyType) } else None } - /** Prepares the script we spending to be serialized for our transaction signature serialization algorithm - * We need to check if the scriptSignature has a redeemScript - * In that case, we need to pass the redeemScript to the TransactionSignatureChecker + /** Prepares the script we spending to be serialized for our transaction + * signature serialization algorithm We need to check if the scriptSignature + * has a redeemScript In that case, we need to pass the redeemScript to the + * TransactionSignatureChecker * - * In the case we have a P2SH(P2WSH) we need to pass the witness's redeem script to the + * In the case we have a P2SH(P2WSH) we need to pass the witness's redeem + * script to the * [[org.bitcoins.core.crypto.TransactionSignatureChecker TransactionSignatureChecker]] * instead of passing the - * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] inside of the - * [[org.bitcoins.core.protocol.script.P2SHScriptSignature P2SHScriptSignature]]'s redeem script. + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] + * inside of the + * [[org.bitcoins.core.protocol.script.P2SHScriptSignature P2SHScriptSignature]]'s + * redeem script. */ def calculateScriptForChecking( txSignatureComponent: TxSigComponent, signature: ECDigitalSignature, - script: Seq[ScriptToken]): Seq[ScriptToken] = { + script: Seq[ScriptToken] + ): Seq[ScriptToken] = { val scriptForChecking = calculateScriptForSigning(txSignatureComponent, script) txSignatureComponent.sigVersion match { @@ -410,26 +439,28 @@ trait BitcoinScriptUtil { removeSignatureFromScript(signature, scriptForChecking) case SigVersionWitnessV0 | SigVersionTaprootKeySpend | SigVersionTapscript => - //BIP143 removes requirement for calling FindAndDelete - //https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#no-findanddelete + // BIP143 removes requirement for calling FindAndDelete + // https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#no-findanddelete scriptForChecking } } def calculateScriptForSigning( txSignatureComponent: TxSigComponent, - script: Seq[ScriptToken]): Seq[ScriptToken] = + script: Seq[ScriptToken] + ): Seq[ScriptToken] = txSignatureComponent.scriptPubKey match { case _: P2SHScriptPubKey => val p2shScriptSig = P2SHScriptSignature( - txSignatureComponent.scriptSignature.bytes) + txSignatureComponent.scriptSignature.bytes + ) p2shScriptSig.redeemScript match { case p2wpkh: P2WPKHWitnessSPKV0 => - //we treat p2sh(p2wpkh) differently for script signing than other spks - //Please note that for a P2SH-P2WPKH, the scriptCode is always 26 bytes including the leading size byte, + // we treat p2sh(p2wpkh) differently for script signing than other spks + // Please note that for a P2SH-P2WPKH, the scriptCode is always 26 bytes including the leading size byte, // as 0x1976a914{20-byte keyhash}88ac, NOT the redeemScript nor scriptPubKey - //https://bitcoincore.org/en/segwit_wallet_dev/#signature-generation-and-verification-for-p2sh-p2wpkh + // https://bitcoincore.org/en/segwit_wallet_dev/#signature-generation-and-verification-for-p2sh-p2wpkh P2PKHScriptPubKey(p2wpkh.pubKeyHash).asm @@ -443,7 +474,8 @@ trait BitcoinScriptUtil { case _: ScriptPubKey => val sigsRemoved = removeSignaturesFromScript( p2shScriptSig.signatures, - p2shScriptSig.redeemScript.asm) + p2shScriptSig.redeemScript.asm + ) sigsRemoved } @@ -455,8 +487,8 @@ trait BitcoinScriptUtil { case rWTxSigComponent: WitnessTxSigComponentRebuilt => rWTxSigComponent.scriptPubKey.asm case _: BaseTxSigComponent => - //shouldn't have BaseTxSigComponent - //with a witness scriptPubKey + // shouldn't have BaseTxSigComponent + // with a witness scriptPubKey script } case _: P2PKHScriptPubKey | _: P2PKScriptPubKey | @@ -470,7 +502,8 @@ trait BitcoinScriptUtil { def calculateScriptForSigning( spendingTransaction: Transaction, signingInfo: InputSigningInfo[InputInfo], - script: Seq[ScriptToken]): Seq[ScriptToken] = { + script: Seq[ScriptToken] + ): Seq[ScriptToken] = { val idx = TxUtil.inputIndex(signingInfo.inputInfo, spendingTransaction) @@ -480,10 +513,10 @@ trait BitcoinScriptUtil { p2sh.redeemScript match { case p2wpkh: P2WPKHWitnessSPKV0 => - //we treat p2sh(p2wpkh) differently for script signing than other spks - //Please note that for a P2SH-P2WPKH, the scriptCode is always 26 bytes including the leading size byte, + // we treat p2sh(p2wpkh) differently for script signing than other spks + // Please note that for a P2SH-P2WPKH, the scriptCode is always 26 bytes including the leading size byte, // as 0x1976a914{20-byte keyhash}88ac, NOT the redeemScript nor scriptPubKey - //https://bitcoincore.org/en/segwit_wallet_dev/#signature-generation-and-verification-for-p2sh-p2wpkh + // https://bitcoincore.org/en/segwit_wallet_dev/#signature-generation-and-verification-for-p2sh-p2wpkh P2PKHScriptPubKey(p2wpkh.pubKeyHash).asm @@ -513,33 +546,37 @@ trait BitcoinScriptUtil { } } - /** Removes the given [[ECDigitalSignature ECDigitalSignature]] from the list of - * [[org.bitcoins.core.script.constant.ScriptToken ScriptToken]] if it exists. + /** Removes the given [[ECDigitalSignature ECDigitalSignature]] from the list + * of [[org.bitcoins.core.script.constant.ScriptToken ScriptToken]] if it + * exists. */ def removeSignatureFromScript( signature: ECDigitalSignature, - script: Seq[ScriptToken]): Seq[ScriptToken] = { + script: Seq[ScriptToken] + ): Seq[ScriptToken] = { if (script.contains(ScriptConstant(signature.hex))) { - //replicates this line in bitcoin core - //https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L872 + // replicates this line in bitcoin core + // https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L872 val sigIndex = script.indexOf(ScriptConstant(signature.hex)) - //remove sig and it's corresponding BytesToPushOntoStack + // remove sig and it's corresponding BytesToPushOntoStack val sigRemoved = script.slice(0, sigIndex - 1) ++ script.slice(sigIndex + 1, script.size) sigRemoved } else script } - /** Removes the list of [[ECDigitalSignature ECDigitalSignature]] from the list of - * [[org.bitcoins.core.script.constant.ScriptToken ScriptToken]] + /** Removes the list of [[ECDigitalSignature ECDigitalSignature]] from the + * list of [[org.bitcoins.core.script.constant.ScriptToken ScriptToken]] */ def removeSignaturesFromScript( sigs: Seq[ECDigitalSignature], - script: Seq[ScriptToken]): Seq[ScriptToken] = { + script: Seq[ScriptToken] + ): Seq[ScriptToken] = { @tailrec def loop( remainingSigs: Seq[ECDigitalSignature], - scriptTokens: Seq[ScriptToken]): Seq[ScriptToken] = { + scriptTokens: Seq[ScriptToken] + ): Seq[ScriptToken] = { remainingSigs match { case Nil => scriptTokens case h +: t => @@ -550,12 +587,14 @@ trait BitcoinScriptUtil { loop(sigs, script) } - /** Removes the [[org.bitcoins.core.script.crypto.OP_CODESEPARATOR OP_CODESEPARATOR]] - * in the original script according to - * the last code separator index in the script. + /** Removes the + * [[org.bitcoins.core.script.crypto.OP_CODESEPARATOR OP_CODESEPARATOR]] in + * the original script according to the last code separator index in the + * script. */ def removeOpCodeSeparator( - program: ExecutionInProgressScriptProgram): Seq[ScriptToken] = { + program: ExecutionInProgressScriptProgram + ): Seq[ScriptToken] = { if (program.lastCodeSeparator.isDefined) { program.originalScript .slice(program.lastCodeSeparator.get + 1, program.originalScript.size) @@ -563,18 +602,21 @@ trait BitcoinScriptUtil { } private def parseScriptEither( - scriptT: Either[ScriptError, ScriptPubKey]): Seq[ScriptToken] = + scriptT: Either[ScriptError, ScriptPubKey] + ): Seq[ScriptToken] = scriptT match { case Right(scriptPubKey) => scriptPubKey.asm case Left(err) => throw new IllegalArgumentException( - s"Could not parse witness script, got err=$err") + s"Could not parse witness script, got err=$err" + ) } - /** Casts the given script token to a boolean value - * Mimics this function inside of Bitcoin Core + /** Casts the given script token to a boolean value Mimics this function + * inside of Bitcoin Core * [[https://github.com/bitcoin/bitcoin/blob/8c1dbc5e9ddbafb77e60e8c4e6eb275a3a76ac12/src/script/interpreter.cpp#L38]] - * All bytes in the byte vector must be zero, unless it is the last byte, which can be 0 or 0x80 (negative zero) + * All bytes in the byte vector must be zero, unless it is the last byte, + * which can be 0 or 0x80 (negative zero) */ def castToBool(token: ScriptToken): Boolean = { token.bytes.toArray.zipWithIndex.exists { case (b, index) => @@ -585,8 +627,8 @@ trait BitcoinScriptUtil { } } - /** Since witnesses are not run through the interpreter, replace - * `OP_0`/`OP_1` with `ScriptNumber.zero`/`ScriptNumber.one` + /** Since witnesses are not run through the interpreter, replace `OP_0`/`OP_1` + * with `ScriptNumber.zero`/`ScriptNumber.one` */ def minimalIfOp(asm: Seq[ScriptToken]): Seq[ScriptToken] = { asm.map { @@ -605,8 +647,8 @@ trait BitcoinScriptUtil { else asm } - /** Checks that all the [[org.bitcoins.crypto.ECPublicKey ECPublicKey]] in this script - * is compressed public keys, this is required for BIP143 + /** Checks that all the [[org.bitcoins.crypto.ECPublicKey ECPublicKey]] in + * this script is compressed public keys, this is required for BIP143 */ def isOnlyCompressedPubKey(spk: ScriptPubKey): Boolean = { spk match { @@ -619,7 +661,8 @@ trait BitcoinScriptUtil { isOnlyCompressedPubKey(l.nestedScriptPubKey) case conditional: ConditionalScriptPubKey => isOnlyCompressedPubKey(conditional.trueSPK) && isOnlyCompressedPubKey( - conditional.falseSPK) + conditional.falseSPK + ) case _: P2PKHScriptPubKey | _: P2SHScriptPubKey | _: P2WPKHWitnessSPKV0 | _: P2WSHWitnessSPKV0 | _: UnassignedWitnessScriptPubKey | _: NonStandardScriptPubKey | _: WitnessCommitment | @@ -631,21 +674,25 @@ trait BitcoinScriptUtil { def parseScript[T <: Script]( bytes: ByteVector, - f: Vector[ScriptToken] => T): T = { + f: Vector[ScriptToken] => T + ): T = { val compactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(bytes) - //TODO: Figure out a better way to do this, we can theoretically have numbers larger than Int.MaxValue, - //but scala collections don't allow you to use 'slice' with longs + // TODO: Figure out a better way to do this, we can theoretically have numbers larger than Int.MaxValue, + // but scala collections don't allow you to use 'slice' with longs val len = Try(compactSizeUInt.num.toInt).getOrElse(Int.MaxValue) val scriptPubKeyBytes = - bytes.slice(compactSizeUInt.byteSize.toInt, - len + compactSizeUInt.byteSize.toInt) + bytes.slice( + compactSizeUInt.byteSize.toInt, + len + compactSizeUInt.byteSize.toInt + ) val script: Vector[ScriptToken] = ScriptParser.fromBytes(scriptPubKeyBytes) f(script) } def verifyScript( tx: Transaction, - utxos: Seq[ScriptSignatureParams[InputInfo]]): Boolean = { + utxos: Seq[ScriptSignatureParams[InputInfo]] + ): Boolean = { val programs: Seq[PreExecutionScriptProgram] = tx.inputs.zipWithIndex.map { case (input: TransactionInput, idx: Int) => val outpoint = input.previousOutput @@ -661,10 +708,12 @@ trait BitcoinScriptUtil { val txSigComponent = spk match { case witSPK: WitnessScriptPubKeyV0 => val o = TransactionOutput(amount, witSPK) - WitnessTxSigComponentRaw(tx.asInstanceOf[WitnessTransaction], - UInt32(idx), - o, - Policy.standardFlags) + WitnessTxSigComponentRaw( + tx.asInstanceOf[WitnessTransaction], + UInt32(idx), + o, + Policy.standardFlags + ) case _: UnassignedWitnessScriptPubKey | _: TaprootScriptPubKey => ??? case x @ (_: P2PKScriptPubKey | _: P2PKHScriptPubKey | @@ -681,17 +730,20 @@ trait BitcoinScriptUtil { p2shScriptSig.redeemScript match { case _: WitnessScriptPubKey => - WitnessTxSigComponentP2SH(transaction = - tx.asInstanceOf[WitnessTransaction], - inputIndex = UInt32(idx), - output = output, - flags = Policy.standardFlags) + WitnessTxSigComponentP2SH( + transaction = tx.asInstanceOf[WitnessTransaction], + inputIndex = UInt32(idx), + output = output, + flags = Policy.standardFlags + ) case _ => - BaseTxSigComponent(tx, - UInt32(idx), - output, - Policy.standardFlags) + BaseTxSigComponent( + tx, + UInt32(idx), + output, + Policy.standardFlags + ) } } @@ -705,16 +757,19 @@ trait BitcoinScriptUtil { inputMap: InputPSBTMap, index: Int, outputMap: PreviousOutputMap, - flags: Seq[ScriptFlag] = Policy.standardFlags): Try[Transaction] = { + flags: Seq[ScriptFlag] = Policy.standardFlags + ): Try[Transaction] = { val txIn = tx.inputs(index) val (preImages, condPath) = InputInfo.getHashPreImagesAndConditionalPath(tx, index) - val inputInfo = inputMap.toInputInfo(txIn, - conditionalPath = condPath, - preImages = preImages) + val inputInfo = inputMap.toInputInfo( + txIn, + conditionalPath = condPath, + preImages = preImages + ) val txSigComponent = TxSigComponent(inputInfo, tx, outputMap, flags) diff --git a/core/src/main/scala/org/bitcoins/core/util/BlockHashWithConfs.scala b/core/src/main/scala/org/bitcoins/core/util/BlockHashWithConfs.scala index d726e9ad58..049c732b99 100644 --- a/core/src/main/scala/org/bitcoins/core/util/BlockHashWithConfs.scala +++ b/core/src/main/scala/org/bitcoins/core/util/BlockHashWithConfs.scala @@ -2,9 +2,10 @@ package org.bitcoins.core.util import org.bitcoins.crypto.DoubleSha256DigestBE -/** Block hash with the number of confirmations associated with it. - * If confirmationsOpt is None, that means the block hash has zero confirmations +/** Block hash with the number of confirmations associated with it. If + * confirmationsOpt is None, that means the block hash has zero confirmations */ case class BlockHashWithConfs( blockHash: DoubleSha256DigestBE, - confirmationsOpt: Option[Int]) + confirmationsOpt: Option[Int] +) diff --git a/core/src/main/scala/org/bitcoins/core/util/BytesUtil.scala b/core/src/main/scala/org/bitcoins/core/util/BytesUtil.scala index 4c5ce24b38..1deb79c40b 100644 --- a/core/src/main/scala/org/bitcoins/core/util/BytesUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/util/BytesUtil.scala @@ -14,12 +14,14 @@ trait BytesUtil extends CryptoBytesUtil { ByteVector.concat(cmpct.bytes +: ts.map(_.bytes)) } - /** Used parse a byte sequence to a Seq[TransactionInput], Seq[TransactionOutput], etc - * Makes sure that we parse the correct amount of elements + /** Used parse a byte sequence to a Seq[TransactionInput], + * Seq[TransactionOutput], etc Makes sure that we parse the correct amount of + * elements */ def parseCmpctSizeUIntSeq[T <: NetworkElement]( bytes: ByteVector, - factory: Factory[T]): (Vector[T], ByteVector) = { + factory: Factory[T] + ): (Vector[T], ByteVector) = { val count = CompactSizeUInt.parse(bytes) val payload = bytes.drop(count.byteSize.toInt) val builder = Vector.newBuilder[T] @@ -42,7 +44,8 @@ trait BytesUtil extends CryptoBytesUtil { val result = builder.result() require( result.size == count.num.toInt, - s"Could not parse the amount of required elements, got: ${result.size} required: ${count}") + s"Could not parse the amount of required elements, got: ${result.size} required: ${count}" + ) (result, remaining) } diff --git a/core/src/main/scala/org/bitcoins/core/util/EnvUtil.scala b/core/src/main/scala/org/bitcoins/core/util/EnvUtil.scala index c9af75e8e8..96d27a3234 100644 --- a/core/src/main/scala/org/bitcoins/core/util/EnvUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/util/EnvUtil.scala @@ -22,8 +22,7 @@ object EnvUtil { secpDisabled != null && (secpDisabled.toLowerCase == "true" || secpDisabled == "1") } - /** Parses the number of commits since last tag - * Expects a string of format + /** Parses the number of commits since last tag Expects a string of format * 1.9.0-9-eddcc94b-SNAPSHOT or 1.9.0 * * If it's a release like 1.9.0, this will return None @@ -31,7 +30,7 @@ object EnvUtil { def parseCommitsSinceLastTag(version: String): Option[Int] = { val split = version.split("-") if (split.length == 1) { - //means this is a release + // means this is a release None } else { Some(split(1).toInt) diff --git a/core/src/main/scala/org/bitcoins/core/util/FutureUtil.scala b/core/src/main/scala/org/bitcoins/core/util/FutureUtil.scala index fc6e90c96f..5e8b1a887a 100644 --- a/core/src/main/scala/org/bitcoins/core/util/FutureUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/util/FutureUtil.scala @@ -9,12 +9,16 @@ object FutureUtil { /** Executes a series of futures sequentially * - * @param items The elements we want to transform into futures - * @param fun A function that transforms each element into a future - * @return The processed elements + * @param items + * The elements we want to transform into futures + * @param fun + * A function that transforms each element into a future + * @return + * The processed elements */ - def sequentially[T, U](items: Iterable[T])(fun: T => Future[U])(implicit - ec: ExecutionContext): Future[Vector[U]] = { + def sequentially[T, U]( + items: Iterable[T] + )(fun: T => Future[U])(implicit ec: ExecutionContext): Future[Vector[U]] = { val init = Future.successful(Vector.empty[U]) items.foldLeft(init) { (f, item) => f.flatMap { x => @@ -23,13 +27,17 @@ object FutureUtil { } map (_.reverse) } - /** Executes a series of futures sequentially. It's similar to [[FutureUtil.sequentially()]], - * but it accepts a collection of futures and executes them one by one. - * @param items The collection of futures - * @return The processed elements + /** Executes a series of futures sequentially. It's similar to + * [[FutureUtil.sequentially()]], but it accepts a collection of futures and + * executes them one by one. + * @param items + * The collection of futures + * @return + * The processed elements */ - def collect[T](items: Iterable[Future[T]])(implicit - ec: ExecutionContext): Future[Vector[T]] = { + def collect[T]( + items: Iterable[Future[T]] + )(implicit ec: ExecutionContext): Future[Vector[T]] = { FutureUtil.sequentially(items)(x => x) } @@ -38,13 +46,17 @@ object FutureUtil { def emptyVec[T]: Future[Vector[T]] = Future.successful(Vector.empty[T]) /** Folds over the given elements sequentially in a non-blocking async way - * @param init the initialized value for the accumulator - * @param items the items we are folding over - * @param fun the function we are applying to every element that returns a future + * @param init + * the initialized value for the accumulator + * @param items + * the items we are folding over + * @param fun + * the function we are applying to every element that returns a future * @return */ - def foldLeftAsync[T, U](init: T, items: Seq[U])(fun: (T, U) => Future[T])( - implicit ec: ExecutionContext): Future[T] = { + def foldLeftAsync[T, U](init: T, items: Seq[U])( + fun: (T, U) => Future[T] + )(implicit ec: ExecutionContext): Future[T] = { items.foldLeft(Future.successful(init)) { case (accumF, elem) => accumF.flatMap { accum => fun(accum, elem) @@ -52,15 +64,17 @@ object FutureUtil { } } - /** Takes elements, groups them into batches of 'batchSize' and then calls f on them. - * The next batch does not start executing until the first batch is finished. This does - * not aggregate result over batches, rather just returns the result of the last batch + /** Takes elements, groups them into batches of 'batchSize' and then calls f + * on them. The next batch does not start executing until the first batch is + * finished. This does not aggregate result over batches, rather just returns + * the result of the last batch */ def batchExecute[T, U]( elements: Vector[T], f: Vector[T] => Future[U], init: U, - batchSize: Int)(implicit ec: ExecutionContext): Future[U] = { + batchSize: Int + )(implicit ec: ExecutionContext): Future[U] = { val initF = Future.successful(init) val batches = elements.grouped(batchSize) for { @@ -75,13 +89,15 @@ object FutureUtil { } yield batchExecution } - /** Batches the elements by batchSize, executes f, and then aggregates all of the results - * into a vector and returns it. This is is the synchronous version of batchAndParallelExecute + /** Batches the elements by batchSize, executes f, and then aggregates all of + * the results into a vector and returns it. This is is the synchronous + * version of batchAndParallelExecute */ def batchAndSyncExecute[T, U]( elements: Vector[T], f: Vector[T] => Future[Vector[U]], - batchSize: Int)(implicit ec: ExecutionContext): Future[Vector[U]] = { + batchSize: Int + )(implicit ec: ExecutionContext): Future[Vector[U]] = { val initF = Future.successful(Vector.empty) val batches = elements.grouped(batchSize) for { @@ -108,16 +124,18 @@ object FutureUtil { resultP.future } - /** Batches the [[elements]] by [[batchSize]] and then calls [[f]] on them in parallel - * This is the parallel version of [[batchAndSyncExecute()]] + /** Batches the [[elements]] by [[batchSize]] and then calls [[f]] on them in + * parallel This is the parallel version of [[batchAndSyncExecute()]] */ def batchAndParallelExecute[T, U]( elements: Vector[T], f: Vector[T] => Future[U], - batchSize: Int)(implicit ec: ExecutionContext): Future[Vector[U]] = { + batchSize: Int + )(implicit ec: ExecutionContext): Future[Vector[U]] = { require( batchSize > 0, - s"Cannot have batch size less than or equal to zero, got=$batchSize") + s"Cannot have batch size less than or equal to zero, got=$batchSize" + ) if (elements.isEmpty) { Future.successful(Vector.empty) } else { @@ -127,14 +145,14 @@ object FutureUtil { } } - /** Same as [[batchAndParallelExecute()]], but computes the batchSize based on the - * number of available processors on your machine + /** Same as [[batchAndParallelExecute()]], but computes the batchSize based on + * the number of available processors on your machine */ def batchAndParallelExecute[T, U]( elements: Vector[T], - f: Vector[T] => Future[U])(implicit - ec: ExecutionContext): Future[Vector[U]] = { - //divide and conquer + f: Vector[T] => Future[U] + )(implicit ec: ExecutionContext): Future[Vector[U]] = { + // divide and conquer val batchSize = Math.max(elements.length / Runtime.getRuntime.availableProcessors(), 1) @@ -143,9 +161,9 @@ object FutureUtil { def getParallelism: Int = { val processors = Runtime.getRuntime.availableProcessors() - //max open requests is 32 in akka, so 1/8 of possible requests - //can be used to open http requests in akka, else just limit it be number of processors - //see: https://github.com/bitcoin-s/bitcoin-s/issues/4252 + // max open requests is 32 in akka, so 1/8 of possible requests + // can be used to open http requests in akka, else just limit it be number of processors + // see: https://github.com/bitcoin-s/bitcoin-s/issues/4252 Math.min(4, processors) } } diff --git a/core/src/main/scala/org/bitcoins/core/util/HDUtil.scala b/core/src/main/scala/org/bitcoins/core/util/HDUtil.scala index 351bdfde86..f25992bb87 100644 --- a/core/src/main/scala/org/bitcoins/core/util/HDUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/util/HDUtil.scala @@ -9,7 +9,8 @@ object HDUtil { /** Gets the xpriv version required for the given HD purpose */ def getXprivVersion( hdPurpose: HDPurpose, - network: NetworkParameters): ExtKeyPrivVersion = { + network: NetworkParameters + ): ExtKeyPrivVersion = { import org.bitcoins.core.crypto.ExtKeyVersion._ import org.bitcoins.core.hd.HDPurposes._ @@ -34,7 +35,8 @@ object HDUtil { /** Gets the xpub version required for the given HD purpose */ def getXpubVersion( hdPurpose: HDPurpose, - network: NetworkParameters): ExtKeyPubVersion = { + network: NetworkParameters + ): ExtKeyPubVersion = { import org.bitcoins.core.hd.HDPurposes._ (hdPurpose, network) match { diff --git a/core/src/main/scala/org/bitcoins/core/util/Indexed.scala b/core/src/main/scala/org/bitcoins/core/util/Indexed.scala index 9c9606cc7e..a7c79720c0 100644 --- a/core/src/main/scala/org/bitcoins/core/util/Indexed.scala +++ b/core/src/main/scala/org/bitcoins/core/util/Indexed.scala @@ -8,11 +8,12 @@ object Indexed { vec.zipWithIndex.map { case (elem, index) => Indexed(elem, index) } } - /** Takes in a given vector of T's with their corresponding index - * and returns a Vector[Indexed[T]]. + /** Takes in a given vector of T's with their corresponding index and returns + * a Vector[Indexed[T]]. * - * This is useful in situations where you want to preserve the initial - * index in a set of elements, but have performed subsequent collection operations (like .filter, .filterNot, .collect etc) + * This is useful in situations where you want to preserve the initial index + * in a set of elements, but have performed subsequent collection operations + * (like .filter, .filterNot, .collect etc) */ def fromGivenIndex[T](vec: Vector[(T, Int)]): Vector[Indexed[T]] = { vec.map { case (t, idx) => Indexed(t, idx) } diff --git a/core/src/main/scala/org/bitcoins/core/util/NetworkUtil.scala b/core/src/main/scala/org/bitcoins/core/util/NetworkUtil.scala index 50abdfb153..9986b8ee15 100644 --- a/core/src/main/scala/org/bitcoins/core/util/NetworkUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/util/NetworkUtil.scala @@ -23,7 +23,8 @@ abstract class NetworkUtil { */ def parseInetSocketAddress( address: String, - defaultPort: => Int): InetSocketAddress = { + defaultPort: => Int + ): InetSocketAddress = { val uri = new URI("tcp://" + address) val port = if (uri.getPort < 0) defaultPort else uri.getPort InetSocketAddress.createUnresolved(uri.getHost, port) @@ -32,7 +33,8 @@ abstract class NetworkUtil { /** Parses IPV4,IPV6 ad TorV3 address bytes to string address */ def parseInetSocketAddress( address: ByteVector, - port: Int): InetSocketAddress = { + port: Int + ): InetSocketAddress = { val uri: URI = { address.size match { case AddrV2Message.IPV4_ADDR_LENGTH => @@ -48,7 +50,8 @@ abstract class NetworkUtil { new URI("tcp://" + hostAddress) case unknownSize => sys.error( - s"Attempted to parse InetSocketAddress with unknown size, got=${unknownSize}") + s"Attempted to parse InetSocketAddress with unknown size, got=${unknownSize}" + ) } } InetSocketAddress.createUnresolved(uri.getHost, port) @@ -66,7 +69,8 @@ abstract class NetworkUtil { .bytes val address = ByteVector( - pubkey ++ checksum.take(2).toArray ++ version).toBase32 + ".onion" + pubkey ++ checksum.take(2).toArray ++ version + ).toBase32 + ".onion" address.toLowerCase } @@ -87,8 +91,9 @@ abstract class NetworkUtil { /** Checks if the [[java.net.InetSocketAddress]] is a loopback address. * - * @return a boolean indicating if the [[java.net.InetSocketAddress]] is - * a loopback address; or false otherwise. + * @return + * a boolean indicating if the [[java.net.InetSocketAddress]] is a loopback + * address; or false otherwise. */ def isLoopbackAddress(socketAddress: InetSocketAddress): Boolean = { try { @@ -109,8 +114,9 @@ abstract class NetworkUtil { /** Checks if the [[java.net.URI]] is pointing to a loopback address. * - * @return a boolean indicating if the [[java.net.URI]] is - * a loopback address; or false otherwise. + * @return + * a boolean indicating if the [[java.net.URI]] is a loopback address; or + * false otherwise. */ def isLoopbackAddress(uri: URI): Boolean = { try { @@ -151,35 +157,45 @@ abstract class NetworkUtil { } } - /** Checks if the given block header is stale relative to the given chain parameters + /** Checks if the given block header is stale relative to the given chain + * parameters * - * @see [[https://github.com/bitcoin/bitcoin/blob/664500fc71a32d5066db8cb4a19ddc7005a1c9e9/src/net_processing.cpp#L1235]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/664500fc71a32d5066db8cb4a19ddc7005a1c9e9/src/net_processing.cpp#L1235]] */ def isBlockHeaderStale( blockHeader: BlockHeader, - chainParams: ChainParams): Boolean = { + chainParams: ChainParams + ): Boolean = { val seconds = blockHeader.time.toLong val expected: Duration = chainParams.powTargetSpacing * 3 (Instant.now.getEpochSecond - seconds) > expected.toSeconds } - /** Akka sends messages as one byte stream. There is not a 1 to 1 relationship between byte streams received and - * bitcoin protocol messages. This function parses our byte stream into individual network messages + /** Akka sends messages as one byte stream. There is not a 1 to 1 relationship + * between byte streams received and bitcoin protocol messages. This function + * parses our byte stream into individual network messages * - * @param bytes the bytes that need to be parsed into individual messages - * @return the parsed [[NetworkMessage]]'s and the unaligned bytes that did not parse to a message + * @param bytes + * the bytes that need to be parsed into individual messages + * @return + * the parsed [[NetworkMessage]]'s and the unaligned bytes that did not + * parse to a message */ def parseIndividualMessages( - bytes: ByteVector): (Vector[NetworkMessage], ByteVector) = { + bytes: ByteVector + ): (Vector[NetworkMessage], ByteVector) = { @tailrec def loop( remainingBytes: ByteVector, - accum: Vector[NetworkMessage]): (Vector[NetworkMessage], ByteVector) = { + accum: Vector[NetworkMessage] + ): (Vector[NetworkMessage], ByteVector) = { if (remainingBytes.length <= 0) { (accum, remainingBytes) } else { val headerTry = Try( - NetworkHeader.fromBytes(remainingBytes.take(NetworkHeader.bytesSize))) + NetworkHeader.fromBytes(remainingBytes.take(NetworkHeader.bytesSize)) + ) headerTry match { case Success(header) => val payloadBytes = remainingBytes @@ -206,9 +222,9 @@ abstract class NetworkUtil { (accum, remainingBytes) } case Failure(_) => - //this case means that our TCP frame was not aligned with bitcoin protocol - //return the unaligned bytes so we can apply them to the next tcp frame of bytes we receive - //http://stackoverflow.com/a/37979529/967713 + // this case means that our TCP frame was not aligned with bitcoin protocol + // return the unaligned bytes so we can apply them to the next tcp frame of bytes we receive + // http://stackoverflow.com/a/37979529/967713 (accum, remainingBytes) } } diff --git a/core/src/main/scala/org/bitcoins/core/util/NumberUtil.scala b/core/src/main/scala/org/bitcoins/core/util/NumberUtil.scala index d9ad15836c..84dead4047 100644 --- a/core/src/main/scala/org/bitcoins/core/util/NumberUtil.scala +++ b/core/src/main/scala/org/bitcoins/core/util/NumberUtil.scala @@ -19,7 +19,8 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { def pow2(exponent: Int): BigInt = { require( exponent < 64, - "We cannot have anything larger than 2^64 - 1 in a long, you tried to do 2^" + exponent) + "We cannot have anything larger than 2^64 - 1 in a long, you tried to do 2^" + exponent + ) BigInt(1) << exponent } @@ -44,7 +45,8 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { from: UInt32, to: UInt32, pad: Boolean, - f: UInt8 => To): Try[Vector[To]] = { + f: UInt8 => To + ): Try[Vector[To]] = { var acc: UInt32 = UInt32.zero var bits: UInt32 = UInt32.zero val ret = Vector.newBuilder[To] @@ -54,12 +56,15 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { if (from > eight || to > eight) { Failure( new IllegalArgumentException( - "Can't have convert bits 'from' or 'to' parameter greater than 8")) + "Can't have convert bits 'from' or 'to' parameter greater than 8" + ) + ) } else { data.map { h: UInt8 => if ((h >> fromU8.toInt) != UInt8.zero) { Failure( - new IllegalArgumentException("Invalid input for bech32: " + h)) + new IllegalArgumentException("Invalid input for bech32: " + h) + ) } else { acc = (acc << from) | UInt32(h.toLong) bits = bits + from @@ -89,7 +94,8 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { from: UInt32, to: UInt32, pad: Boolean, - f: Byte => T): Try[Vector[T]] = { + f: Byte => T + ): Try[Vector[T]] = { val wrapperF: UInt8 => T = { u8: UInt8 => f(UInt8.toByte(u8)) } @@ -108,32 +114,38 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { def convertUInt5sToUInt8( u5s: Vector[UInt5], - pad: Boolean = false): Vector[UInt8] = { + pad: Boolean = false + ): Vector[UInt8] = { val u8s = u5s.map(_.toUInt8) val u8sTry = - NumberUtil.convert[UInt8](u8s, - UInt32(5), - UInt32(8), - pad = pad, - { u8: UInt8 => - u8 - }) - //should always be able to convert from uint5 => uint8 + NumberUtil.convert[UInt8]( + u8s, + UInt32(5), + UInt32(8), + pad = pad, + { u8: UInt8 => + u8 + } + ) + // should always be able to convert from uint5 => uint8 u8sTry.get } - /** Expands the [[org.bitcoins.core.protocol.blockchain.BlockHeader.nBits nBits]] - * field given in a block header to the _actual_ target difficulty. - * @see [[https://bitcoin.org/en/developer-reference#target-nbits developer reference]] - * for more information + /** Expands the + * [[org.bitcoins.core.protocol.blockchain.BlockHeader.nBits nBits]] field + * given in a block header to the _actual_ target difficulty. + * @see + * [[https://bitcoin.org/en/developer-reference#target-nbits developer reference]] + * for more information * * Meant to replicate this function in bitcoin core - * @see [[https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.cpp#L206]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.cpp#L206]] * @param nBits * @return */ def targetExpansion(nBits: UInt32): BlockHeader.TargetDifficultyHelper = { - //mantissa bytes without sign bit + // mantissa bytes without sign bit val noSignificand = nBits.bytes.takeRight(3) val mantissaBytes = { val withSignBit = noSignificand @@ -143,7 +155,7 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { val significand = nBits.bytes.head - //if the most significant bit is set, we have a negative number + // if the most significant bit is set, we have a negative number val signum = if (noSignificand.bits.head) { -1 } else { @@ -152,14 +164,14 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { val mantissa = new BigInteger(signum, mantissaBytes.toArray) - //guards against a negative exponent, in which case we just shift right - //see bitcoin core implementation + // guards against a negative exponent, in which case we just shift right + // see bitcoin core implementation val result = { if (significand <= 3) { val exp = 8 * (3 - significand) - //avoid shift right, because of weird behavior on the jvm - //https://stackoverflow.com/questions/47519140/bitwise-shift-right-with-long-not-equaling-zero/47519728#47519728 + // avoid shift right, because of weird behavior on the jvm + // https://stackoverflow.com/questions/47519140/bitwise-shift-right-with-long-not-equaling-zero/47519728#47519728 mantissa.divide(NumberUtil.pow2(exp).bigInteger) } else { val exponent = significand - 3 @@ -173,13 +185,13 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { val nWord = BigInt(mantissa) val nSize = nBits.toBigInt / NumberUtil.pow2(24) val isNegative: Boolean = { - //*pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; + // *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; nWordNotZero && (nBits & UInt32(0x00800000L)) != UInt32.zero } val isOverflow: Boolean = { - //nWord != 0 && ((nSize > 34) || + // nWord != 0 && ((nSize > 34) || // (nWord > 0xff && nSize > 33) || // (nWord > 0xffff && nSize > 32)); @@ -191,8 +203,10 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { BlockHeader.TargetDifficultyHelper(result.abs(), isNegative, isOverflow) } - /** Compressed the big integer to be used inside of [[org.bitcoins.core.protocol.blockchain.BlockHeader.nBits]] - * @see [[https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.cpp#L226 bitcoin core implementation]] + /** Compressed the big integer to be used inside of + * [[org.bitcoins.core.protocol.blockchain.BlockHeader.nBits]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.cpp#L226 bitcoin core implementation]] * @param bigInteger * @return */ @@ -202,10 +216,10 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { val negativeFlag = UInt32(0x00800000L) - //emulates bits() in arith_uin256.h - //Returns the position of the highest bit set plus one, or zero if the - //value is zero. - //https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.h#L241 + // emulates bits() in arith_uin256.h + // Returns the position of the highest bit set plus one, or zero if the + // value is zero. + // https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.h#L241 var size: Int = if (bigInteger == BigInteger.ZERO) { 0 } else { @@ -215,10 +229,10 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { var compact: UInt32 = { if (size <= 3) { // GetLow64() << 8 * (3 - nSize); - //note: counter intuitively, the expression + // note: counter intuitively, the expression // 8 * (3 - nSize) - //gets evaluated before we apply the shift left operator - //verified this property with g++ + // gets evaluated before we apply the shift left operator + // verified this property with g++ val shiftAmount = 8 * (3 - size) val u64 = toUnsignedInt(bitVec.takeRight(64).toByteArray).bigInteger @@ -226,7 +240,7 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { UInt32.fromBytes(ByteVector(u64.toByteArray)) } else { - //8 * (nSize - 3) + // 8 * (nSize - 3) val shiftAmount = 8 * (size - 3) val bn = bigInteger.shiftRight(shiftAmount) val bytes = bn.toByteArray.takeRight(4) @@ -234,16 +248,18 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { } } - //The 0x00800000 bit denotes the sign. + // The 0x00800000 bit denotes the sign. // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. if ((compact & negativeFlag) != UInt32.zero) { compact = compact >> 8 size = size + 1 } - //~0x007fffff = 0xff800000 - require((compact & UInt32(0xff800000L)) == UInt32.zero, - s"Exponent/sign bit must not be set yet in compact encoding") + // ~0x007fffff = 0xff800000 + require( + (compact & UInt32(0xff800000L)) == UInt32.zero, + s"Exponent/sign bit must not be set yet in compact encoding" + ) require(size < 256, "Size of compact encoding can't be more than 2^256") compact = compact | UInt32(size << 24) @@ -267,8 +283,10 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { targetCompression(difficultyHelper.difficulty, difficultyHelper.isNegative) } - /** Implements this check for overflowing for [[org.bitcoins.core.protocol.blockchain.BlockHeader.nBits]] - * @see [[https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.cpp#L220 bitcoin core check]] + /** Implements this check for overflowing for + * [[org.bitcoins.core.protocol.blockchain.BlockHeader.nBits]] + * @see + * [[https://github.com/bitcoin/bitcoin/blob/2068f089c8b7b90eb4557d3f67ea0f0ed2059a23/src/arith_uint256.cpp#L220 bitcoin core check]] * @param nBits * @return */ @@ -296,8 +314,9 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { Math.abs(scala.util.Random.nextInt()) } - /** Decomposes the input num into a list of numDigits digits in the given base. - * The output Vector has the most significant digit first and the 1's place last. + /** Decomposes the input num into a list of numDigits digits in the given + * base. The output Vector has the most significant digit first and the 1's + * place last. */ def decompose(num: Long, base: Int, numDigits: Int): Vector[Int] = { var currentNum: Long = num @@ -312,8 +331,8 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { backwardsDigits.reverse } - /** Recomposes the input digits into the number they represent. - * The input Vector has the most significant digit first and the 1's place last. + /** Recomposes the input digits into the number they represent. The input + * Vector has the most significant digit first and the 1's place last. */ def fromDigits(digits: Vector[Int], base: Int, numDigits: Int): Long = { def pow(base: Long, exp: Long): Long = { @@ -335,11 +354,12 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { } /** Returns a pseudorandom, uniformly distributed long value between 0 - * (inclusive) and the specified value (exclusive), drawn from this - * random number generator's sequence. + * (inclusive) and the specified value (exclusive), drawn from this random + * number generator's sequence. * - * Stolen from scala.util.Random.nextLong (in scala version 2.13) - * @see https://github.com/scala/scala/blob/4aae0b91cd266f02b9f3d911db49381a300b5103/src/library/scala/util/Random.scala#L131 + * Stolen from scala.util.Random.nextLong (in scala version 2.13) + * @see + * https://github.com/scala/scala/blob/4aae0b91cd266f02b9f3d911db49381a300b5103/src/library/scala/util/Random.scala#L131 */ def randomLong(bound: Long): Long = { require(bound > 0, "bound must be positive") @@ -375,7 +395,8 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { } def lexicographicalOrdering[T](implicit - ord: Ordering[T]): Ordering[Vector[T]] = { + ord: Ordering[T] + ): Ordering[Vector[T]] = { new Ordering[Vector[T]] { override def compare(x: Vector[T], y: Vector[T]): Int = { val xe = x.iterator @@ -392,7 +413,8 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { } /** Stolen from Scala 2.13 IndexedSeq::binarySearch - * @see https://github.com/scala/scala/blob/4aae0b91cd266f02b9f3d911db49381a300b5103/src/library/scala/collection/IndexedSeq.scala#L117 + * @see + * https://github.com/scala/scala/blob/4aae0b91cd266f02b9f3d911db49381a300b5103/src/library/scala/collection/IndexedSeq.scala#L117 */ @tailrec final def search[A, B >: A, Wrapper]( @@ -400,7 +422,8 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { elem: B, from: Int, to: Int, - unwrap: Wrapper => A)(implicit ord: Ordering[B]): Int = { + unwrap: Wrapper => A + )(implicit ord: Ordering[B]): Int = { if (from < 0) search(seq, elem, from = 0, to, unwrap) else if (to > seq.length) search(seq, elem, from, seq.length, unwrap) else if (to <= from) from @@ -417,17 +440,20 @@ sealed abstract class NumberUtil extends CryptoNumberUtil { def search[A, B >: A, Wrapper]( seq: IndexedSeq[Wrapper], elem: B, - unwrap: Wrapper => A)(implicit ord: Ordering[B]): Int = { + unwrap: Wrapper => A + )(implicit ord: Ordering[B]): Int = { search(seq, elem, from = 0, to = seq.length, unwrap) } def search[A, B >: A](seq: IndexedSeq[A], elem: B, from: Int, to: Int)( - implicit ord: Ordering[B]): Int = { + implicit ord: Ordering[B] + ): Int = { search(seq, elem, from, to, identity[A]) } def search[A, B >: A](seq: IndexedSeq[A], elem: B)(implicit - ord: Ordering[B]): Int = { + ord: Ordering[B] + ): Int = { search(seq, elem, from = 0, to = seq.length) } } diff --git a/core/src/main/scala/org/bitcoins/core/util/StartStop.scala b/core/src/main/scala/org/bitcoins/core/util/StartStop.scala index 9def7259a9..569db3b440 100644 --- a/core/src/main/scala/org/bitcoins/core/util/StartStop.scala +++ b/core/src/main/scala/org/bitcoins/core/util/StartStop.scala @@ -1,8 +1,8 @@ package org.bitcoins.core.util -/** This StartStop trait will be used by methods that require broad start stop methods. - * Provides structure for new clients to implement. For the async version please see - * [[StartStopAsync]] +/** This StartStop trait will be used by methods that require broad start stop + * methods. Provides structure for new clients to implement. For the async + * version please see [[StartStopAsync]] * @tparam T */ trait StartStop[T] { diff --git a/core/src/main/scala/org/bitcoins/core/util/StartStopAsync.scala b/core/src/main/scala/org/bitcoins/core/util/StartStopAsync.scala index 54614da52b..28c45f27f7 100644 --- a/core/src/main/scala/org/bitcoins/core/util/StartStopAsync.scala +++ b/core/src/main/scala/org/bitcoins/core/util/StartStopAsync.scala @@ -2,7 +2,7 @@ package org.bitcoins.core.util import scala.concurrent.Future -/** Provide a uniform trait to start/stop a service asynchrously. For synchronous starts - * and stops please see [[StartStop]] +/** Provide a uniform trait to start/stop a service asynchrously. For + * synchronous starts and stops please see [[StartStop]] */ trait StartStopAsync[T] extends StartStop[Future[T]] diff --git a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedAnnouncements.scala b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedAnnouncements.scala index 49cb811d4a..7cb47dff3c 100644 --- a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedAnnouncements.scala +++ b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedAnnouncements.scala @@ -2,20 +2,22 @@ package org.bitcoins.core.util.sorted import org.bitcoins.core.protocol.tlv._ -/** Represents an ordered set of OracleAnnouncementTLVs - * The ordering represents the ranked preference of the user +/** Represents an ordered set of OracleAnnouncementTLVs The ordering represents + * the ranked preference of the user */ case class OrderedAnnouncements(vec: Vector[OracleAnnouncementTLV]) extends SortedVec[OracleAnnouncementTLV, OracleAnnouncementTLV]( vec, - SortedVec.forOrdered(vec)) { + SortedVec.forOrdered(vec) + ) { require(vec.nonEmpty, s"Cannot have empty OrderedAnnouncements") } -/** Represents an ordered set of OracleAnnouncementV0TLV - * The ordering represents the ranked preference of the user +/** Represents an ordered set of OracleAnnouncementV0TLV The ordering represents + * the ranked preference of the user */ case class OrderedAnnouncementV0s(vec: Vector[OracleAnnouncementV0TLV]) extends SortedVec[OracleAnnouncementV0TLV, OracleAnnouncementV0TLV]( vec, - SortedVec.forOrdered(vec)) + SortedVec.forOrdered(vec) + ) diff --git a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedDLCPayoutCurvePieces.scala b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedDLCPayoutCurvePieces.scala index a01fb81cbd..6923f341b8 100644 --- a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedDLCPayoutCurvePieces.scala +++ b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedDLCPayoutCurvePieces.scala @@ -3,21 +3,24 @@ package org.bitcoins.core.util.sorted import org.bitcoins.core.protocol.dlc.models.DLCPayoutCurvePiece case class OrderedDLCPayoutCurvePieces( - private val vec: Vector[DLCPayoutCurvePiece]) - extends SortedVec[DLCPayoutCurvePiece, DLCPayoutCurvePiece]( + private val vec: Vector[DLCPayoutCurvePiece] +) extends SortedVec[DLCPayoutCurvePiece, DLCPayoutCurvePiece]( vec, - org.bitcoins.core.dlcPayoutCurvePieceOrdering) + org.bitcoins.core.dlcPayoutCurvePieceOrdering + ) object OrderedDLCPayoutCurvePieces extends SortedVecFactory[DLCPayoutCurvePiece, OrderedDLCPayoutCurvePieces] { override def apply( - piece: DLCPayoutCurvePiece): OrderedDLCPayoutCurvePieces = { + piece: DLCPayoutCurvePiece + ): OrderedDLCPayoutCurvePieces = { OrderedDLCPayoutCurvePieces(Vector(piece)) } override def fromUnsorted( - vec: Vector[DLCPayoutCurvePiece]): OrderedDLCPayoutCurvePieces = { + vec: Vector[DLCPayoutCurvePiece] + ): OrderedDLCPayoutCurvePieces = { val sorted = vec.sorted(org.bitcoins.core.dlcPayoutCurvePieceOrdering) OrderedDLCPayoutCurvePieces(sorted) } diff --git a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedNonces.scala b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedNonces.scala index 2dd1f4df68..3ee287c777 100644 --- a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedNonces.scala +++ b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedNonces.scala @@ -6,7 +6,8 @@ import org.bitcoins.crypto.SchnorrNonce case class OrderedNonces(private val vec: Vector[SchnorrNonce]) extends SortedVec[SchnorrNonce, SchnorrNonce]( vec, - org.bitcoins.core.nonceOrdering) + org.bitcoins.core.nonceOrdering + ) object OrderedNonces extends SortedVecFactory[SchnorrNonce, OrderedNonces] { diff --git a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedSchnorrSignatures.scala b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedSchnorrSignatures.scala index 592459131e..8b2f47dc82 100644 --- a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedSchnorrSignatures.scala +++ b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedSchnorrSignatures.scala @@ -3,22 +3,25 @@ package org.bitcoins.core.util.sorted import org.bitcoins.crypto.SchnorrDigitalSignature case class OrderedSchnorrSignatures( - private val vec: Vector[SchnorrDigitalSignature]) - extends SortedVec[SchnorrDigitalSignature, SchnorrDigitalSignature]( + private val vec: Vector[SchnorrDigitalSignature] +) extends SortedVec[SchnorrDigitalSignature, SchnorrDigitalSignature]( vec, - org.bitcoins.core.schnorrSignatureOrdering) + org.bitcoins.core.schnorrSignatureOrdering + ) object OrderedSchnorrSignatures extends SortedVecFactory[ SchnorrDigitalSignature, - OrderedSchnorrSignatures] { + OrderedSchnorrSignatures + ] { override def apply(sig: SchnorrDigitalSignature): OrderedSchnorrSignatures = { OrderedSchnorrSignatures(Vector(sig)) } def fromUnsorted( - vec: Vector[SchnorrDigitalSignature]): OrderedSchnorrSignatures = { + vec: Vector[SchnorrDigitalSignature] + ): OrderedSchnorrSignatures = { val sorted = vec.sorted(org.bitcoins.core.schnorrSignatureOrdering) OrderedSchnorrSignatures(sorted) } diff --git a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedTLVPoints.scala b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedTLVPoints.scala index ccfaa9a350..5ec9b3ec9b 100644 --- a/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedTLVPoints.scala +++ b/core/src/main/scala/org/bitcoins/core/util/sorted/OrderedTLVPoints.scala @@ -3,8 +3,10 @@ package org.bitcoins.core.util.sorted import org.bitcoins.core.protocol.tlv.TLVPoint case class OrderedTLVPoints(private val vec: Vector[TLVPoint]) - extends SortedVec[TLVPoint, TLVPoint](vec, - org.bitcoins.core.tlvPointOrdering) + extends SortedVec[TLVPoint, TLVPoint]( + vec, + org.bitcoins.core.tlvPointOrdering + ) object OrderedTLVPoints extends SortedVecFactory[TLVPoint, OrderedTLVPoints] { diff --git a/core/src/main/scala/org/bitcoins/core/util/sorted/SortedVec.scala b/core/src/main/scala/org/bitcoins/core/util/sorted/SortedVec.scala index 8fe51f5da0..b0a725e2d4 100644 --- a/core/src/main/scala/org/bitcoins/core/util/sorted/SortedVec.scala +++ b/core/src/main/scala/org/bitcoins/core/util/sorted/SortedVec.scala @@ -9,12 +9,14 @@ import org.bitcoins.core.util.SeqWrapper */ abstract class SortedVec[T, B >: T]( override val wrapped: Vector[T], - ord: Ordering[B]) - extends SeqWrapper[T] { - require(wrapped.isEmpty || wrapped.init.zip(wrapped.tail).forall { - case (x, y) => ord.lteq(x, y) - }, - s"Vector must be sorted. $wrapped") + ord: Ordering[B] +) extends SeqWrapper[T] { + require( + wrapped.isEmpty || wrapped.init.zip(wrapped.tail).forall { case (x, y) => + ord.lteq(x, y) + }, + s"Vector must be sorted. $wrapped" + ) } object SortedVec { @@ -26,16 +28,18 @@ object SortedVec { } private case class SortedVecImpl[T, B >: T](vec: Vector[T])(implicit - val ord: Ordering[B]) - extends SortedVec[T, B](vec, ord) + val ord: Ordering[B] + ) extends SortedVec[T, B](vec, ord) - def sort[T, B >: T](vec: Vector[T])(implicit - ord: Ordering[B]): SortedVec[T, B] = { + def sort[T, B >: T]( + vec: Vector[T] + )(implicit ord: Ordering[B]): SortedVec[T, B] = { SortedVecImpl(vec.sorted[B]) } - def apply[T, B >: T](vec: Vector[T])(implicit - ord: Ordering[B]): SortedVec[T, B] = { + def apply[T, B >: T]( + vec: Vector[T] + )(implicit ord: Ordering[B]): SortedVec[T, B] = { SortedVecImpl(vec) } } diff --git a/core/src/main/scala/org/bitcoins/core/wallet/builder/FinalizedTxWithSigningInfo.scala b/core/src/main/scala/org/bitcoins/core/wallet/builder/FinalizedTxWithSigningInfo.scala index 57dcfd6ea2..1dae260a40 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/builder/FinalizedTxWithSigningInfo.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/builder/FinalizedTxWithSigningInfo.scala @@ -9,7 +9,8 @@ import org.bitcoins.core.wallet.utxo.{InputInfo, ScriptSignatureParams} */ case class FinalizedTxWithSigningInfo( finalizedTx: Transaction, - infos: Vector[ScriptSignatureParams[InputInfo]]) { + infos: Vector[ScriptSignatureParams[InputInfo]] +) { def sign(expectedFeeRate: FeeUnit): Transaction = { RawTxSigner.sign(this, expectedFeeRate) @@ -19,7 +20,9 @@ case class FinalizedTxWithSigningInfo( expectedFeeRate: FeeUnit, invariants: ( Vector[ScriptSignatureParams[InputInfo]], - Transaction) => Boolean): Transaction = { + Transaction + ) => Boolean + ): Transaction = { RawTxSigner.sign(this, expectedFeeRate, invariants) } } diff --git a/core/src/main/scala/org/bitcoins/core/wallet/builder/FundRawTxHelper.scala b/core/src/main/scala/org/bitcoins/core/wallet/builder/FundRawTxHelper.scala index 87a8f9fe01..086a9428d2 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/builder/FundRawTxHelper.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/builder/FundRawTxHelper.scala @@ -10,7 +10,8 @@ case class FundRawTxHelper[T <: RawTxFinalizer]( txBuilderWithFinalizer: RawTxBuilderWithFinalizer[T], scriptSigParams: Vector[ScriptSignatureParams[InputInfo]], feeRate: FeeUnit, - reservedUTXOsCallbackF: Future[Unit]) { + reservedUTXOsCallbackF: Future[Unit] +) { /** Produces the unsigned transaction built by fundrawtransaction */ def unsignedTx: Transaction = txBuilderWithFinalizer.buildTx() diff --git a/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxBuilder.scala b/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxBuilder.scala index a33dc3da8e..372fe1ca53 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxBuilder.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxBuilder.scala @@ -11,16 +11,16 @@ import scala.collection.mutable * - A version number (default is [[TransactionConstants.validLockVersion]]) * - A lock time (default is [[TransactionConstants.lockTime]]) * - * At a high level, RawTxBuilder is responsible only for the funding inputs - * and logical outputs (outputs that are intended by this transaction, and not + * At a high level, RawTxBuilder is responsible only for the funding inputs and + * logical outputs (outputs that are intended by this transaction, and not * outputs computed from the logical outputs such as change outputs, which are * the responsibility of the RawTxFinalizer) of a transaction. * - * RawTxBuilder supports inline calls to += and ++= for adding inputs - * and outputs. Note that RawTxBuilder respects the order in which inputs - * and outputs are added when generating a RawTxBuilderResult. If you wish - * to have some other (computed) order, this is the responsibility of either - * the calling code (to add in the correct order) or of the RawTxFinalizer which + * RawTxBuilder supports inline calls to += and ++= for adding inputs and + * outputs. Note that RawTxBuilder respects the order in which inputs and + * outputs are added when generating a RawTxBuilderResult. If you wish to have + * some other (computed) order, this is the responsibility of either the + * calling code (to add in the correct order) or of the RawTxFinalizer which * may alter the order of inputs and outputs (and should only do so if it is * clearly documented that this will occur, otherwise it is safe to assume that * RawTxFinalizers will not alter the order of inputs and outputs). @@ -29,39 +29,42 @@ import scala.collection.mutable * RawTransactionFinalizer, call the result method to receive a * [[RawTxBuilderResult]] which can be passed into [[RawTxFinalizer.buildTx]]. * - * If you have access to a finalizer before you are ready to call result, - * you may call the setFinalizer method to receive an instance of type - * [[RawTxBuilderWithFinalizer]] which is described below, and where - * you may continue to build and then call buildTx directly. + * If you have access to a finalizer before you are ready to call result, you + * may call the setFinalizer method to receive an instance of type + * [[RawTxBuilderWithFinalizer]] which is described below, and where you may + * continue to build and then call buildTx directly. * * Note: RawTxBuilder is not thread safe. */ case class RawTxBuilder() { private var version: Int32 = TransactionConstants.validLockVersion - private val inputsBuilder: mutable.Builder[ - TransactionInput, - Vector[TransactionInput]] = Vector.newBuilder + private val inputsBuilder + : mutable.Builder[TransactionInput, Vector[TransactionInput]] = + Vector.newBuilder - private val outputsBuilder: mutable.Builder[ - TransactionOutput, - Vector[TransactionOutput]] = Vector.newBuilder + private val outputsBuilder + : mutable.Builder[TransactionOutput, Vector[TransactionOutput]] = + Vector.newBuilder private var lockTime: UInt32 = TransactionConstants.lockTime /** Returns a RawTxBuilderResult ready for a RawTxFinalizer. */ def result(): RawTxBuilderResult = { - RawTxBuilderResult(version, - inputsBuilder.result(), - outputsBuilder.result(), - lockTime) + RawTxBuilderResult( + version, + inputsBuilder.result(), + outputsBuilder.result(), + lockTime + ) } - /** Returns a RawTxBuilderWithFinalizer where building can continue - * and where buildTx can be called once building is completed. + /** Returns a RawTxBuilderWithFinalizer where building can continue and where + * buildTx can be called once building is completed. */ def setFinalizer[F <: RawTxFinalizer]( - finalizer: F): RawTxBuilderWithFinalizer[F] = { + finalizer: F + ): RawTxBuilderWithFinalizer[F] = { RawTxBuilderWithFinalizer(this, finalizer) } @@ -73,8 +76,9 @@ case class RawTxBuilder() { lockTime = TransactionConstants.lockTime } - /** Adds a TransactionInput to be the next input. No ScriptSignature is required - * and any given ScriptSignature will be ignored (we recommend EmptyScriptSignature). + /** Adds a TransactionInput to be the next input. No ScriptSignature is + * required and any given ScriptSignature will be ignored (we recommend + * EmptyScriptSignature). */ def addInput(input: TransactionInput): this.type = { inputsBuilder += input @@ -90,9 +94,9 @@ case class RawTxBuilder() { /** Adds a TransactionOuput to be the next output. * - * Note that outputs like a change - * output which are computed from other inputs and outputs should not be added here - * and are instead the responsibility of the RawTxFinalizer. + * Note that outputs like a change output which are computed from other + * inputs and outputs should not be added here and are instead the + * responsibility of the RawTxFinalizer. */ def addOutput(output: TransactionOutput): this.type = { outputsBuilder += output @@ -106,11 +110,12 @@ case class RawTxBuilder() { this } - /** Adds a collection of inputs and/or outputs to the - * input and/or output lists + /** Adds a collection of inputs and/or outputs to the input and/or output + * lists */ @inline final def ++=[T >: TransactionInput with TransactionOutput]( - inputsOrOutputs: Iterable[T]): this.type = { + inputsOrOutputs: Iterable[T] + ): this.type = { val vec = inputsOrOutputs.iterator.toVector val inputs = vec.collect { case input: TransactionInput => input @@ -138,14 +143,14 @@ case class RawTxBuilder() { /** Wraps a RawTxBuilder and RawTxFinalizer pair. * - * Provides access to builder methods for continuing - * to collect inputs and outputs and also offers direct - * access to the RawTxFinalizer's buildTx method which - * completes the RawTxBuilder and then finalized the result. + * Provides access to builder methods for continuing to collect inputs and + * outputs and also offers direct access to the RawTxFinalizer's buildTx method + * which completes the RawTxBuilder and then finalized the result. */ case class RawTxBuilderWithFinalizer[F <: RawTxFinalizer]( builder: RawTxBuilder, - finalizer: F) { + finalizer: F +) { /** Completes the builder and finalizes the result */ def buildTx(): Transaction = { @@ -167,7 +172,8 @@ case class RawTxBuilderWithFinalizer[F <: RawTxFinalizer]( } @inline final def ++=[T >: TransactionInput with TransactionOutput]( - inputsOrOutputs: Iterable[T]): this.type = { + inputsOrOutputs: Iterable[T] + ): this.type = { builder ++= inputsOrOutputs this } diff --git a/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxBuilderResult.scala b/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxBuilderResult.scala index f2c7bc3e24..dc38fef2a1 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxBuilderResult.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxBuilderResult.scala @@ -15,7 +15,8 @@ case class RawTxBuilderResult( version: Int32, inputs: Vector[TransactionInput], outputs: Vector[TransactionOutput], - lockTime: UInt32) { + lockTime: UInt32 +) { def toBaseTransaction: BaseTransaction = { BaseTransaction(version, inputs, outputs, lockTime) @@ -29,9 +30,11 @@ case class RawTxBuilderResult( object RawTxBuilderResult { def fromTransaction(tx: Transaction): RawTxBuilderResult = { - RawTxBuilderResult(tx.version, - tx.inputs.toVector, - tx.outputs.toVector, - tx.lockTime) + RawTxBuilderResult( + tx.version, + tx.inputs.toVector, + tx.outputs.toVector, + tx.lockTime + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxFinalizer.scala b/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxFinalizer.scala index 198a4c0e24..635068b86b 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxFinalizer.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxFinalizer.scala @@ -10,34 +10,35 @@ import org.bitcoins.core.wallet.utxo.{InputInfo, InputSigningInfo} import scala.util.{Failure, Random, Success, Try} -/** This trait is responsible for converting RawTxBuilderResults into - * finalized (unsigned) transactions. This process usually includes - * such things as computation on inputs and outputs to generate - * things like change outputs, or to reorder inputs or outputs. +/** This trait is responsible for converting RawTxBuilderResults into finalized + * (unsigned) transactions. This process usually includes such things as + * computation on inputs and outputs to generate things like change outputs, or + * to reorder inputs or outputs. * - * Once a transaction is done being finalized, its txid/wtxid should - * not change as the RawTxSigner's only responsibility is adding signature - * data not included in the txid/wtxid. + * Once a transaction is done being finalized, its txid/wtxid should not change + * as the RawTxSigner's only responsibility is adding signature data not + * included in the txid/wtxid. * - * RawTxFinalizer may (but is not required to) generate witness data - * other than signatures (i.e. public keys for P2WPKH and redeem scripts - * for P2WSH). RawTxFinalizer may not otherwise populate any other kind - * of script signature or witness data. + * RawTxFinalizer may (but is not required to) generate witness data other than + * signatures (i.e. public keys for P2WPKH and redeem scripts for P2WSH). + * RawTxFinalizer may not otherwise populate any other kind of script signature + * or witness data. * - * RawTxFinalizers are compose-able through the andThen method which will - * turn the first RawTxFinalizer's finalized transaction into a RawTxBuilderResult - * by taking that transactions inputs (in order), outputs (in order), locktime and - * version and this RawTxBuilderResult is then given to the second RawTxFinalizer. + * RawTxFinalizers are compose-able through the andThen method which will turn + * the first RawTxFinalizer's finalized transaction into a RawTxBuilderResult + * by taking that transactions inputs (in order), outputs (in order), locktime + * and version and this RawTxBuilderResult is then given to the second + * RawTxFinalizer. */ trait RawTxFinalizer { /** Constructs a finalized (unsigned) transaction */ def buildTx(txBuilderResult: RawTxBuilderResult): Transaction - /** The result of buildTx is converted into a RawTxBuilderResult - * by taking that transactions inputs (in order), outputs (in order), - * locktime and version and this RawTxBuilderResult is then passed to - * the other RawTxFinalizer's buildTx + /** The result of buildTx is converted into a RawTxBuilderResult by taking + * that transactions inputs (in order), outputs (in order), locktime and + * version and this RawTxBuilderResult is then passed to the other + * RawTxFinalizer's buildTx */ def andThen(other: RawTxFinalizer): RawTxFinalizer = { // this.buildTx above gets shadowed below, so this allows us to call it @@ -61,8 +62,8 @@ abstract class FinalizerFactory[T <: RawTxFinalizer] { utxos: Seq[InputSigningInfo[InputInfo]], feeRate: FeeUnit, changeSPK: ScriptPubKey, - defaultSequence: UInt32 = Policy.sequence): RawTxBuilderWithFinalizer[ - T] = { + defaultSequence: UInt32 = Policy.sequence + ): RawTxBuilderWithFinalizer[T] = { val inputs = InputUtil.calcSequenceForInputs(utxos, defaultSequence) val lockTime = TxUtil.calcLockTime(utxos).get val builder = RawTxBuilder().setLockTime(lockTime) ++= outputs ++= inputs @@ -75,13 +76,15 @@ abstract class FinalizerFactory[T <: RawTxFinalizer] { def txFinalizerFrom( inputs: Vector[InputInfo], feeRate: FeeUnit, - changeSPK: ScriptPubKey): T + changeSPK: ScriptPubKey + ): T def txFrom( outputs: Seq[TransactionOutput], utxos: Seq[InputSigningInfo[InputInfo]], feeRate: FeeUnit, - changeSPK: ScriptPubKey): Transaction = { + changeSPK: ScriptPubKey + ): Transaction = { val builder = txBuilderFrom(outputs, utxos, feeRate, changeSPK) builder.buildTx() @@ -101,7 +104,8 @@ object RawFinalizerFactory extends FinalizerFactory[RawFinalizer.type] { override def txFinalizerFrom( inputs: Vector[InputInfo], feeRate: FeeUnit, - changeSPK: ScriptPubKey): RawFinalizer.type = { + changeSPK: ScriptPubKey + ): RawFinalizer.type = { RawFinalizer } @@ -111,8 +115,8 @@ object RawFinalizerFactory extends FinalizerFactory[RawFinalizer.type] { lockTime: UInt32, feeRate: FeeUnit, changeSPK: ScriptPubKey, - defaultSequence: UInt32 = Policy.sequence): RawTxBuilderWithFinalizer[ - RawFinalizer.type] = { + defaultSequence: UInt32 = Policy.sequence + ): RawTxBuilderWithFinalizer[RawFinalizer.type] = { val inputs = InputUtil.calcSequenceForInputs(utxos, defaultSequence) val builder = RawTxBuilder().setLockTime(lockTime) ++= outputs ++= inputs val finalizer = @@ -126,7 +130,8 @@ object RawFinalizerFactory extends FinalizerFactory[RawFinalizer.type] { utxos: Seq[InputSigningInfo[InputInfo]], lockTime: UInt32, feeRate: FeeUnit, - changeSPK: ScriptPubKey): Transaction = { + changeSPK: ScriptPubKey + ): Transaction = { val builder = txBuilderWithLockTimeFrom(outputs, utxos, lockTime, feeRate, changeSPK) @@ -134,8 +139,8 @@ object RawFinalizerFactory extends FinalizerFactory[RawFinalizer.type] { } } -/** A simple finalizer that only removes outputs beneath the dust - * threshold and does nothing else +/** A simple finalizer that only removes outputs beneath the dust threshold and + * does nothing else */ case object FilterDustFinalizer extends RawTxFinalizer { @@ -153,8 +158,10 @@ case object BIP69Finalizer extends RawTxFinalizer { val sortedInputs = txBuilderResult.inputs.sorted val sortedOutputs = txBuilderResult.outputs.sorted - txBuilderResult.toBaseTransaction.copy(inputs = sortedInputs, - outputs = sortedOutputs) + txBuilderResult.toBaseTransaction.copy( + inputs = sortedInputs, + outputs = sortedOutputs + ) } } @@ -165,17 +172,19 @@ case class SanityCheckFinalizer( inputInfos: Vector[InputInfo], expectedOutputSPKs: Vector[ScriptPubKey], expectedFeeRate: FeeUnit, - changeSPKs: Vector[ScriptPubKey] = Vector.empty) - extends RawTxFinalizer { + changeSPKs: Vector[ScriptPubKey] = Vector.empty +) extends RawTxFinalizer { override def buildTx(txBuilderResult: RawTxBuilderResult): Transaction = { val tx = txBuilderResult.toBaseTransaction val passInOutChecksT = - SanityCheckFinalizer.sanityDestinationChecks(inputInfos.map(_.outPoint), - expectedOutputSPKs, - changeSPKs, - tx) + SanityCheckFinalizer.sanityDestinationChecks( + inputInfos.map(_.outPoint), + expectedOutputSPKs, + changeSPKs, + tx + ) val passChecksT = passInOutChecksT.flatMap { _ => TxUtil.sanityChecks(isSigned = false, inputInfos, expectedFeeRate, tx) @@ -190,19 +199,20 @@ case class SanityCheckFinalizer( object SanityCheckFinalizer { - /** Checks that a finalized transaction contains the expected - * inputs and scriptpubkeys. + /** Checks that a finalized transaction contains the expected inputs and + * scriptpubkeys. * - * Note that it is not responsible for checking output values - * or that change isn't dropped (as it can be dust). That is - * covered by TxUtil.sanityChecks above + * Note that it is not responsible for checking output values or that change + * isn't dropped (as it can be dust). That is covered by TxUtil.sanityChecks + * above */ def sanityDestinationChecks( expectedOutPoints: Vector[TransactionOutPoint], expectedOutputSPKs: Vector[ScriptPubKey], changeSPKs: Vector[ScriptPubKey], - finalizedTx: Transaction): Try[Unit] = { - //make sure we send coins to the appropriate destinations + finalizedTx: Transaction + ): Try[Unit] = { + // make sure we send coins to the appropriate destinations val finalizedSPKs = finalizedTx.outputs.map(_.scriptPubKey) val isMissingDestination = !expectedOutputSPKs.forall(finalizedSPKs.contains) @@ -226,14 +236,14 @@ object SanityCheckFinalizer { } } -/** A finalizer which performs fee estimation and adds a - * change output resulting in the expected fee. +/** A finalizer which performs fee estimation and adds a change output resulting + * in the expected fee. */ case class ChangeFinalizer( inputInfos: Vector[InputInfo], feeRate: FeeUnit, - changeSPK: ScriptPubKey) - extends RawTxFinalizer { + changeSPK: ScriptPubKey +) extends RawTxFinalizer { override def buildTx(txBuilderResult: RawTxBuilderResult): Transaction = { val outputsWithDummyChange = @@ -266,13 +276,12 @@ case class ChangeFinalizer( } } -/** A finalizer which adds only the witness data included in the - * wtxid (pubkey in P2WPKH and redeem script in p2sh). +/** A finalizer which adds only the witness data included in the wtxid (pubkey + * in P2WPKH and redeem script in p2sh). * - * Note that when used in composition with other finalizers, - * if AddWitnessDataFinalizer is not last then its effects - * will be reversed since witness data is not currently kept - * between finalizers during composition. + * Note that when used in composition with other finalizers, if + * AddWitnessDataFinalizer is not last then its effects will be reversed since + * witness data is not currently kept between finalizers during composition. */ case class AddWitnessDataFinalizer(inputInfos: Vector[InputInfo]) extends RawTxFinalizer { @@ -299,15 +308,15 @@ case class AddWitnessDataFinalizer(inputInfos: Vector[InputInfo]) } } -/** A finalizer which adds a change output, performs sanity checks, - * and adds non-signature witness data. This is the standard - * non-interactive finalizer within the Bitcoin-S wallet. +/** A finalizer which adds a change output, performs sanity checks, and adds + * non-signature witness data. This is the standard non-interactive finalizer + * within the Bitcoin-S wallet. */ case class StandardNonInteractiveFinalizer( inputInfos: Vector[InputInfo], feeRate: FeeUnit, - changeSPK: ScriptPubKey) - extends RawTxFinalizer { + changeSPK: ScriptPubKey +) extends RawTxFinalizer { override def buildTx(txBuilderResult: RawTxBuilderResult): Transaction = { val addChange = ChangeFinalizer(inputInfos, feeRate, changeSPK) @@ -316,7 +325,8 @@ case class StandardNonInteractiveFinalizer( inputInfos = inputInfos, expectedOutputSPKs = txBuilderResult.outputs.map(_.scriptPubKey), expectedFeeRate = feeRate, - changeSPKs = Vector(changeSPK)) + changeSPKs = Vector(changeSPK) + ) val addWitnessData = AddWitnessDataFinalizer(inputInfos) @@ -333,20 +343,21 @@ object StandardNonInteractiveFinalizer override def txFinalizerFrom( inputs: Vector[InputInfo], feeRate: FeeUnit, - changeSPK: ScriptPubKey): StandardNonInteractiveFinalizer = { + changeSPK: ScriptPubKey + ): StandardNonInteractiveFinalizer = { StandardNonInteractiveFinalizer(inputs, feeRate, changeSPK) } } -/** A finalizer which adds a change output, performs sanity checks, - * shuffles inputs and outputs, and adds non-signature witness data. - * This is the standard non-interactive finalizer within the Bitcoin-S wallet. +/** A finalizer which adds a change output, performs sanity checks, shuffles + * inputs and outputs, and adds non-signature witness data. This is the + * standard non-interactive finalizer within the Bitcoin-S wallet. */ case class ShufflingNonInteractiveFinalizer( inputInfos: Vector[InputInfo], feeRate: FeeUnit, - changeSPK: ScriptPubKey) - extends RawTxFinalizer { + changeSPK: ScriptPubKey +) extends RawTxFinalizer { override def buildTx(txBuilderResult: RawTxBuilderResult): Transaction = { val addChange = ChangeFinalizer(inputInfos, feeRate, changeSPK) @@ -360,11 +371,12 @@ case class ShufflingNonInteractiveFinalizer( .map(input => inputInfos.find(_.outPoint == input.previousOutput).get) val sanityCheck = - SanityCheckFinalizer(inputInfos = shuffledInputInfos, - expectedOutputSPKs = - tempTxBuilderResult.outputs.map(_.scriptPubKey), - expectedFeeRate = feeRate, - changeSPKs = Vector(changeSPK)) + SanityCheckFinalizer( + inputInfos = shuffledInputInfos, + expectedOutputSPKs = tempTxBuilderResult.outputs.map(_.scriptPubKey), + expectedFeeRate = feeRate, + changeSPKs = Vector(changeSPK) + ) sanityCheck .andThen(AddWitnessDataFinalizer(shuffledInputInfos)) @@ -378,23 +390,23 @@ object ShufflingNonInteractiveFinalizer override def txFinalizerFrom( inputs: Vector[InputInfo], feeRate: FeeUnit, - changeSPK: ScriptPubKey): ShufflingNonInteractiveFinalizer = { + changeSPK: ScriptPubKey + ): ShufflingNonInteractiveFinalizer = { ShufflingNonInteractiveFinalizer(inputs, feeRate, changeSPK) } } -/** Adds a an amount to the output with the given ScriptPubKey - * and subtracts that amount in equal proportions from the specified - * change ScriptPubKeys. +/** Adds a an amount to the output with the given ScriptPubKey and subtracts + * that amount in equal proportions from the specified change ScriptPubKeys. * - * This can be useful when you want to account for a future spending - * fee in this transaction to get nice output values on the spending tx. + * This can be useful when you want to account for a future spending fee in + * this transaction to get nice output values on the spending tx. */ case class AddFutureFeeFinalizer( spk: ScriptPubKey, futureFee: CurrencyUnit, - changeSPKs: Vector[ScriptPubKey]) - extends RawTxFinalizer { + changeSPKs: Vector[ScriptPubKey] +) extends RawTxFinalizer { override def buildTx(txBuilderResult: RawTxBuilderResult): Transaction = { val changeOutputs = txBuilderResult.outputs.filter(output => @@ -406,8 +418,11 @@ case class AddFutureFeeFinalizer( val newOutput = output.copy(value = output.value + futureFee) Success((newOutput, index)) case None => - Failure(new RuntimeException( - s"Did not find expected SPK $spk in ${txBuilderResult.outputs.map(_.scriptPubKey)}")) + Failure( + new RuntimeException( + s"Did not find expected SPK $spk in ${txBuilderResult.outputs.map(_.scriptPubKey)}" + ) + ) } val outputsT = outputT.map { case (newOutput, index) => @@ -435,10 +450,10 @@ case class AddFutureFeeFinalizer( } } -/** Subtracts the given fee from the output with the given ScriptPubKey. - * This can be useful if you are constructing a transaction without - * considering fees and have some after-the-fact external formula for - * computing fees and they need the removed. +/** Subtracts the given fee from the output with the given ScriptPubKey. This + * can be useful if you are constructing a transaction without considering fees + * and have some after-the-fact external formula for computing fees and they + * need the removed. */ case class SubtractFromOutputFinalizer(spk: ScriptPubKey, subAmt: CurrencyUnit) extends RawTxFinalizer { @@ -452,20 +467,21 @@ case class SubtractFromOutputFinalizer(spk: ScriptPubKey, subAmt: CurrencyUnit) txBuilderResult.toBaseTransaction.copy(outputs = newOutputs) case None => throw new RuntimeException( - s"Did not find expected SPK $spk in ${txBuilderResult.outputs.map(_.scriptPubKey)}") + s"Did not find expected SPK $spk in ${txBuilderResult.outputs.map(_.scriptPubKey)}" + ) } } } -/** Assumes the input transaction has had no fee considerations - * and subtracts the estimated fee in equal portions from the - * outputs with the specified ScriptPubKeys +/** Assumes the input transaction has had no fee considerations and subtracts + * the estimated fee in equal portions from the outputs with the specified + * ScriptPubKeys */ case class SubtractFeeFromOutputsFinalizer( inputInfos: Vector[InputInfo], feeRate: FeeUnit, - spks: Vector[ScriptPubKey]) - extends RawTxFinalizer { + spks: Vector[ScriptPubKey] +) extends RawTxFinalizer { override def buildTx(txBuilderResult: RawTxBuilderResult): Transaction = { val dummyTx = @@ -487,7 +503,8 @@ object SubtractFeeFromOutputsFinalizer { def subtractFees( tx: Transaction, feeRate: FeeUnit, - spks: Vector[ScriptPubKey]): Vector[TransactionOutput] = { + spks: Vector[ScriptPubKey] + ): Vector[TransactionOutput] = { val fee = feeRate.calc(tx) val (outputs, unchangedOutputs) = @@ -499,12 +516,16 @@ object SubtractFeeFromOutputsFinalizer { val feeRemainder = Satoshis(Int64(fee.satoshis.toLong % outputs.length)) val newOutputsWithoutRemainder = outputs.map { case (output, index) => - (TransactionOutput(output.value - feePerOutput, output.scriptPubKey), - index) + ( + TransactionOutput(output.value - feePerOutput, output.scriptPubKey), + index + ) } val (lastOutput, lastOutputIndex) = newOutputsWithoutRemainder.last - val newLastOutput = TransactionOutput(lastOutput.value - feeRemainder, - lastOutput.scriptPubKey) + val newLastOutput = TransactionOutput( + lastOutput.value - feeRemainder, + lastOutput.scriptPubKey + ) val newOutputs = newOutputsWithoutRemainder .dropRight(1) .:+((newLastOutput, lastOutputIndex)) @@ -515,15 +536,16 @@ object SubtractFeeFromOutputsFinalizer { case class DualFundingInput( scriptSignature: ScriptSignature, - maxWitnessLen: Int) + maxWitnessLen: Int +) -/** Finalizes a dual-funded transaction given the DualFundingInputs - * from both parties, their change spks and the funding scriptpubkey - * for the dual funded protocol. +/** Finalizes a dual-funded transaction given the DualFundingInputs from both + * parties, their change spks and the funding scriptpubkey for the dual funded + * protocol. * - * This includes adding the future fee of spending transactions - * to the funding output as well as subtracting relevant fees - * from the change outputs. This finalizer filters dust outputs. + * This includes adding the future fee of spending transactions to the funding + * output as well as subtracting relevant fees from the change outputs. This + * finalizer filters dust outputs. */ case class DualFundingTxFinalizer( offerInputs: Vector[DualFundingInput], @@ -533,14 +555,17 @@ case class DualFundingTxFinalizer( acceptPayoutSPK: ScriptPubKey, acceptChangeSPK: ScriptPubKey, feeRate: SatoshisPerVirtualByte, - fundingSPK: ScriptPubKey) - extends RawTxFinalizer { + fundingSPK: ScriptPubKey +) extends RawTxFinalizer { - /** @see https://github.com/discreetlogcontracts/dlcspecs/blob/8ee4bbe816c9881c832b1ce320b9f14c72e3506f/Transactions.md#fees */ + /** @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/8ee4bbe816c9881c832b1ce320b9f14c72e3506f/Transactions.md#fees + */ private def computeFees( inputs: Vector[DualFundingInput], payoutSPK: ScriptPubKey, - changeSPK: ScriptPubKey): (CurrencyUnit, CurrencyUnit) = { + changeSPK: ScriptPubKey + ): (CurrencyUnit, CurrencyUnit) = { // https://github.com/discreetlogcontracts/dlcspecs/blob/8ee4bbe816c9881c832b1ce320b9f14c72e3506f/Transactions.md#expected-weight-of-the-contract-execution-or-refund-transaction val futureFeeWeight = 249 + 4 * payoutSPK.asmBytes.length val futureFeeVBytes = Math.ceil(futureFeeWeight / 4.0).toLong @@ -573,9 +598,11 @@ case class DualFundingTxFinalizer( override def buildTx(txBuilderResult: RawTxBuilderResult): Transaction = { val addOfferFutureFee = AddFutureFeeFinalizer(fundingSPK, offerFutureFee, Vector(offerChangeSPK)) - val addAcceptFutureFee = AddFutureFeeFinalizer(fundingSPK, - acceptFutureFee, - Vector(acceptChangeSPK)) + val addAcceptFutureFee = AddFutureFeeFinalizer( + fundingSPK, + acceptFutureFee, + Vector(acceptChangeSPK) + ) val subtractOfferFundingFee = SubtractFromOutputFinalizer(offerChangeSPK, offerFundingFee) val subtractAcceptFundingFee = diff --git a/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxSigner.scala b/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxSigner.scala index ebfc689075..6659170652 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxSigner.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/builder/RawTxSigner.scala @@ -11,57 +11,65 @@ import org.bitcoins.core.wallet.utxo.{ UnassignedSegwitNativeInputInfo } -/** Transactions that have been finalized by a RawTxFinalizer are passed as inputs - * to a sign function here in order to generate fully signed transactions. +/** Transactions that have been finalized by a RawTxFinalizer are passed as + * inputs to a sign function here in order to generate fully signed + * transactions. * * In the future sign methods specific to multi-party protocols will be added - * here to support PSBT and signed transaction construction between multiple parties. + * here to support PSBT and signed transaction construction between multiple + * parties. */ object RawTxSigner { - val emptyInvariant: ( - Vector[ScriptSignatureParams[InputInfo]], - Transaction) => Boolean = (_, _) => true + val emptyInvariant + : (Vector[ScriptSignatureParams[InputInfo]], Transaction) => Boolean = + (_, _) => true - def feeInvariant(expectedFeeRate: FeeUnit): ( - Vector[ScriptSignatureParams[InputInfo]], - Transaction) => Boolean = + def feeInvariant( + expectedFeeRate: FeeUnit + ): (Vector[ScriptSignatureParams[InputInfo]], Transaction) => Boolean = addFeeRateInvariant(expectedFeeRate, emptyInvariant) private def addFeeRateInvariant( expectedFeeRate: FeeUnit, userInvariants: ( Vector[ScriptSignatureParams[InputInfo]], - Transaction) => Boolean): ( - Vector[ScriptSignatureParams[InputInfo]], - Transaction) => Boolean = { (utxoInfos, signedTx) => - { - userInvariants(utxoInfos, signedTx) && - TxUtil - .sanityChecks(isSigned = true, - inputInfos = utxoInfos.map(_.inputInfo), - expectedFeeRate = expectedFeeRate, - tx = signedTx) - .isSuccess - } + Transaction + ) => Boolean + ): (Vector[ScriptSignatureParams[InputInfo]], Transaction) => Boolean = { + (utxoInfos, signedTx) => + { + userInvariants(utxoInfos, signedTx) && + TxUtil + .sanityChecks( + isSigned = true, + inputInfos = utxoInfos.map(_.inputInfo), + expectedFeeRate = expectedFeeRate, + tx = signedTx + ) + .isSuccess + } } def sign( utx: Transaction, - utxoInfos: Vector[ScriptSignatureParams[InputInfo]]): Transaction = { + utxoInfos: Vector[ScriptSignatureParams[InputInfo]] + ): Transaction = { sign(utx, utxoInfos, emptyInvariant, dummySign = false) } def sign( txWithInfo: FinalizedTxWithSigningInfo, - expectedFeeRate: FeeUnit): Transaction = { + expectedFeeRate: FeeUnit + ): Transaction = { sign(txWithInfo.finalizedTx, txWithInfo.infos, expectedFeeRate) } def sign( utx: Transaction, utxoInfos: Vector[ScriptSignatureParams[InputInfo]], - expectedFeeRate: FeeUnit): Transaction = { + expectedFeeRate: FeeUnit + ): Transaction = { val invariants = feeInvariant(expectedFeeRate) @@ -74,7 +82,9 @@ object RawTxSigner { expectedFeeRate: FeeUnit, userInvariants: ( Vector[ScriptSignatureParams[InputInfo]], - Transaction) => Boolean): Transaction = { + Transaction + ) => Boolean + ): Transaction = { val invariants = addFeeRateInvariant(expectedFeeRate, userInvariants) @@ -86,14 +96,18 @@ object RawTxSigner { expectedFeeRate: FeeUnit, userInvariants: ( Vector[ScriptSignatureParams[InputInfo]], - Transaction) => Boolean): Transaction = { + Transaction + ) => Boolean + ): Transaction = { val invariants = addFeeRateInvariant(expectedFeeRate, userInvariants) - sign(txWithInfo.finalizedTx, - txWithInfo.infos, - invariants, - dummySign = false) + sign( + txWithInfo.finalizedTx, + txWithInfo.infos, + invariants, + dummySign = false + ) } def sign( @@ -101,21 +115,29 @@ object RawTxSigner { utxoInfos: Vector[ScriptSignatureParams[InputInfo]], invariants: ( Vector[ScriptSignatureParams[InputInfo]], - Transaction) => Boolean, - dummySign: Boolean): Transaction = { + Transaction + ) => Boolean, + dummySign: Boolean + ): Transaction = { require( utxoInfos.length == utx.inputs.length, - s"Must provide exactly one UTXOSatisfyingInfo per input, ${utxoInfos.length} != ${utx.inputs.length}") - require(utxoInfos.distinct.length == utxoInfos.length, - "All UTXOSatisfyingInfos must be unique. ") - require(utxoInfos.forall(utxo => - utx.inputs.exists(_.previousOutput == utxo.outPoint)), - "All UTXOSatisfyingInfos must correspond to an input.") + s"Must provide exactly one UTXOSatisfyingInfo per input, ${utxoInfos.length} != ${utx.inputs.length}" + ) + require( + utxoInfos.distinct.length == utxoInfos.length, + "All UTXOSatisfyingInfos must be unique. " + ) + require( + utxoInfos.forall(utxo => + utx.inputs.exists(_.previousOutput == utxo.outPoint)), + "All UTXOSatisfyingInfos must correspond to an input." + ) val signedTx = if ( utxoInfos.exists( - _.inputInfo.isInstanceOf[UnassignedSegwitNativeInputInfo]) + _.inputInfo.isInstanceOf[UnassignedSegwitNativeInputInfo] + ) ) { throw TxBuilderError.NoSigner.exception } else { @@ -150,11 +172,13 @@ object RawTxSigner { txWitness match { case EmptyWitness(_) => btx case _: TransactionWitness => - WitnessTransaction(btx.version, - btx.inputs, - btx.outputs, - btx.lockTime, - txWitness) + WitnessTransaction( + btx.version, + btx.inputs, + btx.outputs, + btx.lockTime, + txWitness + ) } } diff --git a/core/src/main/scala/org/bitcoins/core/wallet/builder/TxBuilderError.scala b/core/src/main/scala/org/bitcoins/core/wallet/builder/TxBuilderError.scala index 4ed93f87c8..2bf1fa27b8 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/builder/TxBuilderError.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/builder/TxBuilderError.scala @@ -4,73 +4,101 @@ import org.bitcoins.core.protocol.transaction.TransactionOutput import scala.util.Failure -/** Represents an error that can be returned by the [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]] - * if it failed to sign a set of utxos +/** Represents an error that can be returned by the + * [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]] if it failed to + * sign a set of utxos */ sealed abstract class TxBuilderError object TxBuilderError { - /** This error indicates that the transaction failed to pass the invariants the user wanted to hold - * true after the signing process was complete. An example of this is the transaction is too big, - * or the fee level was too high or low. + /** This error indicates that the transaction failed to pass the invariants + * the user wanted to hold true after the signing process was complete. An + * example of this is the transaction is too big, or the fee level was too + * high or low. */ val FailedUserInvariants = Failure( new IllegalArgumentException( - "This tx fails the invariants function you passed in")) + "This tx fails the invariants function you passed in" + ) + ) - /** Means that we gave too many [[org.bitcoins.crypto.Sign Sign]] for the TxBuilder - * to use during the signing process for a utxo. - * An example of this occurring is if we gave 2 private keys to sign a p2pkh spk. - * A p2pkh only requires one private key to sign the utxo. + /** Means that we gave too many [[org.bitcoins.crypto.Sign Sign]] for the + * TxBuilder to use during the signing process for a utxo. An example of this + * occurring is if we gave 2 private keys to sign a p2pkh spk. A p2pkh only + * requires one private key to sign the utxo. */ val TooManySigners = Failure( new IllegalArgumentException( - "You passed in too many signers for this scriptPubKey type")) + "You passed in too many signers for this scriptPubKey type" + ) + ) - /** Means that you are using the wrong [[org.bitcoins.core.wallet.signer.Signer Signer]] to - * sign the given [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] + /** Means that you are using the wrong + * [[org.bitcoins.core.wallet.signer.Signer Signer]] to sign the given + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] */ - val WrongSigner = Failure(new IllegalArgumentException( - "You did not pass in the write Signer to sign the given transaction, you probably gave the wrong identifier")) + val WrongSigner = Failure( + new IllegalArgumentException( + "You did not pass in the write Signer to sign the given transaction, you probably gave the wrong identifier" + ) + ) - /** Means that the [[org.bitcoins.core.protocol.script.ScriptWitnessV0 ScriptWitnessV0]] you passed as an argument does - * not hash to the commitment inside of [[org.bitcoins.core.protocol.script.P2WSHWitnessSPKV0 P2WSHWitnessSPKV0]] + /** Means that the + * [[org.bitcoins.core.protocol.script.ScriptWitnessV0 ScriptWitnessV0]] you + * passed as an argument does not hash to the commitment inside of + * [[org.bitcoins.core.protocol.script.P2WSHWitnessSPKV0 P2WSHWitnessSPKV0]] */ - val WrongWitness = Failure(new IllegalArgumentException( - "You passed in the wrong ScriptWitness type to sign the given WitnessScriptPubKey")) + val WrongWitness = Failure( + new IllegalArgumentException( + "You passed in the wrong ScriptWitness type to sign the given WitnessScriptPubKey" + ) + ) - /** Means that the redeem script you passed as an argument does not hash to the commitment - * inside of the [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] + /** Means that the redeem script you passed as an argument does not hash to + * the commitment inside of the + * [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] */ - val WrongRedeemScript = Failure(new IllegalArgumentException( - "Means that the redeem script you passed as an argument does not hash to the commitment")) + val WrongRedeemScript = Failure( + new IllegalArgumentException( + "Means that the redeem script you passed as an argument does not hash to the commitment" + ) + ) /** Means that you passed the wrong public key for a - * [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey P2PKHScriptPubKey]] or a - * [[org.bitcoins.core.protocol.script.P2WPKHWitnessSPKV0 P2WPKHWitnessSPKV0]] that you are trying to spend + * [[org.bitcoins.core.protocol.script.P2PKHScriptPubKey P2PKHScriptPubKey]] + * or a + * [[org.bitcoins.core.protocol.script.P2WPKHWitnessSPKV0 P2WPKHWitnessSPKV0]] + * that you are trying to spend */ - //case object WrongPublicKey extends TxBuilderError + // case object WrongPublicKey extends TxBuilderError val WrongPublicKey = Failure( new IllegalArgumentException( - "You passed in the wrong public key to sign a P2PKHScriptPubKey")) + "You passed in the wrong public key to sign a P2PKHScriptPubKey" + ) + ) /** Can occurr when we are trying to sign a - * [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] but - * we do not have a redeem script for that p2sh spk. + * [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] + * but we do not have a redeem script for that p2sh spk. */ - //case object NoRedeemScript extends TxBuilderError + // case object NoRedeemScript extends TxBuilderError val NoRedeemScript = Failure( new IllegalArgumentException( - "We are missing a redeem script to sign a transaction")) + "We are missing a redeem script to sign a transaction" + ) + ) /** Can occurr when we are trying to sign a * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] - * but we do not have a [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] for that witness spk + * but we do not have a + * [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] for that + * witness spk */ - //case object NoWitness extends TxBuilderError + // case object NoWitness extends TxBuilderError val NoWitness = Failure( - new IllegalArgumentException("We are missing a witness redeem script")) + new IllegalArgumentException("We are missing a witness redeem script") + ) /** We expected a * [[org.bitcoins.core.protocol.script.WitnessScriptPubKeyV0 WitnessScriptPubKeyV0]], @@ -78,107 +106,142 @@ object TxBuilderError { */ val NonWitnessSPK = Failure( new IllegalArgumentException( - "We expected a witness spk, but got a non witness spk")) + "We expected a witness spk, but got a non witness spk" + ) + ) /** We cannot have a - * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] nested inside of another + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] + * nested inside of another * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] */ - //case object NestedWitnessSPK extends TxBuilderError + // case object NestedWitnessSPK extends TxBuilderError val NestedWitnessSPK = Failure( - new IllegalArgumentException("We cannot nested witness SPKs")) + new IllegalArgumentException("We cannot nested witness SPKs") + ) - /** We cannot have a [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] + /** We cannot have a + * [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] * nested inside of another spk */ val NestedP2SHSPK = Failure( - new IllegalArgumentException("We cannot sign nested P2SHScriptPubKeys")) + new IllegalArgumentException("We cannot sign nested P2SHScriptPubKeys") + ) /** Means that there is no signer defined for the given - * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] type. - * An example of a spk with no signer that is defined is + * [[org.bitcoins.core.protocol.script.ScriptPubKey ScriptPubKey]] type. An + * example of a spk with no signer that is defined is * [[org.bitcoins.core.protocol.script.WitnessCommitment WitnessCommitment]] */ val NoSigner = Failure( new IllegalArgumentException( - "We have no means to sign the given scriptpubkey")) + "We have no means to sign the given scriptpubkey" + ) + ) - /** Means that you specified a fee that was too large for the change output you provided. - * This may happen if you have a transaction with a lot of inputs, or the change output you provided - * is a output that contains a very small amount of bitcoin. + /** Means that you specified a fee that was too large for the change output + * you provided. This may happen if you have a transaction with a lot of + * inputs, or the change output you provided is a output that contains a very + * small amount of bitcoin. */ val FeeToLarge = Failure(new IllegalArgumentException("Fee too large")) /** Means that the * [[org.bitcoins.core.wallet.builder.TxBuilder.destinations TxBuilder.destinations]] - * outputs you specified when creating the [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]] are NOT - * all included in the final signed tx + * outputs you specified when creating the + * [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]] are NOT all + * included in the final signed tx */ val MissingDestinationOutput = Failure( new IllegalArgumentException( - "Lost a transaction output in the finalizing process")) + "Lost a transaction output in the finalizing process" + ) + ) - /** Means that the script we are signing for requires a public key, but we did not pass one in - * as a parameter inside of [[org.bitcoins.crypto.Sign Sign]] + /** Means that the script we are signing for requires a public key, but we did + * not pass one in as a parameter inside of [[org.bitcoins.crypto.Sign Sign]] */ val MissingPublicKey = Failure( new IllegalArgumentException( - "You did not pass in a public key to sign a P2PKHScriptPubKey with")) + "You did not pass in a public key to sign a P2PKHScriptPubKey with" + ) + ) - //case object MissingOutPoint extends TxBuilderError + // case object MissingOutPoint extends TxBuilderError val MissingOutPoint = Failure( - new IllegalArgumentException("We cannot this outpoint in the utxo map")) + new IllegalArgumentException("We cannot this outpoint in the utxo map") + ) - /** Means that the signed version of this transaction has MORE outputs than what was specified - * when building the [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]]. - * [[org.bitcoins.core.wallet.builder.TxBuilder.destinations TxBuilder.destinations]] && - * [[org.bitcoins.core.wallet.builder.TxBuilder.changeSPK TxBuilder.changeSPK]] should - * be the only outputs in the signedTx + /** Means that the signed version of this transaction has MORE outputs than + * what was specified when building the + * [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]]. + * [[org.bitcoins.core.wallet.builder.TxBuilder.destinations TxBuilder.destinations]] + * && + * [[org.bitcoins.core.wallet.builder.TxBuilder.changeSPK TxBuilder.changeSPK]] + * should be the only outputs in the signedTx */ - val ExtraOutputsAdded = Failure(new IllegalArgumentException( - "More outputs were added to the transaction than were initally passed in")) + val ExtraOutputsAdded = Failure( + new IllegalArgumentException( + "More outputs were added to the transaction than were initally passed in" + ) + ) - /** Means that the transaction spends outpoints that were not given when creating - * the [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]], aka, we should - * only spend outpoints in + /** Means that the transaction spends outpoints that were not given when + * creating the [[org.bitcoins.core.wallet.builder.TxBuilder TxBuilder]], + * aka, we should only spend outpoints in * [[org.bitcoins.core.wallet.builder.TxBuilder.outPoints TxBuilder.outPoints]] */ - val ExtraOutPoints = Failure(new IllegalArgumentException( - "Means that the transaction spends outpoints that were not given when creating the TxBuilder")) + val ExtraOutPoints = Failure( + new IllegalArgumentException( + "Means that the transaction spends outpoints that were not given when creating the TxBuilder" + ) + ) /** Means that this transaction attempts to print satoshis out of thin air */ - val MintsMoney = Failure(new IllegalArgumentException( - "This transaction creates spends more money than it was funded by the given utxos")) + val MintsMoney = Failure( + new IllegalArgumentException( + "This transaction creates spends more money than it was funded by the given utxos" + ) + ) /** Means that the fee was too low for * [[org.bitcoins.core.wallet.builder.TxBuilder.feeRate TxBuilder.feeRate]] */ val LowFee = Failure( - new IllegalArgumentException("Means that the fee was too low")) + new IllegalArgumentException("Means that the fee was too low") + ) /** Means tha this transaction pays too high of a fee for * [[org.bitcoins.core.wallet.builder.TxBuilder.feeRate TxBuilder.feeRate]] */ val HighFee = Failure( - new IllegalArgumentException("Means that the fee was too high")) + new IllegalArgumentException("Means that the fee was too high") + ) /** Indicates we are spending multiple * [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]], - * and that one of those spk's outputs are locked by block height, while the other is locked by - * a time stamp. Since there is only one locktime field on a transaction, we cannot satisfy both of these - * locktimes simultaneously. + * and that one of those spk's outputs are locked by block height, while the + * other is locked by a time stamp. Since there is only one locktime field on + * a transaction, we cannot satisfy both of these locktimes simultaneously. */ - val IncompatibleLockTimes = Failure(new IllegalArgumentException( - "Means you tried to spend an output that requires a lock by blockheight, and another output that requires a lock by timestamp")) + val IncompatibleLockTimes = Failure( + new IllegalArgumentException( + "Means you tried to spend an output that requires a lock by blockheight, and another output that requires a lock by timestamp" + ) + ) /** Means we have a output on this transaction below * [[org.bitcoins.core.policy.Policy.dustThreshold Policy.dustThreshold]] */ def OutputBelowDustThreshold( - belowDustOutputs: Seq[TransactionOutput]): Failure[Nothing] = - Failure(new IllegalArgumentException( - s"The p2p network discourages outputs below the dustThreshold, $belowDustOutputs, this tx won't be relayed")) + belowDustOutputs: Seq[TransactionOutput] + ): Failure[Nothing] = + Failure( + new IllegalArgumentException( + s"The p2p network discourages outputs below the dustThreshold, $belowDustOutputs, this tx won't be relayed" + ) + ) val UnknownError = Failure(new IllegalArgumentException) } diff --git a/core/src/main/scala/org/bitcoins/core/wallet/fee/FeeUnit.scala b/core/src/main/scala/org/bitcoins/core/wallet/fee/FeeUnit.scala index 06ce9ba018..7e234f2602 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/fee/FeeUnit.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/fee/FeeUnit.scala @@ -4,8 +4,8 @@ import org.bitcoins.core.currency._ import org.bitcoins.core.protocol.transaction.Transaction import org.bitcoins.crypto.StringFactory -/** This is meant to be an abstract type that represents different fee unit measurements for - * blockchains +/** This is meant to be an abstract type that represents different fee unit + * measurements for blockchains */ sealed abstract class FeeUnit { def currencyUnit: CurrencyUnit @@ -17,20 +17,25 @@ sealed abstract class FeeUnit { def factory: FeeUnitFactory[FeeUnit] - /** The coefficient the denominator in the unit is multiplied by, - * for example sats/kilobyte -> 1000 + /** The coefficient the denominator in the unit is multiplied by, for example + * sats/kilobyte -> 1000 */ def scaleFactor: Long = factory.scaleFactor - require(scaleFactor > 0, - s"Scale factor cannot be less than or equal to 0, got $scaleFactor") + require( + scaleFactor > 0, + s"Scale factor cannot be less than or equal to 0, got $scaleFactor" + ) - /** Takes the given transaction returns a size that will be used for calculating the fee rate. - * This is generally the denominator in the unit, ie sats/byte + /** Takes the given transaction returns a size that will be used for + * calculating the fee rate. This is generally the denominator in the unit, + * ie sats/byte */ def txSizeForCalc(tx: Transaction): Long = factory.txSizeForCalc(tx) - /** Calculates the fee for the transaction using this fee rate, rounds down satoshis */ + /** Calculates the fee for the transaction using this fee rate, rounds down + * satoshis + */ final def calc(tx: Transaction): CurrencyUnit = this * txSizeForCalc(tx) def toLong: Long = currencyUnit.satoshis.toLong @@ -45,27 +50,33 @@ trait FeeUnitFactory[+T <: FeeUnit] { /** String to identify this fee unit, for example "sats/byte" */ def unitString: String - /** The coefficient the denominator in the unit is multiplied by, - * for example sats/kilobyte -> 1000 + /** The coefficient the denominator in the unit is multiplied by, for example + * sats/kilobyte -> 1000 */ def scaleFactor: Long - require(scaleFactor > 0, - s"Scale factor cannot be less than or equal to 0, got $scaleFactor") + require( + scaleFactor > 0, + s"Scale factor cannot be less than or equal to 0, got $scaleFactor" + ) - /** Takes the given transaction returns a size that will be used for calculating the fee rate. - * This is generally the denominator in the unit, ie sats/byte + /** Takes the given transaction returns a size that will be used for + * calculating the fee rate. This is generally the denominator in the unit, + * ie sats/byte */ def txSizeForCalc(tx: Transaction): Long - /** Creates an instance T where the value given is the numerator of the fee unit + /** Creates an instance T where the value given is the numerator of the fee + * unit */ def fromLong(long: Long): T - /** Calculates the fee rate from the given Transaction. - * Uses Math.round for rounding up, which returns the closest long to the argument - * @param totalInputAmount Total amount being spent by the transaction's inputs - * @param tx Transaction to calculate the fee rate of + /** Calculates the fee rate from the given Transaction. Uses Math.round for + * rounding up, which returns the closest long to the argument + * @param totalInputAmount + * Total amount being spent by the transaction's inputs + * @param tx + * Transaction to calculate the fee rate of */ def calc(totalInputAmount: CurrencyUnit, tx: Transaction): T = { val feePaid = totalInputAmount - tx.totalOutput @@ -76,7 +87,8 @@ trait FeeUnitFactory[+T <: FeeUnit] { } /** Meant to represent the different fee unit types for the bitcoin protocol - * @see [[https://en.bitcoin.it/wiki/Weight_units]] + * @see + * [[https://en.bitcoin.it/wiki/Weight_units]] */ sealed abstract class BitcoinFeeUnit extends FeeUnit @@ -89,18 +101,20 @@ case class SatoshisPerByte(currencyUnit: CurrencyUnit) extends BitcoinFeeUnit { override def factory: FeeUnitFactory[SatoshisPerByte] = SatoshisPerByte override val toSatsPerVByte: SatoshisPerVirtualByte = SatoshisPerVirtualByte( - currencyUnit) + currencyUnit + ) } object SatoshisPerByte extends FeeUnitFactory[SatoshisPerByte] { - /** The coefficient the denominator in the unit is multiplied by, - * for example sats/kilobyte -> 1000 + /** The coefficient the denominator in the unit is multiplied by, for example + * sats/kilobyte -> 1000 */ override lazy val scaleFactor: Long = 1 - /** Takes the given transaction returns a size that will be used for calculating the fee rate. - * This is generally the denominator in the unit, ie sats/byte + /** Takes the given transaction returns a size that will be used for + * calculating the fee rate. This is generally the denominator in the unit, + * ie sats/byte */ override def txSizeForCalc(tx: Transaction): Long = tx.byteSize @@ -127,7 +141,8 @@ case class SatoshisPerKiloByte(currencyUnit: CurrencyUnit) case None => throw new RuntimeException( - s"Failed to convert sat/kb -> sat/byte (loss of precision) for $currencyUnit") + s"Failed to convert sat/kb -> sat/byte (loss of precision) for $currencyUnit" + ) } } @@ -149,13 +164,14 @@ case class SatoshisPerKiloByte(currencyUnit: CurrencyUnit) object SatoshisPerKiloByte extends FeeUnitFactory[SatoshisPerKiloByte] { - /** The coefficient the denominator in the unit is multiplied by, - * for example sats/kilobyte -> 1000 + /** The coefficient the denominator in the unit is multiplied by, for example + * sats/kilobyte -> 1000 */ override lazy val scaleFactor: Long = 1000 - /** Takes the given transaction returns a size that will be used for calculating the fee rate. - * This is generally the denominator in the unit, ie sats/byte + /** Takes the given transaction returns a size that will be used for + * calculating the fee rate. This is generally the denominator in the unit, + * ie sats/byte */ override def txSizeForCalc(tx: Transaction): Long = tx.byteSize @@ -168,10 +184,11 @@ object SatoshisPerKiloByte extends FeeUnitFactory[SatoshisPerKiloByte] { override val unitString: String = "sats/kb" } -/** A 'virtual byte' (also known as virtual size) is a new weight measurement that - * was created with segregated witness (BIP141). Now 1 'virtual byte' - * has the weight of 4 bytes in the [[org.bitcoins.core.protocol.transaction.TransactionWitness]] - * of a [[org.bitcoins.core.protocol.transaction.WitnessTransaction]] +/** A 'virtual byte' (also known as virtual size) is a new weight measurement + * that was created with segregated witness (BIP141). Now 1 'virtual byte' has + * the weight of 4 bytes in the + * [[org.bitcoins.core.protocol.transaction.TransactionWitness]] of a + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction]] */ case class SatoshisPerVirtualByte(currencyUnit: CurrencyUnit) extends BitcoinFeeUnit { @@ -189,13 +206,14 @@ case class SatoshisPerVirtualByte(currencyUnit: CurrencyUnit) object SatoshisPerVirtualByte extends FeeUnitFactory[SatoshisPerVirtualByte] { - /** The coefficient the denominator in the unit is multiplied by, - * for example sats/kilobyte -> 1000 + /** The coefficient the denominator in the unit is multiplied by, for example + * sats/kilobyte -> 1000 */ override lazy val scaleFactor: Long = 1 - /** Takes the given transaction returns a size that will be used for calculating the fee rate. - * This is generally the denominator in the unit, ie sats/byte + /** Takes the given transaction returns a size that will be used for + * calculating the fee rate. This is generally the denominator in the unit, + * ie sats/byte */ override def txSizeForCalc(tx: Transaction): Long = tx.vsize @@ -205,19 +223,21 @@ object SatoshisPerVirtualByte extends FeeUnitFactory[SatoshisPerVirtualByte] { val zero: SatoshisPerVirtualByte = SatoshisPerVirtualByte(CurrencyUnits.zero) val one: SatoshisPerVirtualByte = SatoshisPerVirtualByte(Satoshis.one) - /** Used to indicate we could not retrieve a fee from a [[org.bitcoins.core.api.feeprovider.FeeRateApi]] */ + /** Used to indicate we could not retrieve a fee from a + * [[org.bitcoins.core.api.feeprovider.FeeRateApi]] + */ val negativeOne: SatoshisPerVirtualByte = SatoshisPerVirtualByte(Satoshis(-1)) override val unitString: String = "sats/vbyte" } -/** Weight is used to indicate how 'expensive' the transaction is on the blockchain. - * This use to be a simple calculation before segwit (BIP141). Each byte in the transaction - * counted as 4 'weight' units. Now with segwit, the +/** Weight is used to indicate how 'expensive' the transaction is on the + * blockchain. This use to be a simple calculation before segwit (BIP141). Each + * byte in the transaction counted as 4 'weight' units. Now with segwit, the * [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] - * is counted as 1 weight unit per byte, - * while other parts of the transaction (outputs, inputs, locktime etc) count as 4 weight units. - * As we add more witness versions, this may be subject to change. + * is counted as 1 weight unit per byte, while other parts of the transaction + * (outputs, inputs, locktime etc) count as 4 weight units. As we add more + * witness versions, this may be subject to change. * [[https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#Transaction_size_calculations BIP 141]] * [[https://github.com/bitcoin/bitcoin/blob/5961b23898ee7c0af2626c46d5d70e80136578d3/src/consensus/validation.h#L96]] */ @@ -228,18 +248,20 @@ case class SatoshisPerKW(currencyUnit: CurrencyUnit) extends BitcoinFeeUnit { override def toString: String = s"$toLong sats/kw" override val toSatsPerVByte: SatoshisPerVirtualByte = SatoshisPerVirtualByte( - currencyUnit / Satoshis(250)) + currencyUnit / Satoshis(250) + ) } object SatoshisPerKW extends FeeUnitFactory[SatoshisPerKW] { - /** The coefficient the denominator in the unit is multiplied by, - * for example sats/kilobyte -> 1000 + /** The coefficient the denominator in the unit is multiplied by, for example + * sats/kilobyte -> 1000 */ override lazy val scaleFactor: Long = 1000 - /** Takes the given transaction returns a size that will be used for calculating the fee rate. - * This is generally the denominator in the unit, ie sats/byte + /** Takes the given transaction returns a size that will be used for + * calculating the fee rate. This is generally the denominator in the unit, + * ie sats/byte */ override def txSizeForCalc(tx: Transaction): Long = tx.weight @@ -254,10 +276,12 @@ object SatoshisPerKW extends FeeUnitFactory[SatoshisPerKW] { object FeeUnit extends StringFactory[FeeUnit] { - val factories = Vector(SatoshisPerVirtualByte, - SatoshisPerByte, - SatoshisPerKiloByte, - SatoshisPerKW) + val factories = Vector( + SatoshisPerVirtualByte, + SatoshisPerByte, + SatoshisPerKiloByte, + SatoshisPerKW + ) override def fromString(string: String): FeeUnit = { val arr = string.split(" ") diff --git a/core/src/main/scala/org/bitcoins/core/wallet/keymanagement/KeyManagerInitializeError.scala b/core/src/main/scala/org/bitcoins/core/wallet/keymanagement/KeyManagerInitializeError.scala index f118dbc905..d6396eb359 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/keymanagement/KeyManagerInitializeError.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/keymanagement/KeyManagerInitializeError.scala @@ -13,11 +13,10 @@ object InitializeKeyManagerError { extends Error(underlying) with KeyManagerInitializeError - /** Wallet data was found in the - * specified data directory. + /** Wallet data was found in the specified data directory. * - * @note `bitcoin-s` only supports one wallet - * per network at the moment. + * @note + * `bitcoin-s` only supports one wallet per network at the moment. */ final case object WalletAlreadyExists extends Error("Wallet already exists") diff --git a/core/src/main/scala/org/bitcoins/core/wallet/keymanagement/KeyManagerParams.scala b/core/src/main/scala/org/bitcoins/core/wallet/keymanagement/KeyManagerParams.scala index 0d29cba395..cb9f377e77 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/keymanagement/KeyManagerParams.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/keymanagement/KeyManagerParams.scala @@ -8,4 +8,5 @@ import org.bitcoins.core.hd.HDPurpose case class KeyManagerParams( seedPath: Path, purpose: HDPurpose, - network: NetworkParameters) + network: NetworkParameters +) diff --git a/core/src/main/scala/org/bitcoins/core/wallet/rescan/RescanState.scala b/core/src/main/scala/org/bitcoins/core/wallet/rescan/RescanState.scala index 0e78b63007..3e78d599f8 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/rescan/RescanState.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/rescan/RescanState.scala @@ -15,29 +15,34 @@ object RescanState { /** Finished a rescan */ case object RescanDone extends RescanState - /** For the case where we do not need to initiate a recursive rescan with a fresh pool of wallet addresses */ + /** For the case where we do not need to initiate a recursive rescan with a + * fresh pool of wallet addresses + */ case object RescanNotNeeded extends RescanState /** A rescan has already been started */ case object RescanAlreadyStarted extends RescanState - /** Indicates a rescan has bene started - * The promise [[completeRescanEarlyP]] gives us the ability to terminate - * the rescan early by completing the promise - * [[blocksMatchedF]] is a future that is completed when the rescan is done - * this returns all blocks that were matched during the rescan. - * [[recursiveRescanP]] If the rescan is continued with a fresh pool of addresses it completes `recursiveRescanP` with the new `RescanState.RescanStarted`. - * If the rescan is done because `addressGapLimit` is satisfied, `recursiveRescanP` with `RescanState.RescanNotNeeded` + /** Indicates a rescan has bene started The promise [[completeRescanEarlyP]] + * gives us the ability to terminate the rescan early by completing the + * promise [[blocksMatchedF]] is a future that is completed when the rescan + * is done this returns all blocks that were matched during the rescan. + * [[recursiveRescanP]] If the rescan is continued with a fresh pool of + * addresses it completes `recursiveRescanP` with the new + * `RescanState.RescanStarted`. If the rescan is done because + * `addressGapLimit` is satisfied, `recursiveRescanP` with + * `RescanState.RescanNotNeeded` */ case class RescanStarted( private val completeRescanEarlyP: Promise[Option[Int]], blocksMatchedF: Future[Vector[BlockMatchingResponse]], - recursiveRescanP: Promise[RescanState])(implicit ec: ExecutionContext) + recursiveRescanP: Promise[RescanState] + )(implicit ec: ExecutionContext) extends RescanState { private val _isCompletedEarly: AtomicBoolean = new AtomicBoolean(false) - //the promise returned by Source.maybe completes with None - //if the stream terminated because the rescan was complete. + // the promise returned by Source.maybe completes with None + // if the stream terminated because the rescan was complete. completeRescanEarlyP.future.map { _ => _isCompletedEarly.set(false) } @@ -46,23 +51,26 @@ object RescanState { case RescanTerminatedEarly => recursiveRescanP.failure(RescanTerminatedEarly) _isCompletedEarly.set(true) - case scala.util.control.NonFatal(_) => //do nothing + case scala.util.control.NonFatal(_) => // do nothing } - /** Useful for determining if the rescan was completed - * externally by the promise to terminate the stream - * or was completed because the rescan was fully executed + /** Useful for determining if the rescan was completed externally by the + * promise to terminate the stream or was completed because the rescan was + * fully executed */ def isCompletedEarly: Boolean = _isCompletedEarly.get def isStopped: Boolean = entireRescanDoneF.isCompleted - /** Means this single rescan is complete, but recursive rescans may not be completed */ + /** Means this single rescan is complete, but recursive rescans may not be + * completed + */ def singleRescanDoneF: Future[Vector[BlockMatchingResponse]] = blocksMatchedF - /** Means the entire rescan is done (including recursive rescans). This future is completed - * when we rescan filters with addresses do not contain funds within [[WalletAppConfig.addressGapLimit]] + /** Means the entire rescan is done (including recursive rescans). This + * future is completed when we rescan filters with addresses do not contain + * funds within [[WalletAppConfig.addressGapLimit]] */ def entireRescanDoneF: Future[Vector[BlockMatchingResponse]] = { for { @@ -82,8 +90,8 @@ object RescanState { recursiveRescanP.failure(err) } - /** Completes the stream that the rescan in progress uses. - * This aborts the rescan early. + /** Completes the stream that the rescan in progress uses. This aborts the + * rescan early. */ def stop(): Future[Vector[BlockMatchingResponse]] = { val stoppedRecursiveRescanF = recursiveRescanP.future.flatMap { @@ -103,8 +111,8 @@ object RescanState { f.flatMap { _ => blocksMatchedF.recoverWith { case RescanTerminatedEarly => - //this means this was purposefully terminated early - //don't propagate the exception + // this means this was purposefully terminated early + // don't propagate the exception Future.successful(Vector.empty) case err => throw err @@ -114,8 +122,9 @@ object RescanState { } } - def awaitSingleRescanDone(rescanState: RescanState)(implicit - ec: ExecutionContext): Future[Unit] = { + def awaitSingleRescanDone( + rescanState: RescanState + )(implicit ec: ExecutionContext): Future[Unit] = { rescanState match { case RescanState.RescanDone | RescanState.RescanAlreadyStarted | RescanState.RescanNotNeeded => @@ -125,13 +134,14 @@ object RescanState { } } - /** Returns a Future for all rescan states that will be complete when the rescan is done. - * This can be because the stream was externally termianted early, or the rescan completes. - * If you are interested in just the stream completing beacuse the rescan was fully executed, - * use [[awaitComplete())]] + /** Returns a Future for all rescan states that will be complete when the + * rescan is done. This can be because the stream was externally termianted + * early, or the rescan completes. If you are interested in just the stream + * completing beacuse the rescan was fully executed, use [[awaitComplete())]] */ - def awaitRescanDone(rescanState: RescanState)(implicit - ec: ExecutionContext): Future[Unit] = { + def awaitRescanDone( + rescanState: RescanState + )(implicit ec: ExecutionContext): Future[Unit] = { rescanState match { case RescanState.RescanDone | RescanState.RescanAlreadyStarted | RescanState.RescanNotNeeded => @@ -141,12 +151,13 @@ object RescanState { } } - /** Returns a Future that is completed when a rescan is fully executed. - * This means that the rescan was NOT terminated externally by completing - * the akka stream that underlies the rescan logic. + /** Returns a Future that is completed when a rescan is fully executed. This + * means that the rescan was NOT terminated externally by completing the akka + * stream that underlies the rescan logic. */ - def awaitRescanComplete(rescanState: RescanState)(implicit - ec: ExecutionContext): Future[Unit] = { + def awaitRescanComplete( + rescanState: RescanState + )(implicit ec: ExecutionContext): Future[Unit] = { rescanState match { case RescanState.RescanDone | RescanState.RescanAlreadyStarted | RescanState.RescanNotNeeded => @@ -156,7 +167,9 @@ object RescanState { if (started.isCompletedEarly) { Future.failed( new RuntimeException( - s"Rescan was completed early, so cannot fulfill this request")) + s"Rescan was completed early, so cannot fulfill this request" + ) + ) } else { Future.unit } diff --git a/core/src/main/scala/org/bitcoins/core/wallet/signer/FundingInfo.scala b/core/src/main/scala/org/bitcoins/core/wallet/signer/FundingInfo.scala index 2ff960bfac..e9821e81c5 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/signer/FundingInfo.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/signer/FundingInfo.scala @@ -7,12 +7,14 @@ import org.bitcoins.core.protocol.transaction.{ } import org.bitcoins.core.wallet.utxo.{InputInfo, InputSigningInfo} -/** This meant to represent the class used to 'fund' an - * unsigned [[org.bitcoins.core.protocol.transaction.Transaction Transaction]]. - * This is useful for when we have multiple [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] - * that each have their own transaction type. I.e. we should only be able to have - * BitcoinTransactions paired with [[org.bitcoins.core.wallet.utxo.InputSigningInfo[InputInfo] UTXOInfo]], - * the same would apply for litecoin etc. +/** This meant to represent the class used to 'fund' an unsigned + * [[org.bitcoins.core.protocol.transaction.Transaction Transaction]]. This is + * useful for when we have multiple + * [[org.bitcoins.core.config.NetworkParameters NetworkParameters]] that each + * have their own transaction type. I.e. we should only be able to have + * BitcoinTransactions paired with + * [[org.bitcoins.core.wallet.utxo.InputSigningInfo[InputInfo] UTXOInfo]], the + * same would apply for litecoin etc. */ sealed abstract class FundingInfo { @@ -31,18 +33,20 @@ object BitcoinFundingInfo { private case class BitcoinFundingInfoImpl( transaction: Transaction, - utxos: Seq[InputSigningInfo[InputInfo]]) - extends BitcoinFundingInfo + utxos: Seq[InputSigningInfo[InputInfo]] + ) extends BitcoinFundingInfo def apply( tx: BaseTransaction, - utxos: Seq[InputSigningInfo[InputInfo]]): BitcoinFundingInfo = { + utxos: Seq[InputSigningInfo[InputInfo]] + ): BitcoinFundingInfo = { BitcoinFundingInfoImpl(tx, utxos) } def apply( wtx: WitnessTransaction, - utxos: Seq[InputSigningInfo[InputInfo]]): BitcoinFundingInfo = { + utxos: Seq[InputSigningInfo[InputInfo]] + ): BitcoinFundingInfo = { BitcoinFundingInfoImpl(wtx, utxos) } } diff --git a/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala b/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala index 16299b8a43..ccc5bfaf2c 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/signer/Signer.scala @@ -20,7 +20,8 @@ sealed abstract class SignerUtils { sigComponent: TxSigComponent, sign: ByteVector => ECDigitalSignature, hashType: HashType, - isDummySignature: Boolean): ECDigitalSignature = { + isDummySignature: Boolean + ): ECDigitalSignature = { if (isDummySignature) { DummyECDigitalSignature } else { @@ -33,21 +34,25 @@ sealed abstract class SignerUtils { signingInfo: InputSigningInfo[InputInfo], sign: ByteVector => ECDigitalSignature, hashType: HashType, - isDummySignature: Boolean): ECDigitalSignature = { + isDummySignature: Boolean + ): ECDigitalSignature = { if (isDummySignature) { LowRDummyECDigitalSignature } else { - TransactionSignatureCreator.createSig(unsignedTx, - signingInfo, - sign, - hashType) + TransactionSignatureCreator.createSig( + unsignedTx, + signingInfo, + sign, + hashType + ) } } def signSingle( spendingInfo: ECSignatureParams[InputInfo], unsignedTx: Transaction, - isDummySignature: Boolean): PartialSignature = { + isDummySignature: Boolean + ): PartialSignature = { val tx = spendingInfo.inputInfo match { case _: SegwitV0NativeInputInfo | _: P2SHNestedSegwitV0InputInfo | @@ -72,43 +77,51 @@ sealed abstract class SignerUtils { protected def relevantInfo( spendingInfo: InputSigningInfo[InputInfo], - unsignedTx: Transaction): ( - Seq[Sign], - TransactionOutput, - UInt32, - HashType) = { - (spendingInfo.signers, - spendingInfo.output, - inputIndex(spendingInfo, unsignedTx), - spendingInfo.hashType) + unsignedTx: Transaction + ): (Seq[Sign], TransactionOutput, UInt32, HashType) = { + ( + spendingInfo.signers, + spendingInfo.output, + inputIndex(spendingInfo, unsignedTx), + spendingInfo.hashType + ) } protected def inputIndex( spendingInfo: InputSigningInfo[InputInfo], - tx: Transaction): UInt32 = { + tx: Transaction + ): UInt32 = { tx.inputs.zipWithIndex .find(_._1.previousOutput == spendingInfo.outPoint) match { case Some((_, index)) => UInt32(index) case None => throw new IllegalArgumentException( - "Transaction did not contain expected input.") + "Transaction did not contain expected input." + ) } } } -/** The class used to represent a signing process for a specific [[org.bitcoins.core.protocol.script.ScriptPubKey]] type */ +/** The class used to represent a signing process for a specific + * [[org.bitcoins.core.protocol.script.ScriptPubKey]] type + */ sealed abstract class Signer[-InputType <: InputInfo] extends SignerUtils { /** The method used to sign a bitcoin unspent transaction output - * @param spendingInfo - The information required for signing - * @param unsignedTx the external Transaction that needs an input signed - * @param isDummySignature - do not sign the tx for real, just use a dummy signature this is useful for fee estimation + * @param spendingInfo + * \- The information required for signing + * @param unsignedTx + * the external Transaction that needs an input signed + * @param isDummySignature + * \- do not sign the tx for real, just use a dummy signature this is + * useful for fee estimation * @return */ def sign( spendingInfo: ScriptSignatureParams[InputType], unsignedTx: Transaction, - isDummySignature: Boolean): TxSigComponent = { + isDummySignature: Boolean + ): TxSigComponent = { sign( spendingInfo, unsignedTx, @@ -117,42 +130,55 @@ sealed abstract class Signer[-InputType <: InputInfo] extends SignerUtils { ) } - /** The method used to sign a bitcoin unspent transaction output that is potentially nested - * @param spendingInfo - The information required for signing - * @param unsignedTx the external Transaction that needs an input signed - * @param isDummySignature - do not sign the tx for real, just use a dummy signature this is useful for fee estimation - * @param spendingInfoToSatisfy - specifies the NewSpendingInfo whose ScriptPubKey needs a ScriptSignature to be generated + /** The method used to sign a bitcoin unspent transaction output that is + * potentially nested + * @param spendingInfo + * \- The information required for signing + * @param unsignedTx + * the external Transaction that needs an input signed + * @param isDummySignature + * \- do not sign the tx for real, just use a dummy signature this is + * useful for fee estimation + * @param spendingInfoToSatisfy + * \- specifies the NewSpendingInfo whose ScriptPubKey needs a + * ScriptSignature to be generated * @return */ def sign( spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[InputType]): TxSigComponent + spendingInfoToSatisfy: ScriptSignatureParams[InputType] + ): TxSigComponent - /** Creates a BaseTxSigComponent by replacing the unsignedTx input at inputIndex - * with a signed one using the given ScriptSignature + /** Creates a BaseTxSigComponent by replacing the unsignedTx input at + * inputIndex with a signed one using the given ScriptSignature */ protected def updateScriptSigInSigComponent( unsignedTx: Transaction, inputIndex: Int, output: TransactionOutput, - scriptSignature: ScriptSignature): BaseTxSigComponent = { + scriptSignature: ScriptSignature + ): BaseTxSigComponent = { val unsignedInput = unsignedTx.inputs(inputIndex) - val signedInput = TransactionInput(unsignedInput.previousOutput, - scriptSignature, - unsignedInput.sequence) + val signedInput = TransactionInput( + unsignedInput.previousOutput, + scriptSignature, + unsignedInput.sequence + ) val signedInputs = unsignedTx.inputs.updated(inputIndex, signedInput) val signedTx = unsignedTx match { case btx: NonWitnessTransaction => BaseTransaction(btx.version, signedInputs, btx.outputs, btx.lockTime) case wtx: WitnessTransaction => - WitnessTransaction(wtx.version, - signedInputs, - wtx.outputs, - wtx.lockTime, - wtx.witness) + WitnessTransaction( + wtx.version, + signedInputs, + wtx.outputs, + wtx.lockTime, + wtx.witness + ) } BaseTxSigComponent(signedTx, UInt32(inputIndex), output, flags) @@ -164,7 +190,8 @@ object BitcoinSigner extends SignerUtils { def sign( spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, - isDummySignature: Boolean): TxSigComponent = { + isDummySignature: Boolean + ): TxSigComponent = { sign(spendingInfo, unsignedTx, isDummySignature, spendingInfo) } @@ -172,76 +199,103 @@ object BitcoinSigner extends SignerUtils { spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[ - InputInfo]): TxSigComponent = { + spendingInfoToSatisfy: ScriptSignatureParams[InputInfo] + ): TxSigComponent = { def spendingFrom[Info <: InputInfo]( - inputInfo: Info): ScriptSignatureParams[Info] = { + inputInfo: Info + ): ScriptSignatureParams[Info] = { spendingInfoToSatisfy.copy(inputInfo = inputInfo) } spendingInfoToSatisfy.inputInfo match { case empty: EmptyInputInfo => - EmptySigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(empty)) + EmptySigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(empty) + ) case p2pk: P2PKInputInfo => - P2PKSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(p2pk)) + P2PKSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(p2pk) + ) case p2pkh: P2PKHInputInfo => - P2PKHSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(p2pkh)) + P2PKHSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(p2pkh) + ) case p2pKWithTimeout: P2PKWithTimeoutInputInfo => - P2PKWithTimeoutSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(p2pKWithTimeout)) + P2PKWithTimeoutSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(p2pKWithTimeout) + ) case p2sh: P2SHInputInfo => - P2SHSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(p2sh)) + P2SHSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(p2sh) + ) case multiSig: MultiSignatureInputInfo => - MultiSigSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(multiSig)) + MultiSigSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(multiSig) + ) case lockTime: LockTimeInputInfo => - LockTimeSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(lockTime)) + LockTimeSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(lockTime) + ) case conditional: ConditionalInputInfo => - ConditionalSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(conditional)) + ConditionalSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(conditional) + ) case p2wpkh: P2WPKHV0InputInfo => - P2WPKHSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(p2wpkh)) + P2WPKHSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(p2wpkh) + ) case pw2sh: P2WSHV0InputInfo => - P2WSHSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - spendingFrom(pw2sh)) + P2WSHSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + spendingFrom(pw2sh) + ) case _: UnassignedSegwitNativeInputInfo => throw new UnsupportedOperationException("Unsupported Segwit version") } } - /** Signs the PSBT's input at the given input with the signer, then adds it to the PSBT - * in a PartialSignature record - * @param psbt The PSBT to sign - * @param inputIndex Index of input to sign - * @param signer Function or private key used to sign the PSBT - * @param isDummySignature Do not sign the tx for real, just use a dummy signature, this is useful for fee estimation - * @param conditionalPath Represents the spending branch being taken in a ScriptPubKey's execution + /** Signs the PSBT's input at the given input with the signer, then adds it to + * the PSBT in a PartialSignature record + * @param psbt + * The PSBT to sign + * @param inputIndex + * Index of input to sign + * @param signer + * Function or private key used to sign the PSBT + * @param isDummySignature + * Do not sign the tx for real, just use a dummy signature, this is useful + * for fee estimation + * @param conditionalPath + * Represents the spending branch being taken in a ScriptPubKey's execution * @return */ def sign( @@ -249,7 +303,8 @@ object BitcoinSigner extends SignerUtils { inputIndex: Int, signer: Sign, conditionalPath: ConditionalPath = ConditionalPath.NoCondition, - isDummySignature: Boolean = false): PSBT = { + isDummySignature: Boolean = false + ): PSBT = { // if already signed by this signer if ( psbt @@ -258,7 +313,8 @@ object BitcoinSigner extends SignerUtils { .exists(_.pubKey.toPublicKey == signer.publicKey) ) { throw new IllegalArgumentException( - "Input has already been signed with this key") + "Input has already been signed with this key" + ) } val tx = psbt.transaction @@ -277,11 +333,13 @@ object BitcoinSigner extends SignerUtils { } val transactionWitness = TransactionWitness.fromWitOpt(witnesses) - WitnessTransaction(btx.version, - btx.inputs, - btx.outputs, - btx.lockTime, - transactionWitness) + WitnessTransaction( + btx.version, + btx.inputs, + btx.outputs, + btx.lockTime, + transactionWitness + ) case wtx: WitnessTransaction => wtx.witness(inputIndex) match { case EmptyScriptWitness => @@ -315,14 +373,15 @@ sealed abstract class RawSingleKeyBitcoinSigner[-InputType <: RawInputInfo] def keyAndSigToScriptSig( key: ECPublicKey, sig: ECDigitalSignature, - spendingInfo: InputSigningInfo[InputType]): ScriptSignature + spendingInfo: InputSigningInfo[InputType] + ): ScriptSignature override def sign( spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[ - InputType]): TxSigComponent = { + spendingInfoToSatisfy: ScriptSignatureParams[InputType] + ): TxSigComponent = { val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx) @@ -330,34 +389,42 @@ sealed abstract class RawSingleKeyBitcoinSigner[-InputType <: RawInputInfo] signSingle(spendingInfo.toSingle(0), unsignedTx, isDummySignature) val scriptSig = - keyAndSigToScriptSig(partialSignature.pubKey.toPublicKey, - partialSignature.signature, - spendingInfoToSatisfy) + keyAndSigToScriptSig( + partialSignature.pubKey.toPublicKey, + partialSignature.signature, + spendingInfoToSatisfy + ) - updateScriptSigInSigComponent(unsignedTx, - inputIndex.toInt, - output, - scriptSig) + updateScriptSigInSigComponent( + unsignedTx, + inputIndex.toInt, + output, + scriptSig + ) } } -/** For signing EmptyScriptPubKeys in tests, should probably not be used in real life. */ +/** For signing EmptyScriptPubKeys in tests, should probably not be used in real + * life. + */ sealed abstract class EmptySigner extends Signer[EmptyInputInfo] { override def sign( spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[ - EmptyInputInfo]): TxSigComponent = { + spendingInfoToSatisfy: ScriptSignatureParams[EmptyInputInfo] + ): TxSigComponent = { val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx) val satisfyEmptyScriptSig = TrivialTrueScriptSignature - updateScriptSigInSigComponent(unsignedTx, - inputIndex.toInt, - output, - satisfyEmptyScriptSig) + updateScriptSigInSigComponent( + unsignedTx, + inputIndex.toInt, + output, + satisfyEmptyScriptSig + ) } } @@ -370,7 +437,8 @@ sealed abstract class P2PKSigner override def keyAndSigToScriptSig( key: ECPublicKey, sig: ECDigitalSignature, - spendingInfo: InputSigningInfo[P2PKInputInfo]): ScriptSignature = { + spendingInfo: InputSigningInfo[P2PKInputInfo] + ): ScriptSignature = { P2PKScriptSignature(sig) } } @@ -384,7 +452,8 @@ sealed abstract class P2PKHSigner override def keyAndSigToScriptSig( key: ECPublicKey, sig: ECDigitalSignature, - spendingInfo: InputSigningInfo[P2PKHInputInfo]): ScriptSignature = { + spendingInfo: InputSigningInfo[P2PKHInputInfo] + ): ScriptSignature = { P2PKHScriptSignature(sig, key) } } @@ -397,8 +466,8 @@ sealed abstract class P2PKWithTimeoutSigner override def keyAndSigToScriptSig( key: ECPublicKey, sig: ECDigitalSignature, - spendingInfo: InputSigningInfo[ - P2PKWithTimeoutInputInfo]): ScriptSignature = { + spendingInfo: InputSigningInfo[P2PKWithTimeoutInputInfo] + ): ScriptSignature = { P2PKWithTimeoutScriptSignature(spendingInfo.inputInfo.isBeforeTimeout, sig) } } @@ -411,8 +480,8 @@ sealed abstract class MultiSigSigner extends Signer[MultiSignatureInputInfo] { spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[ - MultiSignatureInputInfo]): TxSigComponent = { + spendingInfoToSatisfy: ScriptSignatureParams[MultiSignatureInputInfo] + ): TxSigComponent = { val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx) @@ -424,10 +493,12 @@ sealed abstract class MultiSigSigner extends Signer[MultiSignatureInputInfo] { val scriptSig = MultiSignatureScriptSignature(signatures) - updateScriptSigInSigComponent(unsignedTx, - inputIndex.toInt, - output, - scriptSig) + updateScriptSigInSigComponent( + unsignedTx, + inputIndex.toInt, + output, + scriptSig + ) } } @@ -440,8 +511,8 @@ sealed abstract class P2SHSigner extends Signer[P2SHInputInfo] { spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[ - P2SHInputInfo]): TxSigComponent = { + spendingInfoToSatisfy: ScriptSignatureParams[P2SHInputInfo] + ): TxSigComponent = { if (spendingInfoToSatisfy != spendingInfo) { throw TxBuilderError.WrongSigner.exception } else { @@ -449,15 +520,18 @@ sealed abstract class P2SHSigner extends Signer[P2SHInputInfo] { val oldInput = unsignedTx.inputs(inputIndex.toInt) val input = - TransactionInput(spendingInfo.outPoint, - EmptyScriptSignature, - oldInput.sequence) + TransactionInput( + spendingInfo.outPoint, + EmptyScriptSignature, + oldInput.sequence + ) val updatedTx = unsignedTx.updateInput(inputIndex.toInt, input) val nestedSpendingInfo = spendingInfoToSatisfy.copy( - inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo) + inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo + ) val signedTx = BitcoinSigner @@ -467,8 +541,10 @@ sealed abstract class P2SHSigner extends Signer[P2SHInputInfo] { val i = signedTx.inputs(inputIndex.toInt) val p2sh = - P2SHScriptSignature(i.scriptSignature, - spendingInfoToSatisfy.inputInfo.redeemScript) + P2SHScriptSignature( + i.scriptSignature, + spendingInfoToSatisfy.inputInfo.redeemScript + ) val signedInput = TransactionInput(i.previousOutput, p2sh, i.sequence) @@ -478,21 +554,27 @@ sealed abstract class P2SHSigner extends Signer[P2SHInputInfo] { val finalTx = signedTx match { case btx: NonWitnessTransaction => - BaseTransaction(version = btx.version, - inputs = signedInputs, - outputs = btx.outputs, - lockTime = btx.lockTime) + BaseTransaction( + version = btx.version, + inputs = signedInputs, + outputs = btx.outputs, + lockTime = btx.lockTime + ) case wtx: WitnessTransaction => - WitnessTransaction(version = wtx.version, - inputs = signedInputs, - outputs = wtx.outputs, - lockTime = wtx.lockTime, - witness = wtx.witness) + WitnessTransaction( + version = wtx.version, + inputs = signedInputs, + outputs = wtx.outputs, + lockTime = wtx.lockTime, + witness = wtx.witness + ) } - P2SHTxSigComponent(transaction = finalTx, - inputIndex = inputIndex, - output = output, - flags = flags) + P2SHTxSigComponent( + transaction = finalTx, + inputIndex = inputIndex, + output = output, + flags = flags + ) } } } @@ -505,8 +587,8 @@ sealed abstract class P2WPKHSigner extends Signer[P2WPKHV0InputInfo] { spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[ - P2WPKHV0InputInfo]): TxSigComponent = { + spendingInfoToSatisfy: ScriptSignatureParams[P2WPKHV0InputInfo] + ): TxSigComponent = { if (spendingInfoToSatisfy != spendingInfo) { throw TxBuilderError.WrongSigner.exception } else { @@ -519,21 +601,27 @@ sealed abstract class P2WPKHSigner extends Signer[P2WPKHV0InputInfo] { val unsignedTxWitness = TransactionWitness( wtx.witness - .updated(inputIndex.toInt, - spendingInfoToSatisfy.inputInfo.scriptWitness) - .toVector) + .updated( + inputIndex.toInt, + spendingInfoToSatisfy.inputInfo.scriptWitness + ) + .toVector + ) - val unsignedWtx = WitnessTransaction(wtx.version, - wtx.inputs, - wtx.outputs, - wtx.lockTime, - unsignedTxWitness) + val unsignedWtx = WitnessTransaction( + wtx.version, + wtx.inputs, + wtx.outputs, + wtx.lockTime, + unsignedTxWitness + ) val witSPK = output.scriptPubKey match { case p2wpkh: P2WPKHWitnessSPKV0 => p2wpkh case spk: TaprootScriptPubKey => throw new IllegalArgumentException( - s"Taproot not yet supported: $spk") + s"Taproot not yet supported: $spk" + ) case _: UnassignedWitnessScriptPubKey | _: P2WSHWitnessSPKV0 => throw TxBuilderError.WrongSigner.exception case _: NonWitnessScriptPubKey => @@ -543,20 +631,24 @@ sealed abstract class P2WPKHSigner extends Signer[P2WPKHV0InputInfo] { val witOutput = TransactionOutput(output.value, witSPK) val signature = - doSign(unsignedTx, - spendingInfo, - signer.signLowR, - hashType, - isDummySignature) + doSign( + unsignedTx, + spendingInfo, + signer.signLowR, + hashType, + isDummySignature + ) val scriptWitness = P2WPKHWitnessV0(pubKey, signature) val signedTxWitness = wtx.witness.updated(inputIndex.toInt, scriptWitness) - val signedTx = WitnessTransaction(unsignedWtx.version, - unsignedWtx.inputs, - unsignedWtx.outputs, - unsignedWtx.lockTime, - signedTxWitness) + val signedTx = WitnessTransaction( + unsignedWtx.version, + unsignedWtx.inputs, + unsignedWtx.outputs, + unsignedWtx.lockTime, + signedTxWitness + ) WitnessTxSigComponentRaw(signedTx, inputIndex, witOutput, flags) case btx: NonWitnessTransaction => @@ -575,8 +667,8 @@ sealed abstract class P2WSHSigner extends Signer[P2WSHV0InputInfo] { spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[ - P2WSHV0InputInfo]): TxSigComponent = { + spendingInfoToSatisfy: ScriptSignatureParams[P2WSHV0InputInfo] + ): TxSigComponent = { if (spendingInfoToSatisfy != spendingInfo) { throw TxBuilderError.WrongSigner.exception } else { @@ -584,29 +676,37 @@ sealed abstract class P2WSHSigner extends Signer[P2WSHV0InputInfo] { val wtx = WitnessTransaction .toWitnessTx(unsignedTx) - .updateWitness(inputIndex.toInt, - spendingInfoToSatisfy.inputInfo.scriptWitness) + .updateWitness( + inputIndex.toInt, + spendingInfoToSatisfy.inputInfo.scriptWitness + ) val nestedSpendingInfo = spendingInfoToSatisfy.copy( - inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo) + inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo + ) - val signedSigComponent = BitcoinSigner.sign(spendingInfo, - wtx, - isDummySignature, - nestedSpendingInfo) + val signedSigComponent = BitcoinSigner.sign( + spendingInfo, + wtx, + isDummySignature, + nestedSpendingInfo + ) val scriptWit = P2WSHWitnessV0( spendingInfoToSatisfy.inputInfo.scriptWitness.redeemScript, - signedSigComponent.scriptSignature) + signedSigComponent.scriptSignature + ) val signedWitness = wtx.witness.updated(inputIndex.toInt, scriptWit) - val signedWTx = WitnessTransaction(wtx.version, - wtx.inputs, - wtx.outputs, - wtx.lockTime, - signedWitness) + val signedWTx = WitnessTransaction( + wtx.version, + wtx.inputs, + wtx.outputs, + wtx.lockTime, + signedWitness + ) WitnessTxSigComponentRaw(signedWTx, inputIndex, output, flags) } } @@ -619,21 +719,24 @@ sealed abstract class LockTimeSigner extends Signer[LockTimeInputInfo] { spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[ - LockTimeInputInfo]): TxSigComponent = { + spendingInfoToSatisfy: ScriptSignatureParams[LockTimeInputInfo] + ): TxSigComponent = { val nestedSpendingInfo = spendingInfoToSatisfy.copy( - inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo) + inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo + ) - BitcoinSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - nestedSpendingInfo) + BitcoinSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + nestedSpendingInfo + ) } } object LockTimeSigner extends LockTimeSigner -/** Delegates to get a ScriptSignature for the case being - * spent and then adds an OP_TRUE or OP_FALSE +/** Delegates to get a ScriptSignature for the case being spent and then adds an + * OP_TRUE or OP_FALSE */ sealed abstract class ConditionalSigner extends Signer[ConditionalInputInfo] { @@ -641,26 +744,33 @@ sealed abstract class ConditionalSigner extends Signer[ConditionalInputInfo] { spendingInfo: ScriptSignatureParams[InputInfo], unsignedTx: Transaction, isDummySignature: Boolean, - spendingInfoToSatisfy: ScriptSignatureParams[ - ConditionalInputInfo]): TxSigComponent = { + spendingInfoToSatisfy: ScriptSignatureParams[ConditionalInputInfo] + ): TxSigComponent = { val (_, output, inputIndex, _) = relevantInfo(spendingInfo, unsignedTx) val nestedSpendingInfo = spendingInfoToSatisfy.copy( - inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo) + inputInfo = spendingInfoToSatisfy.inputInfo.nestedInputInfo + ) - val missingOpSigComponent = BitcoinSigner.sign(spendingInfo, - unsignedTx, - isDummySignature, - nestedSpendingInfo) + val missingOpSigComponent = BitcoinSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature, + nestedSpendingInfo + ) val scriptSig = - ConditionalScriptSignature(missingOpSigComponent.scriptSignature, - spendingInfoToSatisfy.inputInfo.condition) + ConditionalScriptSignature( + missingOpSigComponent.scriptSignature, + spendingInfoToSatisfy.inputInfo.condition + ) - updateScriptSigInSigComponent(unsignedTx, - inputIndex.toInt, - output, - scriptSig) + updateScriptSigInSigComponent( + unsignedTx, + inputIndex.toInt, + output, + scriptSig + ) } } object ConditionalSigner extends ConditionalSigner diff --git a/core/src/main/scala/org/bitcoins/core/wallet/utxo/AddressTag.scala b/core/src/main/scala/org/bitcoins/core/wallet/utxo/AddressTag.scala index 502704fbbb..175c1febf2 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/utxo/AddressTag.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/utxo/AddressTag.scala @@ -2,8 +2,8 @@ package org.bitcoins.core.wallet.utxo import org.bitcoins.crypto.StringFactory -/** A type of address tag, many AddressTags of the same type - * should inherit the AddressTagType that they all share +/** A type of address tag, many AddressTags of the same type should inherit the + * AddressTagType that they all share */ trait AddressTagType { def typeName: String @@ -19,8 +19,8 @@ trait AddressTagName { def !=(at: AddressTagType): Boolean = !(this == at) } -/** An tag for an address. It's name is what it is referred to as - * and it's tagType is its parent AddressTagType +/** An tag for an address. It's name is what it is referred to as and it's + * tagType is its parent AddressTagType */ trait AddressTag { def tagName: AddressTagName diff --git a/core/src/main/scala/org/bitcoins/core/wallet/utxo/ConditionalPath.scala b/core/src/main/scala/org/bitcoins/core/wallet/utxo/ConditionalPath.scala index d2d76ba99d..361df6625c 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/utxo/ConditionalPath.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/utxo/ConditionalPath.scala @@ -8,9 +8,10 @@ import scala.annotation.tailrec * then the remaining over-specified path will be ignored. * * For example, if you wanted to spend a ConditionalScriptPubKey(P2PK1, P2PK2) - * (which looks like OP_IF OP_ELSE OP_ENDIF) with the P2PK1 case, - * then you would construct a ConditionalSpendingInfo using nonNestedTrue as your - * ConditionalPath. Otherwise if you wanted to use P2PK2 you would use nonNestedFalse. + * (which looks like OP_IF OP_ELSE OP_ENDIF) with the P2PK1 + * case, then you would construct a ConditionalSpendingInfo using nonNestedTrue + * as your ConditionalPath. Otherwise if you wanted to use P2PK2 you would use + * nonNestedFalse. */ sealed trait ConditionalPath { def headOption: Option[Boolean] @@ -45,7 +46,8 @@ object ConditionalPath { @tailrec def loop( current: ConditionalPath, - accum: Vector[Boolean]): Vector[Boolean] = { + accum: Vector[Boolean] + ): Vector[Boolean] = { current match { case cond: ConditionTrue => loop(cond.nextCondition, accum :+ true) diff --git a/core/src/main/scala/org/bitcoins/core/wallet/utxo/ExternalAddressTag.scala b/core/src/main/scala/org/bitcoins/core/wallet/utxo/ExternalAddressTag.scala index 3bed955584..398fdc1284 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/utxo/ExternalAddressTag.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/utxo/ExternalAddressTag.scala @@ -10,7 +10,7 @@ trait ExternalAddressTagName extends AddressTagName */ trait ExternalAddressTagType extends AddressTagType -/** Address Tags defined outside the library, used for other projects - * creating there own address tags that aren't supported by bitcoin-s +/** Address Tags defined outside the library, used for other projects creating + * there own address tags that aren't supported by bitcoin-s */ trait ExternalAddressTag extends AddressTag diff --git a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputInfo.scala b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputInfo.scala index 328dc9db09..f040f728fb 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputInfo.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputInfo.scala @@ -18,12 +18,12 @@ import org.bitcoins.crypto.{ import scala.annotation.tailrec -/** An InputInfo contains all information other than private keys about - * a particular spending condition in a UTXO. +/** An InputInfo contains all information other than private keys about a + * particular spending condition in a UTXO. * - * Note that while some pieces of information (TxOutPoint, amount, etc.) - * apply to all input types, other pieces are specific to particular ones - * such as a witness to a SegWit input. + * Note that while some pieces of information (TxOutPoint, amount, etc.) apply + * to all input types, other pieces are specific to particular ones such as a + * witness to a SegWit input. */ sealed trait InputInfo { def outPoint: TransactionOutPoint @@ -49,20 +49,22 @@ sealed trait InputInfo { def toSpendingInfo( prevTransaction: Transaction, signers: Vector[Sign], - hashType: HashType): ScriptSignatureParams[InputInfo] = { + hashType: HashType + ): ScriptSignatureParams[InputInfo] = { ScriptSignatureParams(this, prevTransaction, signers, hashType) } def toSpendingInfo( prevTransaction: Transaction, signer: Sign, - hashType: HashType): ECSignatureParams[InputInfo] = { + hashType: HashType + ): ECSignatureParams[InputInfo] = { ECSignatureParams(this, prevTransaction, signer, hashType) } def genericWithSignFrom( - signerMaterial: InputSigningInfo[InputInfo]): InputSigningInfo[ - this.type] = { + signerMaterial: InputSigningInfo[InputInfo] + ): InputSigningInfo[this.type] = { signerMaterial match { case info: ScriptSignatureParams[InputInfo] => withSignFrom(info) case info: ECSignatureParams[InputInfo] => withSignFrom(info) @@ -70,14 +72,14 @@ sealed trait InputInfo { } def withSignFrom( - signerMaterial: ScriptSignatureParams[InputInfo]): ScriptSignatureParams[ - this.type] = { + signerMaterial: ScriptSignatureParams[InputInfo] + ): ScriptSignatureParams[this.type] = { signerMaterial.copy(inputInfo = this) } def withSignFrom( - signerMaterial: ECSignatureParams[InputInfo]): ECSignatureParams[ - this.type] = { + signerMaterial: ECSignatureParams[InputInfo] + ): ECSignatureParams[this.type] = { signerMaterial.copy(inputInfo = this) } } @@ -96,9 +98,9 @@ object InputInfo { def getScriptWitness(inputInfo: InputInfo): Option[ScriptWitness] = { inputInfo match { case _: RawInputInfo | _: P2SHNonSegwitInputInfo => None - case info: SegwitV0NativeInputInfo => Some(info.scriptWitness) - case info: P2SHNestedSegwitV0InputInfo => Some(info.scriptWitness) - case info: UnassignedSegwitNativeInputInfo => Some(info.scriptWitness) + case info: SegwitV0NativeInputInfo => Some(info.scriptWitness) + case info: P2SHNestedSegwitV0InputInfo => Some(info.scriptWitness) + case info: UnassignedSegwitNativeInputInfo => Some(info.scriptWitness) } } @@ -122,21 +124,22 @@ object InputInfo { } } - /** Returns the needed hash pre-images and conditional path that was used to spend the input - * at inputIndex, this is calculated through the ScriptSignature and ScriptWitness + /** Returns the needed hash pre-images and conditional path that was used to + * spend the input at inputIndex, this is calculated through the + * ScriptSignature and ScriptWitness */ def getHashPreImagesAndConditionalPath( signedTransaction: Transaction, - inputIndex: Int): (Vector[NetworkElement], ConditionalPath) = { + inputIndex: Int + ): (Vector[NetworkElement], ConditionalPath) = { val txIn = signedTransaction.inputs(inputIndex) @tailrec def getPreImagesAndCondPath( scriptSignature: ScriptSignature, - conditionalPath: Vector[Boolean] = Vector.empty): ( - Vector[NetworkElement], - Vector[Boolean]) = { + conditionalPath: Vector[Boolean] = Vector.empty + ): (Vector[NetworkElement], Vector[Boolean]) = { scriptSignature match { case p2pkh: P2PKHScriptSignature => (Vector(p2pkh.publicKey), conditionalPath) @@ -144,8 +147,10 @@ object InputInfo { val path = conditionalPath :+ cond.isTrue getPreImagesAndCondPath(cond.nestedScriptSig, path) case p2sh: P2SHScriptSignature => - getPreImagesAndCondPath(p2sh.scriptSignatureNoRedeemScript, - conditionalPath) + getPreImagesAndCondPath( + p2sh.scriptSignatureNoRedeemScript, + conditionalPath + ) case _: ScriptSignature => (Vector.empty, conditionalPath) } @@ -170,7 +175,8 @@ object InputInfo { case taprootWitness @ (_: TaprootScriptPath | _: TaprootUnknownPath) => throw new UnsupportedOperationException( - s"Taproot script path not yet supported, got=$taprootWitness") + s"Taproot script path not yet supported, got=$taprootWitness" + ) } } @@ -190,12 +196,13 @@ object InputInfo { case class ScriptSigLenAndStackHeight(scriptSigLen: Int, stackHeight: Int) - /** Computes the byteSize of witness/scriptSignature for the given info, - * and also returns the number of stack elements for the P2WSH case. + /** Computes the byteSize of witness/scriptSignature for the given info, and + * also returns the number of stack elements for the P2WSH case. */ private def maxScriptSigLenAndStackHeight( info: InputInfo, - forP2WSH: Boolean): ScriptSigLenAndStackHeight = { + forP2WSH: Boolean + ): ScriptSigLenAndStackHeight = { val boolSize = if (forP2WSH) 2 else 1 info match { @@ -212,32 +219,42 @@ object InputInfo { val ScriptSigLenAndStackHeight(scriptSigLen, stackHeight) = maxScriptSigLenAndStackHeight(info.nestedInputInfo, forP2WSH) - ScriptSigLenAndStackHeight(redeemScriptLen + scriptSigLen, - stackHeight + 1) + ScriptSigLenAndStackHeight( + redeemScriptLen + scriptSigLen, + stackHeight + 1 + ) case _: EmptyInputInfo => ScriptSigLenAndStackHeight(boolSize, 1) case _: P2PKInputInfo => ScriptSigLenAndStackHeight( P2PKScriptSignature( - LowRDummyECDigitalSignature).asmBytes.length.toInt, - 1) + LowRDummyECDigitalSignature + ).asmBytes.length.toInt, + 1 + ) case _: P2PKHInputInfo => ScriptSigLenAndStackHeight( - P2PKHScriptSignature(LowRDummyECDigitalSignature, - ECPublicKey.dummy).asmBytes.length.toInt, - 2) + P2PKHScriptSignature( + LowRDummyECDigitalSignature, + ECPublicKey.dummy + ).asmBytes.length.toInt, + 2 + ) case info: P2PKWithTimeoutInputInfo => ScriptSigLenAndStackHeight( P2PKWithTimeoutScriptSignature( info.isBeforeTimeout, - LowRDummyECDigitalSignature).asmBytes.length.toInt, - 2) + LowRDummyECDigitalSignature + ).asmBytes.length.toInt, + 2 + ) case info: MultiSignatureInputInfo => ScriptSigLenAndStackHeight( MultiSignatureScriptSignature( - Vector.fill(info.requiredSigs)( - LowRDummyECDigitalSignature)).asmBytes.length.toInt, - 1 + info.requiredSigs) + Vector.fill(info.requiredSigs)(LowRDummyECDigitalSignature) + ).asmBytes.length.toInt, + 1 + info.requiredSigs + ) case info: ConditionalInputInfo => val ScriptSigLenAndStackHeight(maxLen, stackHeight) = maxScriptSigLenAndStackHeight(info.nestedInputInfo, forP2WSH) @@ -264,7 +281,8 @@ object InputInfo { maxWitnessLen(info.nestedInputInfo) case _: UnassignedSegwitNativeInputInfo => throw new IllegalArgumentException( - s"Cannot compute witness for unknown segwit InputInfo, got $info") + s"Cannot compute witness for unknown segwit InputInfo, got $info" + ) } } @@ -274,13 +292,15 @@ object InputInfo { redeemScriptOpt: Option[ScriptPubKey], scriptWitnessOpt: Option[ScriptWitness], conditionalPath: ConditionalPath, - hashPreImages: Vector[NetworkElement] = Vector.empty): InputInfo = { + hashPreImages: Vector[NetworkElement] = Vector.empty + ): InputInfo = { output.scriptPubKey match { case _: P2SHScriptPubKey => redeemScriptOpt match { case None => throw new IllegalArgumentException( - "Redeem Script must be defined for P2SH.") + "Redeem Script must be defined for P2SH." + ) case Some(redeemScript) => redeemScript match { case _: WitnessScriptPubKeyV0 => @@ -288,30 +308,38 @@ object InputInfo { case Some(witness: ScriptWitnessV0) => witness case None => throw new IllegalArgumentException( - "Script Witness must be defined for (nested) Segwit input") + "Script Witness must be defined for (nested) Segwit input" + ) case Some(_: ScriptWitness) => throw new UnsupportedOperationException( - "Only v0 Segwit is supported for wrapped segwit") + "Only v0 Segwit is supported for wrapped segwit" + ) } - P2SHNestedSegwitV0InputInfo(outPoint, - output.value, - witness, - conditionalPath, - hashPreImages) + P2SHNestedSegwitV0InputInfo( + outPoint, + output.value, + witness, + conditionalPath, + hashPreImages + ) case nonWitnessSPK: RawScriptPubKey => - P2SHNonSegwitInputInfo(outPoint, - output.value, - nonWitnessSPK, - conditionalPath, - hashPreImages) + P2SHNonSegwitInputInfo( + outPoint, + output.value, + nonWitnessSPK, + conditionalPath, + hashPreImages + ) case _: P2SHScriptPubKey => throw new IllegalArgumentException("Cannot have nested P2SH") case _: TaprootScriptPubKey => throw new UnsupportedOperationException( - s"Taproot cannot be used as a nested P2SH") + s"Taproot cannot be used as a nested P2SH" + ) case _: UnassignedWitnessScriptPubKey => throw new UnsupportedOperationException( - s"Unsupported ScriptPubKey ${output.scriptPubKey}") + s"Unsupported ScriptPubKey ${output.scriptPubKey}" + ) } } case _: WitnessScriptPubKeyV0 => @@ -319,16 +347,20 @@ object InputInfo { case Some(witness: ScriptWitnessV0) => witness case None => throw new IllegalArgumentException( - "Script Witness must be defined for Segwit input") + "Script Witness must be defined for Segwit input" + ) case Some(_: ScriptWitness) => throw new UnsupportedOperationException( - "Only v0 Segwit is currently supported") + "Only v0 Segwit is currently supported" + ) } - SegwitV0NativeInputInfo(outPoint, - output.value, - witness, - conditionalPath, - hashPreImages) + SegwitV0NativeInputInfo( + outPoint, + output.value, + witness, + conditionalPath, + hashPreImages + ) case wspk @ (_: UnassignedWitnessScriptPubKey | _: TaprootScriptPubKey) => UnassignedSegwitNativeInputInfo( outPoint, @@ -336,13 +368,16 @@ object InputInfo { wspk.asInstanceOf[WitnessScriptPubKey], scriptWitnessOpt.getOrElse(EmptyScriptWitness), conditionalPath, - Vector.empty) + Vector.empty + ) case rawSPK: RawScriptPubKey => - RawInputInfo(outPoint, - output.value, - rawSPK, - conditionalPath, - hashPreImages) + RawInputInfo( + outPoint, + output.value, + rawSPK, + conditionalPath, + hashPreImages + ) } } } @@ -358,7 +393,8 @@ object RawInputInfo { amount: CurrencyUnit, scriptPubKey: RawScriptPubKey, conditionalPath: ConditionalPath, - hashPreImages: Vector[NetworkElement] = Vector.empty): RawInputInfo = { + hashPreImages: Vector[NetworkElement] = Vector.empty + ): RawInputInfo = { scriptPubKey match { case p2pk: P2PKScriptPubKey => P2PKInputInfo(outPoint, amount, p2pk) @@ -370,11 +406,13 @@ object RawInputInfo { } match { case None => throw new IllegalArgumentException( - s"P2PKH pre-image must be specified for P2PKH ScriptPubKey, got $hashPreImages") + s"P2PKH pre-image must be specified for P2PKH ScriptPubKey, got $hashPreImages" + ) case Some(p2pkhPreImage) => require( P2PKHScriptPubKey(p2pkhPreImage) == p2pkh, - s"Specified P2PKH pre-image ($p2pkhPreImage) does not match $p2pkh") + s"Specified P2PKH pre-image ($p2pkhPreImage) does not match $p2pkh" + ) P2PKHInputInfo(outPoint, amount, p2pkhPreImage) } @@ -382,27 +420,34 @@ object RawInputInfo { conditionalPath.headOption match { case None => throw new IllegalArgumentException( - "ConditionalPath must be specified for P2PKWithTimeout") + "ConditionalPath must be specified for P2PKWithTimeout" + ) case Some(beforeTimeout) => - P2PKWithTimeoutInputInfo(outPoint, - amount, - p2pkWithTimeout, - beforeTimeout) + P2PKWithTimeoutInputInfo( + outPoint, + amount, + p2pkWithTimeout, + beforeTimeout + ) } case multiSig: MultiSignatureScriptPubKey => MultiSignatureInputInfo(outPoint, amount, multiSig) case conditional: ConditionalScriptPubKey => - ConditionalInputInfo(outPoint, - amount, - conditional, - conditionalPath, - hashPreImages) + ConditionalInputInfo( + outPoint, + amount, + conditional, + conditionalPath, + hashPreImages + ) case lockTime: LockTimeScriptPubKey => - LockTimeInputInfo(outPoint, - amount, - lockTime, - conditionalPath, - hashPreImages) + LockTimeInputInfo( + outPoint, + amount, + lockTime, + conditionalPath, + hashPreImages + ) case EmptyScriptPubKey => EmptyInputInfo(outPoint, amount) case spk @ (_: NonStandardScriptPubKey | _: WitnessCommitment) => @@ -410,7 +455,8 @@ object RawInputInfo { EmptyInputInfo(outPoint, amount) } else { throw new UnsupportedOperationException( - s"Currently unsupported ScriptPubKey $scriptPubKey") + s"Currently unsupported ScriptPubKey $scriptPubKey" + ) } } } @@ -429,14 +475,15 @@ case class EmptyInputInfo(outPoint: TransactionOutPoint, amount: CurrencyUnit) case class P2PKInputInfo( outPoint: TransactionOutPoint, amount: CurrencyUnit, - scriptPubKey: P2PKScriptPubKey) - extends RawInputInfo { + scriptPubKey: P2PKScriptPubKey +) extends RawInputInfo { override def conditionalPath: ConditionalPath = ConditionalPath.NoCondition override def pubKeys: Vector[ECPublicKey] = Vector( - scriptPubKey.publicKey.toPublicKey) + scriptPubKey.publicKey.toPublicKey + ) override def requiredSigs: Int = 1 } @@ -444,8 +491,8 @@ case class P2PKInputInfo( case class P2PKHInputInfo( outPoint: TransactionOutPoint, amount: CurrencyUnit, - pubKey: ECPublicKey) - extends RawInputInfo { + pubKey: ECPublicKey +) extends RawInputInfo { override def scriptPubKey: P2PKHScriptPubKey = P2PKHScriptPubKey(pubKey) override def conditionalPath: ConditionalPath = @@ -460,8 +507,8 @@ case class P2PKWithTimeoutInputInfo( outPoint: TransactionOutPoint, amount: CurrencyUnit, scriptPubKey: P2PKWithTimeoutScriptPubKey, - isBeforeTimeout: Boolean) - extends RawInputInfo { + isBeforeTimeout: Boolean +) extends RawInputInfo { override def conditionalPath: ConditionalPath = { if (isBeforeTimeout) { @@ -472,8 +519,10 @@ case class P2PKWithTimeoutInputInfo( } override def pubKeys: Vector[ECPublicKey] = - Vector(scriptPubKey.pubKey.toPublicKey, - scriptPubKey.timeoutPubKey.toPublicKey) + Vector( + scriptPubKey.pubKey.toPublicKey, + scriptPubKey.timeoutPubKey.toPublicKey + ) override def requiredSigs: Int = 1 } @@ -481,8 +530,8 @@ case class P2PKWithTimeoutInputInfo( case class MultiSignatureInputInfo( outPoint: TransactionOutPoint, amount: CurrencyUnit, - scriptPubKey: MultiSignatureScriptPubKey) - extends RawInputInfo { + scriptPubKey: MultiSignatureScriptPubKey +) extends RawInputInfo { override def conditionalPath: ConditionalPath = ConditionalPath.NoCondition @@ -498,8 +547,8 @@ case class ConditionalInputInfo( amount: CurrencyUnit, scriptPubKey: ConditionalScriptPubKey, conditionalPath: ConditionalPath, - hashPreImages: Vector[NetworkElement] = Vector.empty) - extends RawInputInfo { + hashPreImages: Vector[NetworkElement] = Vector.empty +) extends RawInputInfo { lazy val (condition: Boolean, nextConditionalPath: ConditionalPath) = conditionalPath match { @@ -518,11 +567,13 @@ case class ConditionalInputInfo( scriptPubKey.falseSPK } - RawInputInfo(outPoint, - amount, - nestedSPK, - nextConditionalPath, - hashPreImages) + RawInputInfo( + outPoint, + amount, + nestedSPK, + nextConditionalPath, + hashPreImages + ) } override def pubKeys: Vector[ECPublicKey] = nestedInputInfo.pubKeys @@ -543,7 +594,8 @@ case class LockTimeInputInfo( amount, scriptPubKey.nestedScriptPubKey, conditionalPath, - hashPreImages) + hashPreImages + ) override def pubKeys: Vector[ECPublicKey] = nestedInputInfo.pubKeys @@ -561,17 +613,19 @@ object SegwitV0NativeInputInfo { amount: CurrencyUnit, scriptWitness: ScriptWitnessV0, conditionalPath: ConditionalPath, - hashPreImages: Vector[NetworkElement] = - Vector.empty): SegwitV0NativeInputInfo = { + hashPreImages: Vector[NetworkElement] = Vector.empty + ): SegwitV0NativeInputInfo = { scriptWitness match { case p2wpkh: P2WPKHWitnessV0 => P2WPKHV0InputInfo(outPoint, amount, p2wpkh.pubKey.toPublicKey) case p2wsh: P2WSHWitnessV0 => - P2WSHV0InputInfo(outPoint, - amount, - p2wsh, - conditionalPath, - hashPreImages) + P2WSHV0InputInfo( + outPoint, + amount, + p2wsh, + conditionalPath, + hashPreImages + ) } } } @@ -579,8 +633,8 @@ object SegwitV0NativeInputInfo { case class P2WPKHV0InputInfo( outPoint: TransactionOutPoint, amount: CurrencyUnit, - pubKey: ECPublicKey) - extends SegwitV0NativeInputInfo { + pubKey: ECPublicKey +) extends SegwitV0NativeInputInfo { override def scriptPubKey: P2WPKHWitnessSPKV0 = P2WPKHWitnessSPKV0(pubKey) override def scriptWitness: P2WPKHWitnessV0 = P2WPKHWitnessV0(pubKey) @@ -598,18 +652,20 @@ case class P2WSHV0InputInfo( amount: CurrencyUnit, scriptWitness: P2WSHWitnessV0, conditionalPath: ConditionalPath, - hashPreImages: Vector[NetworkElement] = Vector.empty) - extends SegwitV0NativeInputInfo { + hashPreImages: Vector[NetworkElement] = Vector.empty +) extends SegwitV0NativeInputInfo { override def scriptPubKey: P2WSHWitnessSPKV0 = P2WSHWitnessSPKV0(scriptWitness.redeemScript) val nestedInputInfo: RawInputInfo = - RawInputInfo(outPoint, - amount, - scriptWitness.redeemScript, - conditionalPath, - hashPreImages) + RawInputInfo( + outPoint, + amount, + scriptWitness.redeemScript, + conditionalPath, + hashPreImages + ) override def pubKeys: Vector[ECPublicKey] = nestedInputInfo.pubKeys @@ -622,8 +678,8 @@ case class UnassignedSegwitNativeInputInfo( scriptPubKey: WitnessScriptPubKey, scriptWitness: ScriptWitness, conditionalPath: ConditionalPath, - pubKeys: Vector[ECPublicKey]) - extends InputInfo { + pubKeys: Vector[ECPublicKey] +) extends InputInfo { override def requiredSigs: Int = pubKeys.length } @@ -646,8 +702,8 @@ case class P2SHNonSegwitInputInfo( amount: CurrencyUnit, redeemScript: RawScriptPubKey, conditionalPath: ConditionalPath, - hashPreImages: Vector[NetworkElement] = Vector.empty) - extends P2SHInputInfo { + hashPreImages: Vector[NetworkElement] = Vector.empty +) extends P2SHInputInfo { override val nestedInputInfo: RawInputInfo = RawInputInfo(outPoint, amount, redeemScript, conditionalPath, hashPreImages) @@ -658,8 +714,8 @@ case class P2SHNestedSegwitV0InputInfo( amount: CurrencyUnit, scriptWitness: ScriptWitnessV0, conditionalPath: ConditionalPath, - hashPreImages: Vector[NetworkElement] = Vector.empty) - extends P2SHInputInfo { + hashPreImages: Vector[NetworkElement] = Vector.empty +) extends P2SHInputInfo { override def redeemScript: WitnessScriptPubKeyV0 = scriptWitness match { @@ -668,9 +724,11 @@ case class P2SHNestedSegwitV0InputInfo( } override val nestedInputInfo: SegwitV0NativeInputInfo = - SegwitV0NativeInputInfo(outPoint, - amount, - scriptWitness, - conditionalPath, - hashPreImages) + SegwitV0NativeInputInfo( + outPoint, + amount, + scriptWitness, + conditionalPath, + hashPreImages + ) } diff --git a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputSigningInfo.scala b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputSigningInfo.scala index 2366ea23b6..1096b7c9f0 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputSigningInfo.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InputSigningInfo.scala @@ -10,8 +10,8 @@ import org.bitcoins.core.protocol.transaction._ import org.bitcoins.crypto.{HashType, Sign} /** Stores the information required to generate a signature (ECSignatureParams) - * or to generate a script signature (ScriptSignatureParams) for a given satisfaction - * condition on a UTXO. + * or to generate a script signature (ScriptSignatureParams) for a given + * satisfaction condition on a UTXO. */ sealed trait InputSigningInfo[+InputType <: InputInfo] { def inputInfo: InputType @@ -30,12 +30,14 @@ sealed trait InputSigningInfo[+InputType <: InputInfo] { .outputs(outPoint.vout.toInt) .value == amount, s"prevTransaction output at index ${outPoint.vout.toInt} (${prevTransaction - .outputs(outPoint.vout.toInt)}) does match the corresponding value $amount" + .outputs(outPoint.vout.toInt)}) does match the corresponding value $amount" ) private val keysToSignFor = inputInfo.pubKeys - require(signers.map(_.publicKey).forall(keysToSignFor.contains), - s"Cannot have signers that do not sign for one of $keysToSignFor") + require( + signers.map(_.publicKey).forall(keysToSignFor.contains), + s"Cannot have signers that do not sign for one of $keysToSignFor" + ) def outputReference: OutputReference = inputInfo.outputReference def amount: CurrencyUnit = inputInfo.amount @@ -60,13 +62,14 @@ case class ScriptSignatureParams[+InputType <: InputInfo]( inputInfo: InputType, prevTransaction: Transaction, signers: Vector[Sign], - hashType: HashType) - extends InputSigningInfo[InputType] { + hashType: HashType +) extends InputSigningInfo[InputType] { def signer: Sign = { require( signers.length == 1, - "This method is for spending infos with a single signer, if you mean signers.head be explicit") + "This method is for spending infos with a single signer, if you mean signers.head be explicit" + ) signers.head } @@ -82,7 +85,8 @@ case class ScriptSignatureParams[+InputType <: InputInfo]( } def mapInfo[T <: InputInfo]( - func: InputType => T): ScriptSignatureParams[T] = { + func: InputType => T + ): ScriptSignatureParams[T] = { this.copy(inputInfo = func(this.inputInfo)) } @@ -97,19 +101,20 @@ object ScriptSignatureParams { inputInfo: InputType, prevTransaction: Transaction, signer: Sign, - hashType: HashType): ScriptSignatureParams[InputType] = + hashType: HashType + ): ScriptSignatureParams[InputType] = ScriptSignatureParams(inputInfo, prevTransaction, Vector(signer), hashType) } -/** Stores the information needed to generate an ECDigitalSignature for - * a use in spending a UTXO. +/** Stores the information needed to generate an ECDigitalSignature for a use in + * spending a UTXO. */ case class ECSignatureParams[+InputType <: InputInfo]( inputInfo: InputType, prevTransaction: Transaction, signer: Sign, - hashType: HashType) - extends InputSigningInfo[InputType] { + hashType: HashType +) extends InputSigningInfo[InputType] { override def signers: Vector[Sign] = Vector(signer) def toScriptSignatureParams: ScriptSignatureParams[InputType] = { diff --git a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InternalAddressTag.scala b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InternalAddressTag.scala index ee7e80bd40..2255e8bf50 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/utxo/InternalAddressTag.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/utxo/InternalAddressTag.scala @@ -2,46 +2,55 @@ package org.bitcoins.core.wallet.utxo import org.bitcoins.crypto.StringFactory -/** An AddressTagNames that is native to Bitcoin-S. - * InternalAddressTagNames are still usable when using Bitcoin-S - * as a dependency +/** An AddressTagNames that is native to Bitcoin-S. InternalAddressTagNames are + * still usable when using Bitcoin-S as a dependency */ sealed trait InternalAddressTagName extends AddressTagName -/** An AddressTagType that is native to Bitcoin-S. - * InternalAddressTagTypes are still usable when using Bitcoin-S - * as a dependency +/** An AddressTagType that is native to Bitcoin-S. InternalAddressTagTypes are + * still usable when using Bitcoin-S as a dependency */ sealed trait InternalAddressTagType extends AddressTagType -/** An AddressTag that is native to Bitcoin-S. - * InternalAddressTags are still usable when using Bitcoin-S - * as a dependency +/** An AddressTag that is native to Bitcoin-S. InternalAddressTags are still + * usable when using Bitcoin-S as a dependency */ sealed trait InternalAddressTag extends AddressTag -/** An unknown address tag name, most likely an internal representation of an [[ExternalAddressTagName]] */ +/** An unknown address tag name, most likely an internal representation of an + * [[ExternalAddressTagName]] + */ case class UnknownAddressTagName(name: String) extends InternalAddressTagName { - require(InternalAddressTagName.fromStringOpt(name).isEmpty, - s"This tag name is already defined, got $name") + require( + InternalAddressTagName.fromStringOpt(name).isEmpty, + s"This tag name is already defined, got $name" + ) } -/** An unknown address tag type, most likely an internal representation of an [[ExternalAddressTagType]] */ +/** An unknown address tag type, most likely an internal representation of an + * [[ExternalAddressTagType]] + */ case class UnknownAddressTagType(typeName: String) extends InternalAddressTagType { - require(InternalAddressTagType.fromStringOpt(typeName).isEmpty, - s"This tag type is already defined, got $typeName") + require( + InternalAddressTagType.fromStringOpt(typeName).isEmpty, + s"This tag type is already defined, got $typeName" + ) } -/** An address tag without an unknown type, most likely an internal representation of an [[ExternalAddressTag]] */ +/** An address tag without an unknown type, most likely an internal + * representation of an [[ExternalAddressTag]] + */ case class UnknownAddressTag(tagName: AddressTagName, tagType: AddressTagType) extends InternalAddressTag object UnknownAddressTag { def apply(tagName: String, tagType: String): UnknownAddressTag = - UnknownAddressTag(UnknownAddressTagName(tagName), - UnknownAddressTagType(tagType)) + UnknownAddressTag( + UnknownAddressTagName(tagName), + UnknownAddressTagType(tagType) + ) def apply(tagName: String, tagType: AddressTagType): UnknownAddressTag = UnknownAddressTag(UnknownAddressTagName(tagName), tagType) @@ -77,7 +86,8 @@ object InternalAddressTag { def apply( tagName: AddressTagName, - tagType: AddressTagType): InternalAddressTag = { + tagType: AddressTagType + ): InternalAddressTag = { tagType match { case StorageLocationTagType => tagName match { @@ -137,7 +147,9 @@ object StorageLocationTag extends AddressTagFactory[StorageLocationTag] { override val tagName: AddressTagName = ColdStorageName } - /** Keys stored on a hardware wallet or other offline device locked in a safe in a distant location */ + /** Keys stored on a hardware wallet or other offline device locked in a safe + * in a distant location + */ case object DeepColdStorage extends StorageLocationTag { override val tagName: AddressTagName = DeepColdStorageName } @@ -152,9 +164,8 @@ object AddressLabelTagType extends InternalAddressTagType { case class AddressLabelTagName(name: String) extends InternalAddressTagName -/** Used for generic address labeling, generally labels should be - * provided by the user so they keep track which parties are aware - * of which addresses +/** Used for generic address labeling, generally labels should be provided by + * the user so they keep track which parties are aware of which addresses */ case class AddressLabelTag(name: String) extends InternalAddressTag { override val tagType: AddressTagType = AddressLabelTagType diff --git a/core/src/main/scala/org/bitcoins/core/wallet/utxo/TxoState.scala b/core/src/main/scala/org/bitcoins/core/wallet/utxo/TxoState.scala index 7f0adfd50e..f47831ae3c 100644 --- a/core/src/main/scala/org/bitcoins/core/wallet/utxo/TxoState.scala +++ b/core/src/main/scala/org/bitcoins/core/wallet/utxo/TxoState.scala @@ -16,25 +16,30 @@ object TxoState extends StringFactory[TxoState] { */ final case object ImmatureCoinbase extends ReceivedState - /** Means we have received funds to this utxo, and they have not been confirmed in a block */ + /** Means we have received funds to this utxo, and they have not been + * confirmed in a block + */ final case object BroadcastReceived extends ReceivedState - /** Means we have received funds to this utxo, and they have some confirmations but - * have not reached our confirmation threshold + /** Means we have received funds to this utxo, and they have some + * confirmations but have not reached our confirmation threshold */ final case object PendingConfirmationsReceived extends ReceivedState /** Means we have received funds and they are fully confirmed for this utxo */ final case object ConfirmedReceived extends ReceivedState - /** Means we have not spent this utxo yet, but will be used in a future transaction */ + /** Means we have not spent this utxo yet, but will be used in a future + * transaction + */ final case object Reserved extends SpentState - /** Means we have spent this utxo, and they have not been confirmed in a block */ + /** Means we have spent this utxo, and they have not been confirmed in a block + */ final case object BroadcastSpent extends SpentState - /** Means we have spent this utxo, and they have some confirmations but - * have not reached our confirmation threshold + /** Means we have spent this utxo, and they have some confirmations but have + * not reached our confirmation threshold */ final case object PendingConfirmationsSpent extends SpentState @@ -56,10 +61,12 @@ object TxoState extends StringFactory[TxoState] { Set(TxoState.ConfirmedReceived, TxoState.ConfirmedSpent) val receivedStates: Set[TxoState] = - Set(PendingConfirmationsReceived, - ConfirmedReceived, - BroadcastReceived, - TxoState.ImmatureCoinbase) + Set( + PendingConfirmationsReceived, + ConfirmedReceived, + BroadcastReceived, + TxoState.ImmatureCoinbase + ) val spentStates: Set[TxoState] = Set(PendingConfirmationsSpent, TxoState.ConfirmedSpent, BroadcastSpent) diff --git a/crypto-test/.js/src/test/scala/org/bitcoins/crypto/SigningTest.scala b/crypto-test/.js/src/test/scala/org/bitcoins/crypto/SigningTest.scala index fea1345636..25889f518e 100644 --- a/crypto-test/.js/src/test/scala/org/bitcoins/crypto/SigningTest.scala +++ b/crypto-test/.js/src/test/scala/org/bitcoins/crypto/SigningTest.scala @@ -26,14 +26,16 @@ class SigningTest extends BitcoinSCryptoTest { it must "pass the BIP 340 test-vectors with bcrypto" in { BIP340TestVectors.vectors.foreach { case (index, secKeyOpt, pubKey, auxRandOpt, msg, sig, result, comment) => - test(index = index, - secKeyOpt = secKeyOpt, - pubKey = pubKey, - auxRandOpt = auxRandOpt, - msg = msg, - sig = sig, - result = result, - comment = comment) + test( + index = index, + secKeyOpt = secKeyOpt, + pubKey = pubKey, + auxRandOpt = auxRandOpt, + msg = msg, + sig = sig, + result = result, + comment = comment + ) } } @@ -45,7 +47,8 @@ class SigningTest extends BitcoinSCryptoTest { msg: String, sig: String, result: Boolean, - comment: String): Assertion = { + comment: String + ): Assertion = { val pkT = Try(SchnorrPublicKey(pubKey)) val msgBytes = ByteVector.fromHex(msg).get val schnorrSigT = Try(SchnorrDigitalSignature(sig)) @@ -75,11 +78,14 @@ class SigningTest extends BitcoinSCryptoTest { secKey: ECPrivateKey, auxRand: ByteVector, msg: ByteVector, - expectedSig: SchnorrDigitalSignature): Assertion = { + expectedSig: SchnorrDigitalSignature + ): Assertion = { val bcryptoSig = BCryptoCryptoRuntime.schnorrSign(msg, secKey, auxRand) - assert(bcryptoSig == expectedSig, - s"Test $index failed signing for Bouncy Castle") + assert( + bcryptoSig == expectedSig, + s"Test $index failed signing for Bouncy Castle" + ) } def testVerify( @@ -88,11 +94,14 @@ class SigningTest extends BitcoinSCryptoTest { msg: ByteVector, sig: SchnorrDigitalSignature, expectedResult: Boolean, - comment: String): Assertion = { + comment: String + ): Assertion = { val bcryptoResult = BCryptoCryptoRuntime.schnorrVerify(msg, pubKey, sig) - assert(bcryptoResult == expectedResult, - s"Test $index failed verification for Bouncy Castle: $comment") + assert( + bcryptoResult == expectedResult, + s"Test $index failed verification for Bouncy Castle: $comment" + ) } } diff --git a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/AesCryptTest.scala b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/AesCryptTest.scala index e17ca2561c..2a44fdecbb 100644 --- a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/AesCryptTest.scala +++ b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/AesCryptTest.scala @@ -23,8 +23,7 @@ class AesCryptTest extends BitcoinSCryptoTest { * * Here's a link to the first test vector: * https://gchq.github.io/CyberChef/#recipe=AES_Encrypt(%7B'option':'Hex','string':'2eefdf6ee2dbca83e7b7648a8f9d1897'%7D,%7B'option':'Hex','string':'889dc64377f6d993ef713c995f9c1ee5'%7D,'CFB','Hex','Hex')&input=NzZmZTM1ODgwMDU1ZTFmYWM5NTBmNDg0YTgxNWNkMjI - * The other vectors can be replicated by tweaking the values - * in the UI. + * The other vectors can be replicated by tweaking the values in the UI. */ it must "decrypt and encrypt some hard coded test vectors" in { case class TestVector( @@ -98,7 +97,7 @@ class AesCryptTest extends BitcoinSCryptoTest { case Right(b) => b } val iv = getIV(hex"455014871CD34F8DCFD7C1E387987BFF") - //val expectedCipher = ByteVector.fromValidBase64("oE8HErg1lg==") + // val expectedCipher = ByteVector.fromValidBase64("oE8HErg1lg==") val encrypted = AesCrypt.encryptWithIV(plainbytes, iv, key) @@ -123,23 +122,19 @@ class AesCryptTest extends BitcoinSCryptoTest { } - /** REPL.it: https://repl.it/@torkelrogstad/aes-test - * To replicate: - * const CryptoJS = require("crypto-js") - * const text = "The quick brown fox jumps over the lazy dog. 👻 👻"; + /** REPL.it: https://repl.it/@torkelrogstad/aes-test To replicate: const + * CryptoJS = require("crypto-js") const text = "The quick brown fox jumps + * over the lazy dog. 👻 👻"; * * const key = CryptoJS.enc.Hex.parse("12345678123456781234567812345678") * * const iv = CryptoJS.enc.Hex.parse("87654321876543218765432187654321") * - * const encrypted = CryptoJS.AES.encrypt(text, key, { - * mode: CryptoJS.mode.CFB, - * padding: CryptoJS.pad.NoPadding, - * iv: iv - * }) + * const encrypted = CryptoJS.AES.encrypt(text, key, { mode: + * CryptoJS.mode.CFB, padding: CryptoJS.pad.NoPadding, iv: iv }) * - * console.log(encrypted.toString()) - * // KKbLXDQUy7ajmuIJm7ZR7ugaRubqGl1JwG+x5C451JXIFofnselHVTy/u8u0Or9nV2d7Kjy0 + * console.log(encrypted.toString()) // + * KKbLXDQUy7ajmuIJm7ZR7ugaRubqGl1JwG+x5C451JXIFofnselHVTy/u8u0Or9nV2d7Kjy0 */ it must "pass a hardcoded crypto-js vector where we decrypt with a key" in { val key = getKey(hex"12345678123456781234567812345678") @@ -200,73 +195,52 @@ class AesCryptTest extends BitcoinSCryptoTest { /** To replicate: * - * from Crypto import Random - * from Crypto.Cipher import AES - * import base64 - * from binascii import unhexlify - * import binascii - * import math + * from Crypto import Random from Crypto.Cipher import AES import base64 from + * binascii import unhexlify import binascii import math * * text = "The quick brown fox jumps over the lazy dog." * * SEGMENT_SIZE = 128 * - * # BLOCK_SIZE can be 16, 24 or 32 - * # key must be same number of bytes - * BLOCK_SIZE = 16 - * key = "e67a00b510bcff7f4a0101ff5f7fb690" - * assert len(bytes.fromhex(key)) == BLOCK_SIZE + * # BLOCK_SIZE can be 16, 24 or 32 # key must be same number of bytes + * BLOCK_SIZE = 16 key = "e67a00b510bcff7f4a0101ff5f7fb690" assert + * len(bytes.fromhex(key)) == BLOCK_SIZE * - * # IV must always be 16 bytes in CFB mode - * IV_SIZE = 16 - * iv = "f43b7f80624e7f01123ac272beb1ff7f" - * assert len(bytes.fromhex(iv)) == IV_SIZE + * # IV must always be 16 bytes in CFB mode IV_SIZE = 16 iv = + * "f43b7f80624e7f01123ac272beb1ff7f" assert len(bytes.fromhex(iv)) == + * IV_SIZE * - * def pad(value): - * """Pads the given string with zero-bytes""" - * length = len(value) + * def pad(value): """Pads the given string with zero-bytes""" length = + * len(value) * - * pad_size = BLOCK_SIZE - (length % BLOCK_SIZE) + * pad_size = BLOCK_SIZE - (length % BLOCK_SIZE) * - * return value.ljust(length + pad_size, "\x00") + * return value.ljust(length + pad_size, "\x00") * - * def unpad(value): - * """Removes trailing zero-bytes from the given string""" - * while value[-1] == "\x00": - * value = value[:-1] + * def unpad(value): """Removes trailing zero-bytes from the given string""" + * while value[-1] == "\x00": value = value[:-1] * - * return value + * return value * - * def encrypt(in_string, key, iv): - * """ - * Takes in a plain string to encrypt, as well as - * hex representations of the key and IV - * """ - * key = unhexlify(key) - * iv = unhexlify(iv) - * aes = AES.new(key, AES.MODE_CFB, IV=iv, segment_size=SEGMENT_SIZE) - * padded = pad(in_string) - * return aes.encrypt(padded) + * def encrypt(in_string, key, iv): """ Takes in a plain string to encrypt, + * as well as hex representations of the key and IV """ key = unhexlify(key) + * iv = unhexlify(iv) aes = AES.new(key, AES.MODE_CFB, IV=iv, + * segment_size=SEGMENT_SIZE) padded = pad(in_string) return + * aes.encrypt(padded) * - * def decrypt(encrypted, key, iv): - * """ - * Takes in a bytes object to decrypt, as well as - * hex representations of the key and IV - * """ - * key = unhexlify(key) - * iv = unhexlify(iv) - * aes = AES.new(key, AES.MODE_CFB, IV=iv, segment_size=SEGMENT_SIZE) - * decrypted = aes.decrypt(encrypted) - * return unpad(decrypted) + * def decrypt(encrypted, key, iv): """ Takes in a bytes object to decrypt, + * as well as hex representations of the key and IV """ key = unhexlify(key) + * iv = unhexlify(iv) aes = AES.new(key, AES.MODE_CFB, IV=iv, + * segment_size=SEGMENT_SIZE) decrypted = aes.decrypt(encrypted) return + * unpad(decrypted) * - * encrypted = encrypt(text, key, iv) - * print(f"encrypted: {encrypted.hex()}") + * encrypted = encrypt(text, key, iv) print(f"encrypted: {encrypted.hex()}") */ it must "pass a hard coded test vector from pycrypto" in { /** Asserts that the two bytevectors are equal expect for trailing padding. - * Pycrypto has issues with encrypting plaintexts that don't line up - * with block size, so this is only used here. + * Pycrypto has issues with encrypting plaintexts that don't line up with + * block size, so this is only used here. */ def assertPaddedEqual(first: ByteVector, second: ByteVector): Assertion = { if (first.length == second.length) { @@ -321,12 +295,10 @@ class AesCryptTest extends BitcoinSCryptoTest { case Right(b) => b } - /** The AES implementation in pycrypto refuses to work with - * data that's not padded to the block size (although this - * should be possible with AES CFB encryption...). On - * the pycrypto side we therefore have to add some - * padding, which leads to trailing zero bytes in the - * plaintext + /** The AES implementation in pycrypto refuses to work with data that's + * not padded to the block size (although this should be possible with + * AES CFB encryption...). On the pycrypto side we therefore have to add + * some padding, which leads to trailing zero bytes in the plaintext */ assertPaddedEqual(decrypted, plainbytes) diff --git a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleBIP340Test.scala b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleBIP340Test.scala index d4baae49bb..d977a72cd0 100644 --- a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleBIP340Test.scala +++ b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleBIP340Test.scala @@ -5,7 +5,9 @@ import scodec.bits.ByteVector import scala.util.{Failure, Success, Try} -/** Tests from https://github.com/sipa/bips/blob/bip-taproot/bip-0340/test-vectors.csv */ +/** Tests from + * https://github.com/sipa/bips/blob/bip-taproot/bip-0340/test-vectors.csv + */ class BouncyCastleBIP340Test extends BitcoinSCryptoTest { behavior of "Schnorr Signing" @@ -14,14 +16,19 @@ class BouncyCastleBIP340Test extends BitcoinSCryptoTest { secKey: ECPrivateKey, auxRand: ByteVector, msg: ByteVector, - expectedSig: SchnorrDigitalSignature): Assertion = { + expectedSig: SchnorrDigitalSignature + ): Assertion = { val secpSig = secKey.schnorrSign(msg, auxRand) val bouncyCastleSig = BouncycastleCryptoRuntime.schnorrSign(msg, secKey, auxRand) - assert(secpSig == expectedSig, - s"Test $index failed signing for libsecp256k1") - assert(bouncyCastleSig == expectedSig, - s"Test $index failed signing for Bouncy Castle") + assert( + secpSig == expectedSig, + s"Test $index failed signing for libsecp256k1" + ) + assert( + bouncyCastleSig == expectedSig, + s"Test $index failed signing for Bouncy Castle" + ) assert(bouncyCastleSig == secpSig) } @@ -31,15 +38,20 @@ class BouncyCastleBIP340Test extends BitcoinSCryptoTest { msg: ByteVector, sig: SchnorrDigitalSignature, expectedResult: Boolean, - comment: String): Assertion = { + comment: String + ): Assertion = { val secpResult = Try(pubKey.verify(msg, sig)).getOrElse(false) val bouncyCastleResult = Try(BouncycastleCryptoRuntime.schnorrVerify(msg, pubKey, sig)) .getOrElse(false) - assert(secpResult == expectedResult, - s"Test $index failed verification for libsecp256k1: $comment") - assert(bouncyCastleResult == expectedResult, - s"Test $index failed verification for Bouncy Castle: $comment") + assert( + secpResult == expectedResult, + s"Test $index failed verification for libsecp256k1: $comment" + ) + assert( + bouncyCastleResult == expectedResult, + s"Test $index failed verification for Bouncy Castle: $comment" + ) assert(bouncyCastleResult == secpResult) } @@ -51,7 +63,8 @@ class BouncyCastleBIP340Test extends BitcoinSCryptoTest { msg: String, sig: String, result: Boolean, - comment: String): Assertion = { + comment: String + ): Assertion = { val pkT = Try(SchnorrPublicKey(pubKey)) val msgBytes = ByteVector.fromHex(msg).get val schnorrSigT = Try(SchnorrDigitalSignature(sig)) @@ -79,14 +92,16 @@ class BouncyCastleBIP340Test extends BitcoinSCryptoTest { it must "pass the BIP 340 test-vectors with both secp256k1 bindings and bouncy castle" in { BIP340TestVectors.vectors.foreach { case (index, secKeyOpt, pubKey, auxRandOpt, msg, sig, result, comment) => - test(index = index, - secKeyOpt = secKeyOpt, - pubKey = pubKey, - auxRandOpt = auxRandOpt, - msg = msg, - sig = sig, - result = result, - comment = comment) + test( + index = index, + secKeyOpt = secKeyOpt, + pubKey = pubKey, + auxRandOpt = auxRandOpt, + msg = msg, + sig = sig, + result = result, + comment = comment + ) } } } diff --git a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleECAdaptorSignatureTest.scala b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleECAdaptorSignatureTest.scala index c08e4b4059..64c9ba5b4f 100644 --- a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleECAdaptorSignatureTest.scala +++ b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleECAdaptorSignatureTest.scala @@ -3,7 +3,8 @@ package org.bitcoins.crypto import org.scalatest.Assertion import scodec.bits.ByteVector -/** Executes tests at https://github.com/discreetlogcontracts/dlcspecs/blob/9b11bcc99341ad40d8ae146d5d3ead116d5bb131/test/ecdsa_adaptor.json +/** Executes tests at + * https://github.com/discreetlogcontracts/dlcspecs/blob/9b11bcc99341ad40d8ae146d5d3ead116d5bb131/test/ecdsa_adaptor.json * along with some static signing tests Jesse generated. */ class BouncyCastleECAdaptorSignatureTest extends BitcoinSCryptoTest { @@ -16,7 +17,8 @@ class BouncyCastleECAdaptorSignatureTest extends BitcoinSCryptoTest { pubKey: String, encKey: String, auxRand: String, - adaptorSig: String): Assertion = { + adaptorSig: String + ): Assertion = { testSign( ECPrivateKey(secKey), ByteVector.fromValidHex(msg), @@ -35,18 +37,22 @@ class BouncyCastleECAdaptorSignatureTest extends BitcoinSCryptoTest { pubKey: ECPublicKey, encKey: ECPublicKey, auxRand: ByteVector, - adaptorSig: ECAdaptorSignature): Assertion = { + adaptorSig: ECAdaptorSignature + ): Assertion = { assert(pubKey == secKey.publicKey) assert( BouncycastleCryptoRuntime - .adaptorSign(secKey, encKey, msg, auxRand) == adaptorSig) + .adaptorSign(secKey, encKey, msg, auxRand) == adaptorSig + ) assert( - BouncycastleCryptoRuntime.adaptorVerify(adaptorSig, pubKey, msg, encKey)) + BouncycastleCryptoRuntime.adaptorVerify(adaptorSig, pubKey, msg, encKey) + ) val sigBC = BouncycastleCryptoRuntime.adaptorComplete(decKey, adaptorSig) assert( BouncycastleCryptoRuntime - .extractAdaptorSecret(sigBC, adaptorSig, encKey) == decKey) + .extractAdaptorSecret(sigBC, adaptorSig, encKey) == decKey + ) } it must "pass Jesse's static test vectors" in { @@ -133,110 +139,153 @@ class BouncyCastleECAdaptorSignatureTest extends BitcoinSCryptoTest { it must "pass happy path verification test" in { val adaptorSig = ECAdaptorSignature( - "03424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb6730223f325042fce535d040fee52ec13231bf709ccd84233c6944b90317e62528b2527dff9d659a96db4c99f9750168308633c1867b70f3a18fb0f4539a1aecedcd1fc0148fc22f36b6303083ece3f872b18e35d368b3958efe5fb081f7716736ccb598d269aa3084d57e1855e1ea9a45efc10463bbf32ae378029f5763ceb40173f") + "03424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb6730223f325042fce535d040fee52ec13231bf709ccd84233c6944b90317e62528b2527dff9d659a96db4c99f9750168308633c1867b70f3a18fb0f4539a1aecedcd1fc0148fc22f36b6303083ece3f872b18e35d368b3958efe5fb081f7716736ccb598d269aa3084d57e1855e1ea9a45efc10463bbf32ae378029f5763ceb40173f" + ) val msg = ByteVector.fromValidHex( - "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d") + "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d" + ) val pubKey = ECPublicKey( - "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c") + "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c" + ) val encKey = ECPublicKey( - "02c2662c97488b07b6e819124b8989849206334a4c2fbdf691f7b34d2b16e9c293") + "02c2662c97488b07b6e819124b8989849206334a4c2fbdf691f7b34d2b16e9c293" + ) val decKey = ECPrivateKey( - "0b2aba63b885a0f0e96fa0f303920c7fb7431ddfa94376ad94d969fbf4109dc8") + "0b2aba63b885a0f0e96fa0f303920c7fb7431ddfa94376ad94d969fbf4109dc8" + ) val signature = ECDigitalSignature.fromRS( - "424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb67329e80e0ee60e57af3e625bbae1672b1ecaa58effe613426b024fa1621d903394") + "424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb67329e80e0ee60e57af3e625bbae1672b1ecaa58effe613426b024fa1621d903394" + ) assert( - BouncycastleCryptoRuntime.adaptorVerify(adaptorSig, pubKey, msg, encKey)) + BouncycastleCryptoRuntime.adaptorVerify(adaptorSig, pubKey, msg, encKey) + ) assert( - BouncycastleCryptoRuntime.adaptorComplete(decKey, - adaptorSig) == signature) + BouncycastleCryptoRuntime.adaptorComplete(decKey, adaptorSig) == signature + ) assert( - BouncycastleCryptoRuntime.extractAdaptorSecret(signature, - adaptorSig, - encKey) == decKey) + BouncycastleCryptoRuntime.extractAdaptorSecret( + signature, + adaptorSig, + encKey + ) == decKey + ) } it must "pass ECDSA malleable verification test" in { val adaptorSig = ECAdaptorSignature( - "036035c89860ec62ad153f69b5b3077bcd08fbb0d28dc7f7f6df4a05cca35455be037043b63c56f6317d9928e8f91007335748c49824220db14ad10d80a5d00a9654af0996c1824c64c90b951bb2734aaecf78d4b36131a47238c3fa2ba25e2ced54255b06df696de1483c3767242a3728826e05f79e3981e12553355bba8a0131cd370e63e3da73106f638576a5aab0ea6d45c042574c0c8d0b14b8c7c01cfe9072") + "036035c89860ec62ad153f69b5b3077bcd08fbb0d28dc7f7f6df4a05cca35455be037043b63c56f6317d9928e8f91007335748c49824220db14ad10d80a5d00a9654af0996c1824c64c90b951bb2734aaecf78d4b36131a47238c3fa2ba25e2ced54255b06df696de1483c3767242a3728826e05f79e3981e12553355bba8a0131cd370e63e3da73106f638576a5aab0ea6d45c042574c0c8d0b14b8c7c01cfe9072" + ) val msg = ByteVector.fromValidHex( - "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d") + "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d" + ) val pubKey = ECPublicKey( - "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c") + "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c" + ) val encKey = ECPublicKey( - "024eee18be9a5a5224000f916c80b393447989e7194bc0b0f1ad7a03369702bb51") + "024eee18be9a5a5224000f916c80b393447989e7194bc0b0f1ad7a03369702bb51" + ) val decKey = ECPrivateKey( - "db2debddb002473a001dd70b06f6c97bdcd1c46ba1001237fe0ee1aeffb2b6c4") + "db2debddb002473a001dd70b06f6c97bdcd1c46ba1001237fe0ee1aeffb2b6c4" + ) val signature = ECDigitalSignature.fromRS( - "6035c89860ec62ad153f69b5b3077bcd08fbb0d28dc7f7f6df4a05cca35455be4ceacf921546c03dd1be596723ad1e7691bdac73d88cc36c421c5e7f08384305") + "6035c89860ec62ad153f69b5b3077bcd08fbb0d28dc7f7f6df4a05cca35455be4ceacf921546c03dd1be596723ad1e7691bdac73d88cc36c421c5e7f08384305" + ) assert( - BouncycastleCryptoRuntime.adaptorVerify(adaptorSig, pubKey, msg, encKey)) + BouncycastleCryptoRuntime.adaptorVerify(adaptorSig, pubKey, msg, encKey) + ) assert( - BouncycastleCryptoRuntime.adaptorComplete(decKey, - adaptorSig) == signature) + BouncycastleCryptoRuntime.adaptorComplete(decKey, adaptorSig) == signature + ) assert( - BouncycastleCryptoRuntime.extractAdaptorSecret(signature, - adaptorSig, - encKey) == decKey) + BouncycastleCryptoRuntime.extractAdaptorSecret( + signature, + adaptorSig, + encKey + ) == decKey + ) } it must "fail to validate a false proof" in { val adaptorSig = ECAdaptorSignature( - "03f94dca206d7582c015fb9bffe4e43b14591b30ef7d2b464d103ec5e116595dba03127f8ac3533d249280332474339000922eb6a58e3b9bf4fc7e01e4b4df2b7a4100a1e089f16e5d70bb89f961516f1de0684cc79db978495df2f399b0d01ed7240fa6e3252aedb58bdc6b5877b0c602628a235dd1ccaebdddcbe96198c0c21bead7b05f423b673d14d206fa1507b2dbe2722af792b8c266fc25a2d901d7e2c335") + "03f94dca206d7582c015fb9bffe4e43b14591b30ef7d2b464d103ec5e116595dba03127f8ac3533d249280332474339000922eb6a58e3b9bf4fc7e01e4b4df2b7a4100a1e089f16e5d70bb89f961516f1de0684cc79db978495df2f399b0d01ed7240fa6e3252aedb58bdc6b5877b0c602628a235dd1ccaebdddcbe96198c0c21bead7b05f423b673d14d206fa1507b2dbe2722af792b8c266fc25a2d901d7e2c335" + ) val msg = ByteVector.fromValidHex( - "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d") + "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d" + ) val pubKey = ECPublicKey( - "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c") + "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c" + ) val encKey = ECPublicKey( - "0214ccb756249ad6e733c80285ea7ac2ee12ffebbcee4e556e6810793a60c45ad4") + "0214ccb756249ad6e733c80285ea7ac2ee12ffebbcee4e556e6810793a60c45ad4" + ) assert( - !BouncycastleCryptoRuntime.adaptorVerify(adaptorSig, pubKey, msg, encKey)) + !BouncycastleCryptoRuntime.adaptorVerify(adaptorSig, pubKey, msg, encKey) + ) } it must "pass happy path recovery test" in { val adaptorSig = ECAdaptorSignature( - "03f2db6e9ed33092cc0b898fd6b282e99bdaeccb3de85c2d2512d8d507f9abab290210c01b5bed7094a12664aeaab3402d8709a8f362b140328d1b36dd7cb420d02fb66b1230d61c16d0cd0a2a02246d5ac7848dcd6f04fe627053cd3c7015a7d4aa6ac2b04347348bd67da43be8722515d99a7985fbfa66f0365c701de76ff0400dffdc9fa84dddf413a729823b16af60aa6361bc32e7cfd6701e32957c72ace67b") + "03f2db6e9ed33092cc0b898fd6b282e99bdaeccb3de85c2d2512d8d507f9abab290210c01b5bed7094a12664aeaab3402d8709a8f362b140328d1b36dd7cb420d02fb66b1230d61c16d0cd0a2a02246d5ac7848dcd6f04fe627053cd3c7015a7d4aa6ac2b04347348bd67da43be8722515d99a7985fbfa66f0365c701de76ff0400dffdc9fa84dddf413a729823b16af60aa6361bc32e7cfd6701e32957c72ace67b" + ) val encKey = ECPublicKey( - "027ee4f899bc9c5f2b626fa1a9b37ce291c0388b5227e90b0fd8f4fa576164ede7") + "027ee4f899bc9c5f2b626fa1a9b37ce291c0388b5227e90b0fd8f4fa576164ede7" + ) val decKey = ECPrivateKey( - "9cf3ea9be594366b78c457162908af3c2ea177058177e9c6bf99047927773a06") + "9cf3ea9be594366b78c457162908af3c2ea177058177e9c6bf99047927773a06" + ) val signature = ECDigitalSignature.fromRS( - "f2db6e9ed33092cc0b898fd6b282e99bdaeccb3de85c2d2512d8d507f9abab2921811fe7b53becf3b7affa9442abaa93c0ab8a8e45cd7ee2ea8d258bfc25d464") + "f2db6e9ed33092cc0b898fd6b282e99bdaeccb3de85c2d2512d8d507f9abab2921811fe7b53becf3b7affa9442abaa93c0ab8a8e45cd7ee2ea8d258bfc25d464" + ) assert( - BouncycastleCryptoRuntime.extractAdaptorSecret(signature, - adaptorSig, - encKey) == decKey) + BouncycastleCryptoRuntime.extractAdaptorSecret( + signature, + adaptorSig, + encKey + ) == decKey + ) } it must "fail to extract a secret on unrelated signatures" in { val adaptorSig = ECAdaptorSignature( - "03aa86d78059a91059c29ec1a757c4dc029ff636a1e6c1142fefe1e9d7339617c003a8153e50c0c8574a38d389e61bbb0b5815169e060924e4b5f2e78ff13aa7ad858e0c27c4b9eed9d60521b3f54ff83ca4774be5fb3a680f820a35e8840f4aaf2de88e7c5cff38a37b78725904ef97bb82341328d55987019bd38ae1745e3efe0f8ea8bdfede0d378fc1f96e944a7505249f41e93781509ee0bade77290d39cd12") + "03aa86d78059a91059c29ec1a757c4dc029ff636a1e6c1142fefe1e9d7339617c003a8153e50c0c8574a38d389e61bbb0b5815169e060924e4b5f2e78ff13aa7ad858e0c27c4b9eed9d60521b3f54ff83ca4774be5fb3a680f820a35e8840f4aaf2de88e7c5cff38a37b78725904ef97bb82341328d55987019bd38ae1745e3efe0f8ea8bdfede0d378fc1f96e944a7505249f41e93781509ee0bade77290d39cd12" + ) val encKey = ECPublicKey( - "035176d24129741b0fcaa5fd6750727ce30860447e0a92c9ebebdeb7c3f93995ed") + "035176d24129741b0fcaa5fd6750727ce30860447e0a92c9ebebdeb7c3f93995ed" + ) val signature = ECDigitalSignature.fromRS( - "f7f7fe6bd056fc4abd70d335f72d0aa1e8406bba68f3e579e4789475323564a452c46176c7fb40aa37d5651341f55697dab27d84a213b30c93011a7790bace8c") + "f7f7fe6bd056fc4abd70d335f72d0aa1e8406bba68f3e579e4789475323564a452c46176c7fb40aa37d5651341f55697dab27d84a213b30c93011a7790bace8c" + ) assertThrows[Exception]( BouncycastleCryptoRuntime - .extractAdaptorSecret(signature, adaptorSig, encKey)) + .extractAdaptorSecret(signature, adaptorSig, encKey) + ) } it must "pass recovery test for high s value" in { val adaptorSig = ECAdaptorSignature( - "032c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b1403eb615a3e59b1cbbf4f87acaf645be1eda32a066611f35dd5557802802b14b19c81c04c3fefac5783b2077bd43fa0a39ab8a64d4d78332a5d621ea23eca46bc011011ab82dda6deb85699f508744d70d4134bea03f784d285b5c6c15a56e4e1fab4bc356abbdebb3b8fe1e55e6dd6d2a9ea457e91b2e6642fae69f9dbb5258854") + "032c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b1403eb615a3e59b1cbbf4f87acaf645be1eda32a066611f35dd5557802802b14b19c81c04c3fefac5783b2077bd43fa0a39ab8a64d4d78332a5d621ea23eca46bc011011ab82dda6deb85699f508744d70d4134bea03f784d285b5c6c15a56e4e1fab4bc356abbdebb3b8fe1e55e6dd6d2a9ea457e91b2e6642fae69f9dbb5258854" + ) val encKey = ECPublicKey( - "02042537e913ad74c4bbd8da9607ad3b9cb297d08e014afc51133083f1bd687a62") + "02042537e913ad74c4bbd8da9607ad3b9cb297d08e014afc51133083f1bd687a62" + ) val decKey = ECPrivateKey( - "324719b51ff2474c9438eb76494b0dc0bcceeb529f0a5428fd198ad8f886e99c") + "324719b51ff2474c9438eb76494b0dc0bcceeb529f0a5428fd198ad8f886e99c" + ) val signature = ECDigitalSignature.fromRS( - "2c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b14b5f24321f550b7b9dd06ee4fcfd82bdad8b142ff93a790cc4d9f7962b38c6a3b") + "2c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b14b5f24321f550b7b9dd06ee4fcfd82bdad8b142ff93a790cc4d9f7962b38c6a3b" + ) assert( - BouncycastleCryptoRuntime.extractAdaptorSecret(signature, - adaptorSig, - encKey) == decKey) + BouncycastleCryptoRuntime.extractAdaptorSecret( + signature, + adaptorSig, + encKey + ) == decKey + ) } } diff --git a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleSecp256k1Test.scala b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleSecp256k1Test.scala index c5485b444e..c451dc3571 100644 --- a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleSecp256k1Test.scala +++ b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/BouncyCastleSecp256k1Test.scala @@ -49,7 +49,8 @@ class BouncyCastleSecp256k1Test extends BitcoinSCryptoTest { it must "decompress edge case keys the same" in { val pubKeyBytes = ByteVector.fromValidHex( - "03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c") + "03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c" + ) testCompatibility(_.decompressed(pubKeyBytes)) } @@ -67,17 +68,21 @@ class BouncyCastleSecp256k1Test extends BitcoinSCryptoTest { } it must "compute signatures with entropy the same" in { - forAll(CryptoGenerators.privateKey, - NumberGenerator.bytevector(32), - NumberGenerator.bytevector(32)) { case (privKey, bytes, entropy) => + forAll( + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32), + NumberGenerator.bytevector(32) + ) { case (privKey, bytes, entropy) => testCompatibility(_.signWithEntropy(privKey, bytes, entropy)) } } it must "verify signatures the same" in { - forAll(CryptoGenerators.privateKey, - NumberGenerator.bytevector(32), - CryptoGenerators.digitalSignature) { case (privKey, bytes, badSig) => + forAll( + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32), + CryptoGenerators.digitalSignature + ) { case (privKey, bytes, badSig) => val sig = privKey.sign(bytes) val pubKey = privKey.publicKey @@ -87,64 +92,74 @@ class BouncyCastleSecp256k1Test extends BitcoinSCryptoTest { } it must "compute schnorr signatures the same" in { - forAll(CryptoGenerators.privateKey, - NumberGenerator.bytevector(32), - NumberGenerator.bytevector(32)) { case (privKey, bytes, auxRand) => + forAll( + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32), + NumberGenerator.bytevector(32) + ) { case (privKey, bytes, auxRand) => testCompatibility(_.schnorrSign(bytes, privKey, auxRand)) } } it must "compute schnorr signature for fixed nonce the same" in { - forAll(CryptoGenerators.privateKey, - CryptoGenerators.privateKey, - NumberGenerator.bytevector(32)) { case (privKey, nonceKey, bytes) => + forAll( + CryptoGenerators.privateKey, + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32) + ) { case (privKey, nonceKey, bytes) => testCompatibility(_.schnorrSignWithNonce(bytes, privKey, nonceKey)) } } it must "validate schnorr signatures the same" in { - forAll(CryptoGenerators.privateKey, - NumberGenerator.bytevector(32), - CryptoGenerators.schnorrDigitalSignature) { - case (privKey, bytes, badSig) => - val sig = privKey.schnorrSign(bytes) - val pubKey = privKey.schnorrPublicKey + forAll( + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32), + CryptoGenerators.schnorrDigitalSignature + ) { case (privKey, bytes, badSig) => + val sig = privKey.schnorrSign(bytes) + val pubKey = privKey.schnorrPublicKey - testCompatibility(_.schnorrVerify(bytes, pubKey, sig)) - testCompatibility(_.schnorrVerify(bytes, pubKey, badSig)) + testCompatibility(_.schnorrVerify(bytes, pubKey, sig)) + testCompatibility(_.schnorrVerify(bytes, pubKey, badSig)) } } it must "compute schnorr signature points the same" in { - forAll(CryptoGenerators.schnorrPublicKey, - CryptoGenerators.schnorrNonce, - NumberGenerator.bytevector(32)) { case (pubKey, nonce, bytes) => + forAll( + CryptoGenerators.schnorrPublicKey, + CryptoGenerators.schnorrNonce, + NumberGenerator.bytevector(32) + ) { case (pubKey, nonce, bytes) => testCompatibility( - _.schnorrComputeSigPoint(bytes, nonce, pubKey, compressed = true)) + _.schnorrComputeSigPoint(bytes, nonce, pubKey, compressed = true) + ) } } it must "compute adaptor signatures the same" in { - forAll(CryptoGenerators.privateKey, - CryptoGenerators.publicKey, - NumberGenerator.bytevector(32), - NumberGenerator.bytevector(32)) { - case (privKey, adaptor, msg, auxRand) => - testCompatibility(_.adaptorSign(privKey, adaptor, msg, auxRand)) + forAll( + CryptoGenerators.privateKey, + CryptoGenerators.publicKey, + NumberGenerator.bytevector(32), + NumberGenerator.bytevector(32) + ) { case (privKey, adaptor, msg, auxRand) => + testCompatibility(_.adaptorSign(privKey, adaptor, msg, auxRand)) } } it must "verify adaptor signatures the same" in { - forAll(CryptoGenerators.privateKey, - CryptoGenerators.publicKey, - NumberGenerator.bytevector(32), - CryptoGenerators.adaptorSignature) { - case (privKey, adaptor, msg, badSig) => - val sig = privKey.adaptorSign(adaptor, msg) - val pubKey = privKey.publicKey + forAll( + CryptoGenerators.privateKey, + CryptoGenerators.publicKey, + NumberGenerator.bytevector(32), + CryptoGenerators.adaptorSignature + ) { case (privKey, adaptor, msg, badSig) => + val sig = privKey.adaptorSign(adaptor, msg) + val pubKey = privKey.publicKey - testCompatibility(_.adaptorVerify(sig, pubKey, msg, adaptor)) - testCompatibility(_.adaptorVerify(badSig, pubKey, msg, adaptor)) + testCompatibility(_.adaptorVerify(sig, pubKey, msg, adaptor)) + testCompatibility(_.adaptorVerify(badSig, pubKey, msg, adaptor)) } } diff --git a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/SignWithEntropyTest.scala b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/SignWithEntropyTest.scala index 4ddfb941d8..1a15326114 100644 --- a/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/SignWithEntropyTest.scala +++ b/crypto-test/.jvm/src/test/scala/org/bitcoins/crypto/SignWithEntropyTest.scala @@ -5,8 +5,8 @@ class SignWithEntropyTest extends BitcoinSCryptoTest { implicit override val generatorDrivenConfig: PropertyCheckConfiguration = generatorDrivenConfigNewCode - //ECPrivateKey implements the sign interface - //so just use it for testing purposes + // ECPrivateKey implements the sign interface + // so just use it for testing purposes val privKey: Sign = ECPrivateKey.freshPrivateKey val pubKey: ECPublicKey = privKey.publicKey diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/BIP340TestVectors.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/BIP340TestVectors.scala index 37f89932fc..96e7453bf7 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/BIP340TestVectors.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/BIP340TestVectors.scala @@ -11,7 +11,9 @@ object BIP340TestVectors { String, String, Boolean, - String)] = Vector( + String + ) + ] = Vector( "index,secret key,public key,aux_rand,message,signature,verification result,comment", "0,0000000000000000000000000000000000000000000000000000000000000003,F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9,0000000000000000000000000000000000000000000000000000000000000000,0000000000000000000000000000000000000000000000000000000000000000,E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0,TRUE,", "1,B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,0000000000000000000000000000000000000000000000000000000000000001,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A,TRUE,", diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/BitcoinSCryptoTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/BitcoinSCryptoTest.scala index 65af3ab8bb..f5c9406ba5 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/BitcoinSCryptoTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/BitcoinSCryptoTest.scala @@ -57,8 +57,9 @@ trait BitcoinSCryptoAsyncTest ) } - def forAllAsync[A](gen: Gen[A])( - func: A => Future[Assertion]): Future[Assertion] = { + def forAllAsync[A]( + gen: Gen[A] + )(func: A => Future[Assertion]): Future[Assertion] = { val samples = 1 .to(generatorDrivenConfig.minSize) @@ -72,7 +73,8 @@ trait BitcoinSCryptoAsyncTest } def forAllAsync[A, B](genA: Gen[A], genB: Gen[B])( - func: (A, B) => Future[Assertion]): Future[Assertion] = { + func: (A, B) => Future[Assertion] + ): Future[Assertion] = { val samples = 1 .to(generatorDrivenConfig.minSize) @@ -105,13 +107,11 @@ trait BitcoinSCryptoAsyncTest object BitcoinSCryptoTest { - /** The number of times new code - * should be executed in a property based test + /** The number of times new code should be executed in a property based test */ val NEW_CODE_EXECUTIONS = 100 - /** The number of times old code should be executed - * in a property based test + /** The number of times old code should be executed in a property based test */ val OLD_CODE_EXECUTIONS = 20 diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoGenerators.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoGenerators.scala index a91e90f6ab..4891b53544 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoGenerators.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoGenerators.scala @@ -9,11 +9,11 @@ import scodec.bits.ByteVector sealed abstract class CryptoGenerators { def privateKey: Gen[ECPrivateKey] = { - //purposefully don't reach for cryptographically strong - //number generation, we want determinism to reproduce failed - //test cases. If we don't generate the private key with scalacheck - //we won't be able to reproduce the test case with a seed - //see: https://github.com/bitcoin-s/bitcoin-s/issues/1339 + // purposefully don't reach for cryptographically strong + // number generation, we want determinism to reproduce failed + // test cases. If we don't generate the private key with scalacheck + // we won't be able to reproduce the test case with a seed + // see: https://github.com/bitcoin-s/bitcoin-s/issues/1339 NumberGenerator.bytevector(32).map { vec => ECPrivateKey.fromBytes(vec) } @@ -56,15 +56,17 @@ sealed abstract class CryptoGenerators { def xOnlyPubKey: Gen[XOnlyPubKey] = publicKey.map(_.toXOnly) /** Generate a sequence of private keys - * @param num maximum number of keys to generate + * @param num + * maximum number of keys to generate * @return */ def privateKeySeq(num: Int): Gen[Seq[ECPrivateKey]] = Gen.listOfN(num, privateKey) - /** Generates a sequence of private keys, and determines an amount of 'required' private keys - * that a transaction needs to be signed with - * @param num the maximum number of keys to generate + /** Generates a sequence of private keys, and determines an amount of + * 'required' private keys that a transaction needs to be signed with + * @param num + * the maximum number of keys to generate * @return */ def privateKeySeqWithRequiredSigs(num: Int): Gen[(Seq[ECPrivateKey], Int)] = { @@ -79,8 +81,8 @@ sealed abstract class CryptoGenerators { } } - /** Generates a random number of private keys less than 15. - * Also generates a random 'requiredSigs' number that a transaction needs to be signed with + /** Generates a random number of private keys less than 15. Also generates a + * random 'requiredSigs' number that a transaction needs to be signed with */ def privateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] = for { @@ -88,7 +90,9 @@ sealed abstract class CryptoGenerators { keysAndRequiredSigs <- privateKeySeqWithRequiredSigs(num) } yield keysAndRequiredSigs - /** A generator with 7 or less private keys -- useful for creating smaller scripts */ + /** A generator with 7 or less private keys -- useful for creating smaller + * scripts + */ def smallPrivateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] = for { num <- Gen.choose(0, 7) @@ -131,8 +135,8 @@ sealed abstract class CryptoGenerators { } } - def adaptorSignatureWithDecryptedSignatureAndAdaptor: Gen[ - (ECAdaptorSignature, ECDigitalSignature, ECPublicKey)] = { + def adaptorSignatureWithDecryptedSignatureAndAdaptor + : Gen[(ECAdaptorSignature, ECDigitalSignature, ECPublicKey)] = { for { privKey <- privateKey decKey <- privateKey @@ -169,7 +173,8 @@ sealed abstract class CryptoGenerators { } /** Generates a sequence of [[DoubleSha256Digest DoubleSha256Digest]] - * @param num the number of digets to generate + * @param num + * the number of digets to generate * @return */ def doubleSha256DigestSeq(num: Int): Gen[Seq[DoubleSha256Digest]] = diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoUtilTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoUtilTest.scala index c0fb1c6b0e..9c7c0322f0 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoUtilTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/CryptoUtilTest.scala @@ -22,7 +22,7 @@ class CryptoUtilTest extends BitcoinSCryptoTest { } it must "perform a RIPEMD160 on a SHA256 hash to generate a bitcoin address" in { - //https://bitcoin.stackexchange.com/questions/37040/ripemd160sha256publickey-where-am-i-going-wrong + // https://bitcoin.stackexchange.com/questions/37040/ripemd160sha256publickey-where-am-i-going-wrong val bytes = hex"ea571f53cb3a9865d3dc74735e0c16643d319c6ad81e199b9c8408cecbcec7bb" val expected = "5238c71458e464d9ff90299abca4a1d7b9cb76ab" @@ -94,13 +94,16 @@ class CryptoUtilTest extends BitcoinSCryptoTest { forAll(NumberGenerator.bytevector) { bytes => assert( CryptoUtil.sha256SchnorrChallenge(bytes) == CryptoUtil - .taggedSha256(bytes, "BIP0340/challenge")) + .taggedSha256(bytes, "BIP0340/challenge") + ) assert( CryptoUtil.sha256SchnorrNonce(bytes) == CryptoUtil - .taggedSha256(bytes, "BIP0340/nonce")) + .taggedSha256(bytes, "BIP0340/nonce") + ) assert( CryptoUtil.sha256SchnorrAuxRand(bytes) == CryptoUtil - .taggedSha256(bytes, "BIP0340/aux")) + .taggedSha256(bytes, "BIP0340/aux") + ) } } @@ -143,13 +146,15 @@ class CryptoUtilTest extends BitcoinSCryptoTest { val nonComposite = "fi" assert( CryptoUtil.serializeForHash(nonComposite) == ByteVector.fromValidHex( - "6669") + "6669" + ) ) val accentString = "éléphant" assert( CryptoUtil.serializeForHash(accentString) == ByteVector.fromValidHex( - "c3a96cc3a97068616e74") + "c3a96cc3a97068616e74" + ) ) } @@ -159,40 +164,55 @@ class CryptoUtilTest extends BitcoinSCryptoTest { assert( singletons .map(CryptoUtil.sha256) - .forall(_ == Sha256Digest( - "0a94dc9d420d1142d6b71de60f9bf7e2f345a4d62c9f141b091539769ddf3075")) + .forall( + _ == Sha256Digest( + "0a94dc9d420d1142d6b71de60f9bf7e2f345a4d62c9f141b091539769ddf3075" + ) + ) ) val canonicalComposites = Vector("\u00f4", "\u006f\u0302") assert( canonicalComposites .map(CryptoUtil.sha256) - .forall(_ == Sha256Digest( - "cc912dbca598fd80ca7f5d98ece5d846b447f4a9ae3f73c352e2687eb293eef5")) + .forall( + _ == Sha256Digest( + "cc912dbca598fd80ca7f5d98ece5d846b447f4a9ae3f73c352e2687eb293eef5" + ) + ) ) val multipleCombiningMarks = Vector("\u1e69", "\u0073\u0323\u0307") assert( multipleCombiningMarks .map(CryptoUtil.sha256) - .forall(_ == Sha256Digest( - "ceca1ea456e95ee498463622915209bb08a018e8ee9741b46b64ef1a08fb56ab")) + .forall( + _ == Sha256Digest( + "ceca1ea456e95ee498463622915209bb08a018e8ee9741b46b64ef1a08fb56ab" + ) + ) ) val compatibilityComposite = "\ufb01" assert( CryptoUtil.sha256(compatibilityComposite) == Sha256Digest( - "b6554cce8a93f1c8818280e2a768116a79216ad5501a85357d233409db87d340")) + "b6554cce8a93f1c8818280e2a768116a79216ad5501a85357d233409db87d340" + ) + ) val nonComposite = "fi" assert( CryptoUtil.sha256(nonComposite) == Sha256Digest( - "b4bdc848109722a383d0a972c6eb859f2abd29565b8c4cc7199e7c9eb708f1b7")) + "b4bdc848109722a383d0a972c6eb859f2abd29565b8c4cc7199e7c9eb708f1b7" + ) + ) val accentString = "éléphant" assert( CryptoUtil.sha256(accentString) == Sha256Digest( - "c941ae685f62cbe7bb47d0791af7154788fd9e873e5c57fd2449d1454ed5b16f")) + "c941ae685f62cbe7bb47d0791af7154788fd9e873e5c57fd2449d1454ed5b16f" + ) + ) } it must "encode strings correctly when hashing" in { @@ -228,7 +248,7 @@ class CryptoUtilTest extends BitcoinSCryptoTest { assert(!CryptoUtil.checkEntropy(sameBytes1.toBitVector)) assert(!CryptoUtil.checkEntropy(sameBytes2.toBitVector)) - //to short of entropy + // to short of entropy val toShort = ByteVector.fromValidHex("0123456789abcdef") assert(!CryptoUtil.checkEntropy(toShort.toBitVector)) } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/DERSignatureUtilTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/DERSignatureUtilTest.scala index 8b98bedf95..744ea68637 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/DERSignatureUtilTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/DERSignatureUtilTest.scala @@ -9,20 +9,23 @@ import scala.math.BigInt class DERSignatureUtilTest extends BitcoinSCryptoTest { val p2shSignature = ECDigitalSignature( - "304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001") + "304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001" + ) val p2pkhSignature = ECDigitalSignature( - "3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01") + "3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01" + ) val p2pkSignature = ECDigitalSignature( - "304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001") + "304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b742001" + ) "DERSignatureUtil" must "say that a signature taken from a p2sh transaction is a valid DER encoded signature" in { DERSignatureUtil.isValidSignatureEncoding(p2shSignature) must be(true) } it must "say that signature taken from a p2pkh transaction is a valid DER encoded signature" in { - //need to remove the hash type byte to check for der encoding + // need to remove the hash type byte to check for der encoding val hashTypeByteRemoved = p2pkhSignature.bytes.slice(0, p2pkhSignature.bytes.size - 1) DERSignatureUtil.isDEREncoded(hashTypeByteRemoved) must be(true) @@ -38,30 +41,42 @@ class DERSignatureUtilTest extends BitcoinSCryptoTest { val (r, s) = DERSignatureUtil.decodeSignature(p2shSignature) r must be( CryptoNumberUtil.toBigInt( - "5b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb")) + "5b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb" + ) + ) s must be( CryptoNumberUtil.toBigInt( - "2e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf80")) + "2e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf80" + ) + ) } it must "retrieve the (r,s) values for a p2pkh signature in bitcoin" in { val (r, s) = DERSignatureUtil.decodeSignature(p2pkhSignature) r must be( CryptoNumberUtil.toBigInt( - "16ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca03")) + "16ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca03" + ) + ) s must be( CryptoNumberUtil.toBigInt( - "119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac")) + "119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac" + ) + ) } it must "retrieve the (r,s) values from a p2pk signature in bitcoin" in { val (r, s) = DERSignatureUtil.decodeSignature(p2pkSignature) r must be( CryptoNumberUtil.toBigInt( - "0a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa1")) + "0a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa1" + ) + ) s must be( CryptoNumberUtil.toBigInt( - "1fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b7420")) + "1fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b7420" + ) + ) } it must "say that a signature taken from a p2sh transaction is a valid stirctly DER encoded signature" in { @@ -79,20 +94,24 @@ class DERSignatureUtilTest extends BitcoinSCryptoTest { it must "say that the empty signature is a valid strictly encoded DER signature" in { DERSignatureUtil.isValidSignatureEncoding(ECDigitalSignature("")) must be( - true) + true + ) DERSignatureUtil.isValidSignatureEncoding(EmptyDigitalSignature) must be( - true) + true + ) } it must "say that an overly long signature is NOT strict der encoded" in { val sig = ECDigitalSignature( - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ) DERSignatureUtil.isValidSignatureEncoding(sig) must be(false) } it must "determine if a signature is encoded with a low s value" in { val highS = ECDigitalSignature( - "304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001".toLowerCase) + "304502203e4516da7253cf068effec6b95c41221c0cf3a8e6ccb8cbf1725b562e9afde2c022100ab1e3da73d67e32045a20e0b999e049978ea8d6ee5480d485fcf2ce0d03b2ef001".toLowerCase + ) DERSignatureUtil.isLowS(highS) must be(false) } @@ -126,20 +145,34 @@ class DERSignatureUtilTest extends BitcoinSCryptoTest { it must "fail to parse garbage signatures" in { val signatures = Vector( - ("4402204c2dd8a9b6f8d425fcd8ee9a20ac73b619906a6367eac6cb93e70375225ec0160220356878eff111ff3663d7e6bf08947f94443845e0dcc54961664d922f7660b80c", - "no leading byte"), - ("204402202ea9d51c7173b1d96d331bd41b3d1b4e78e66148e64ed5992abd6ca66290321c0220628c47517e049b3e41509e9d71e480a0cdc766f8cdec265ef0017711c1b5336f", - "bad leading byte"), - ("30477022100bf8e050c85ffa1c313108ad8c482c4849027937916374617af3f2e9a881861c9022023f65814222cab09d5ec41032ce9c72ca96a5676020736614de7b78a4e55325a", - "long length byte"), - ("30462100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45", - "no r integer tag"), - ("3046022100eaa5f90483eb20224616775891397d47efa64c68b969db1dacb1c30acdfc50aa2100cf9903bbefb1c8000cf482b0aeeb5af19287af20bd794de11d82716f9bae3db1", - "no s integer tag"), - ("3045022847d512bc85842ac463ca3b669b62666ab8672ee60725b6c06759e476cebdc6c102210083805e93bd941770109bcc797784a71db9e48913f702c56e60b1c3e2ff379a60", - "long r length"), - ("3044022023ee4e95151b2fbbb08a72f35babe02830d14d54bd7ed1320e4751751d1baa4802286235245254f58fd1be6ff19ca291817da76da65c2f6d81d654b5185dd86b8acf", - "long s length") + ( + "4402204c2dd8a9b6f8d425fcd8ee9a20ac73b619906a6367eac6cb93e70375225ec0160220356878eff111ff3663d7e6bf08947f94443845e0dcc54961664d922f7660b80c", + "no leading byte" + ), + ( + "204402202ea9d51c7173b1d96d331bd41b3d1b4e78e66148e64ed5992abd6ca66290321c0220628c47517e049b3e41509e9d71e480a0cdc766f8cdec265ef0017711c1b5336f", + "bad leading byte" + ), + ( + "30477022100bf8e050c85ffa1c313108ad8c482c4849027937916374617af3f2e9a881861c9022023f65814222cab09d5ec41032ce9c72ca96a5676020736614de7b78a4e55325a", + "long length byte" + ), + ( + "30462100839c1fbc5304de944f697c9f4b1d01d1faeba32d751c0f7acb21ac8a0f436a72022100e89bd46bb3a5a62adc679f659b7ce876d83ee297c7a5587b2011c4fcc72eab45", + "no r integer tag" + ), + ( + "3046022100eaa5f90483eb20224616775891397d47efa64c68b969db1dacb1c30acdfc50aa2100cf9903bbefb1c8000cf482b0aeeb5af19287af20bd794de11d82716f9bae3db1", + "no s integer tag" + ), + ( + "3045022847d512bc85842ac463ca3b669b62666ab8672ee60725b6c06759e476cebdc6c102210083805e93bd941770109bcc797784a71db9e48913f702c56e60b1c3e2ff379a60", + "long r length" + ), + ( + "3044022023ee4e95151b2fbbb08a72f35babe02830d14d54bd7ed1320e4751751d1baa4802286235245254f58fd1be6ff19ca291817da76da65c2f6d81d654b5185dd86b8acf", + "long s length" + ) ).map { case (sig, msg) => (ByteVector.fromValidHex(sig), msg) } signatures.foreach { case (sig, msg) => diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/ECAdaptorSignatureTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/ECAdaptorSignatureTest.scala index 25137fd162..57fb6faee7 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/ECAdaptorSignatureTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/ECAdaptorSignatureTest.scala @@ -3,7 +3,8 @@ package org.bitcoins.crypto import org.scalatest.Assertion import scodec.bits.ByteVector -/** Executes tests at https://github.com/discreetlogcontracts/dlcspecs/blob/9b11bcc99341ad40d8ae146d5d3ead116d5bb131/test/ecdsa_adaptor.json +/** Executes tests at + * https://github.com/discreetlogcontracts/dlcspecs/blob/9b11bcc99341ad40d8ae146d5d3ead116d5bb131/test/ecdsa_adaptor.json * along with some static signing tests Jesse generated. */ class ECAdaptorSignatureTest extends BitcoinSCryptoTest { @@ -16,7 +17,8 @@ class ECAdaptorSignatureTest extends BitcoinSCryptoTest { pubKey: String, encKey: String, auxRand: String, - adaptorSig: String): Assertion = { + adaptorSig: String + ): Assertion = { testSign( ECPrivateKey(secKey), ByteVector.fromValidHex(msg), @@ -35,7 +37,8 @@ class ECAdaptorSignatureTest extends BitcoinSCryptoTest { pubKey: ECPublicKey, encKey: ECPublicKey, auxRand: ByteVector, - adaptorSig: ECAdaptorSignature): Assertion = { + adaptorSig: ECAdaptorSignature + ): Assertion = { assert(pubKey == secKey.publicKey) assert(secKey.adaptorSign(encKey, msg, auxRand) == adaptorSig) assert(pubKey.adaptorVerify(msg, encKey, adaptorSig)) @@ -128,17 +131,23 @@ class ECAdaptorSignatureTest extends BitcoinSCryptoTest { it must "pass happy path verification test" in { val adaptorSig = ECAdaptorSignature( - "03424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb6730223f325042fce535d040fee52ec13231bf709ccd84233c6944b90317e62528b2527dff9d659a96db4c99f9750168308633c1867b70f3a18fb0f4539a1aecedcd1fc0148fc22f36b6303083ece3f872b18e35d368b3958efe5fb081f7716736ccb598d269aa3084d57e1855e1ea9a45efc10463bbf32ae378029f5763ceb40173f") + "03424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb6730223f325042fce535d040fee52ec13231bf709ccd84233c6944b90317e62528b2527dff9d659a96db4c99f9750168308633c1867b70f3a18fb0f4539a1aecedcd1fc0148fc22f36b6303083ece3f872b18e35d368b3958efe5fb081f7716736ccb598d269aa3084d57e1855e1ea9a45efc10463bbf32ae378029f5763ceb40173f" + ) val msg = ByteVector.fromValidHex( - "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d") + "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d" + ) val pubKey = ECPublicKey( - "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c") + "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c" + ) val encKey = ECPublicKey( - "02c2662c97488b07b6e819124b8989849206334a4c2fbdf691f7b34d2b16e9c293") + "02c2662c97488b07b6e819124b8989849206334a4c2fbdf691f7b34d2b16e9c293" + ) val decKey = ECPrivateKey( - "0b2aba63b885a0f0e96fa0f303920c7fb7431ddfa94376ad94d969fbf4109dc8") + "0b2aba63b885a0f0e96fa0f303920c7fb7431ddfa94376ad94d969fbf4109dc8" + ) val signature = ECDigitalSignature.fromRS( - "424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb67329e80e0ee60e57af3e625bbae1672b1ecaa58effe613426b024fa1621d903394") + "424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb67329e80e0ee60e57af3e625bbae1672b1ecaa58effe613426b024fa1621d903394" + ) assert(pubKey.adaptorVerify(msg, encKey, adaptorSig)) assert(decKey.completeAdaptorSignature(adaptorSig) == signature) @@ -147,17 +156,23 @@ class ECAdaptorSignatureTest extends BitcoinSCryptoTest { it must "pass ECDSA malleable verification test" in { val adaptorSig = ECAdaptorSignature( - "036035c89860ec62ad153f69b5b3077bcd08fbb0d28dc7f7f6df4a05cca35455be037043b63c56f6317d9928e8f91007335748c49824220db14ad10d80a5d00a9654af0996c1824c64c90b951bb2734aaecf78d4b36131a47238c3fa2ba25e2ced54255b06df696de1483c3767242a3728826e05f79e3981e12553355bba8a0131cd370e63e3da73106f638576a5aab0ea6d45c042574c0c8d0b14b8c7c01cfe9072") + "036035c89860ec62ad153f69b5b3077bcd08fbb0d28dc7f7f6df4a05cca35455be037043b63c56f6317d9928e8f91007335748c49824220db14ad10d80a5d00a9654af0996c1824c64c90b951bb2734aaecf78d4b36131a47238c3fa2ba25e2ced54255b06df696de1483c3767242a3728826e05f79e3981e12553355bba8a0131cd370e63e3da73106f638576a5aab0ea6d45c042574c0c8d0b14b8c7c01cfe9072" + ) val msg = ByteVector.fromValidHex( - "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d") + "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d" + ) val pubKey = ECPublicKey( - "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c") + "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c" + ) val encKey = ECPublicKey( - "024eee18be9a5a5224000f916c80b393447989e7194bc0b0f1ad7a03369702bb51") + "024eee18be9a5a5224000f916c80b393447989e7194bc0b0f1ad7a03369702bb51" + ) val decKey = ECPrivateKey( - "db2debddb002473a001dd70b06f6c97bdcd1c46ba1001237fe0ee1aeffb2b6c4") + "db2debddb002473a001dd70b06f6c97bdcd1c46ba1001237fe0ee1aeffb2b6c4" + ) val signature = ECDigitalSignature.fromRS( - "6035c89860ec62ad153f69b5b3077bcd08fbb0d28dc7f7f6df4a05cca35455be4ceacf921546c03dd1be596723ad1e7691bdac73d88cc36c421c5e7f08384305") + "6035c89860ec62ad153f69b5b3077bcd08fbb0d28dc7f7f6df4a05cca35455be4ceacf921546c03dd1be596723ad1e7691bdac73d88cc36c421c5e7f08384305" + ) assert(pubKey.adaptorVerify(msg, encKey, adaptorSig)) assert(decKey.completeAdaptorSignature(adaptorSig) == signature) @@ -166,50 +181,65 @@ class ECAdaptorSignatureTest extends BitcoinSCryptoTest { it must "fail to validate a false proof" in { val adaptorSig = ECAdaptorSignature( - "03f94dca206d7582c015fb9bffe4e43b14591b30ef7d2b464d103ec5e116595dba03127f8ac3533d249280332474339000922eb6a58e3b9bf4fc7e01e4b4df2b7a4100a1e089f16e5d70bb89f961516f1de0684cc79db978495df2f399b0d01ed7240fa6e3252aedb58bdc6b5877b0c602628a235dd1ccaebdddcbe96198c0c21bead7b05f423b673d14d206fa1507b2dbe2722af792b8c266fc25a2d901d7e2c335") + "03f94dca206d7582c015fb9bffe4e43b14591b30ef7d2b464d103ec5e116595dba03127f8ac3533d249280332474339000922eb6a58e3b9bf4fc7e01e4b4df2b7a4100a1e089f16e5d70bb89f961516f1de0684cc79db978495df2f399b0d01ed7240fa6e3252aedb58bdc6b5877b0c602628a235dd1ccaebdddcbe96198c0c21bead7b05f423b673d14d206fa1507b2dbe2722af792b8c266fc25a2d901d7e2c335" + ) val msg = ByteVector.fromValidHex( - "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d") + "8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d" + ) val pubKey = ECPublicKey( - "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c") + "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c" + ) val encKey = ECPublicKey( - "0214ccb756249ad6e733c80285ea7ac2ee12ffebbcee4e556e6810793a60c45ad4") + "0214ccb756249ad6e733c80285ea7ac2ee12ffebbcee4e556e6810793a60c45ad4" + ) assert(!pubKey.adaptorVerify(msg, encKey, adaptorSig)) } it must "pass happy path recovery test" in { val adaptorSig = ECAdaptorSignature( - "03f2db6e9ed33092cc0b898fd6b282e99bdaeccb3de85c2d2512d8d507f9abab290210c01b5bed7094a12664aeaab3402d8709a8f362b140328d1b36dd7cb420d02fb66b1230d61c16d0cd0a2a02246d5ac7848dcd6f04fe627053cd3c7015a7d4aa6ac2b04347348bd67da43be8722515d99a7985fbfa66f0365c701de76ff0400dffdc9fa84dddf413a729823b16af60aa6361bc32e7cfd6701e32957c72ace67b") + "03f2db6e9ed33092cc0b898fd6b282e99bdaeccb3de85c2d2512d8d507f9abab290210c01b5bed7094a12664aeaab3402d8709a8f362b140328d1b36dd7cb420d02fb66b1230d61c16d0cd0a2a02246d5ac7848dcd6f04fe627053cd3c7015a7d4aa6ac2b04347348bd67da43be8722515d99a7985fbfa66f0365c701de76ff0400dffdc9fa84dddf413a729823b16af60aa6361bc32e7cfd6701e32957c72ace67b" + ) val encKey = ECPublicKey( - "027ee4f899bc9c5f2b626fa1a9b37ce291c0388b5227e90b0fd8f4fa576164ede7") + "027ee4f899bc9c5f2b626fa1a9b37ce291c0388b5227e90b0fd8f4fa576164ede7" + ) val decKey = ECPrivateKey( - "9cf3ea9be594366b78c457162908af3c2ea177058177e9c6bf99047927773a06") + "9cf3ea9be594366b78c457162908af3c2ea177058177e9c6bf99047927773a06" + ) val signature = ECDigitalSignature.fromRS( - "f2db6e9ed33092cc0b898fd6b282e99bdaeccb3de85c2d2512d8d507f9abab2921811fe7b53becf3b7affa9442abaa93c0ab8a8e45cd7ee2ea8d258bfc25d464") + "f2db6e9ed33092cc0b898fd6b282e99bdaeccb3de85c2d2512d8d507f9abab2921811fe7b53becf3b7affa9442abaa93c0ab8a8e45cd7ee2ea8d258bfc25d464" + ) assert(encKey.extractAdaptorSecret(adaptorSig, signature) == decKey) } it must "fail to extract a secret on unrelated signatures" in { val adaptorSig = ECAdaptorSignature( - "03aa86d78059a91059c29ec1a757c4dc029ff636a1e6c1142fefe1e9d7339617c003a8153e50c0c8574a38d389e61bbb0b5815169e060924e4b5f2e78ff13aa7ad858e0c27c4b9eed9d60521b3f54ff83ca4774be5fb3a680f820a35e8840f4aaf2de88e7c5cff38a37b78725904ef97bb82341328d55987019bd38ae1745e3efe0f8ea8bdfede0d378fc1f96e944a7505249f41e93781509ee0bade77290d39cd12") + "03aa86d78059a91059c29ec1a757c4dc029ff636a1e6c1142fefe1e9d7339617c003a8153e50c0c8574a38d389e61bbb0b5815169e060924e4b5f2e78ff13aa7ad858e0c27c4b9eed9d60521b3f54ff83ca4774be5fb3a680f820a35e8840f4aaf2de88e7c5cff38a37b78725904ef97bb82341328d55987019bd38ae1745e3efe0f8ea8bdfede0d378fc1f96e944a7505249f41e93781509ee0bade77290d39cd12" + ) val encKey = ECPublicKey( - "035176d24129741b0fcaa5fd6750727ce30860447e0a92c9ebebdeb7c3f93995ed") + "035176d24129741b0fcaa5fd6750727ce30860447e0a92c9ebebdeb7c3f93995ed" + ) val signature = ECDigitalSignature.fromRS( - "f7f7fe6bd056fc4abd70d335f72d0aa1e8406bba68f3e579e4789475323564a452c46176c7fb40aa37d5651341f55697dab27d84a213b30c93011a7790bace8c") + "f7f7fe6bd056fc4abd70d335f72d0aa1e8406bba68f3e579e4789475323564a452c46176c7fb40aa37d5651341f55697dab27d84a213b30c93011a7790bace8c" + ) assertThrows[Exception](encKey.extractAdaptorSecret(adaptorSig, signature)) } it must "pass recovery test for high s value" in { val adaptorSig = ECAdaptorSignature( - "032c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b1403eb615a3e59b1cbbf4f87acaf645be1eda32a066611f35dd5557802802b14b19c81c04c3fefac5783b2077bd43fa0a39ab8a64d4d78332a5d621ea23eca46bc011011ab82dda6deb85699f508744d70d4134bea03f784d285b5c6c15a56e4e1fab4bc356abbdebb3b8fe1e55e6dd6d2a9ea457e91b2e6642fae69f9dbb5258854") + "032c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b1403eb615a3e59b1cbbf4f87acaf645be1eda32a066611f35dd5557802802b14b19c81c04c3fefac5783b2077bd43fa0a39ab8a64d4d78332a5d621ea23eca46bc011011ab82dda6deb85699f508744d70d4134bea03f784d285b5c6c15a56e4e1fab4bc356abbdebb3b8fe1e55e6dd6d2a9ea457e91b2e6642fae69f9dbb5258854" + ) val encKey = ECPublicKey( - "02042537e913ad74c4bbd8da9607ad3b9cb297d08e014afc51133083f1bd687a62") + "02042537e913ad74c4bbd8da9607ad3b9cb297d08e014afc51133083f1bd687a62" + ) val decKey = ECPrivateKey( - "324719b51ff2474c9438eb76494b0dc0bcceeb529f0a5428fd198ad8f886e99c") + "324719b51ff2474c9438eb76494b0dc0bcceeb529f0a5428fd198ad8f886e99c" + ) val signature = ECDigitalSignature.fromRS( - "2c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b14b5f24321f550b7b9dd06ee4fcfd82bdad8b142ff93a790cc4d9f7962b38c6a3b") + "2c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b14b5f24321f550b7b9dd06ee4fcfd82bdad8b142ff93a790cc4d9f7962b38c6a3b" + ) assert(encKey.extractAdaptorSecret(adaptorSig, signature) == decKey) } @@ -217,17 +247,26 @@ class ECAdaptorSignatureTest extends BitcoinSCryptoTest { it must "pass serialization tests" in { val goodSigsT = scala.util.Try { ECAdaptorSignature( - "03e6d51da7bc2bf24cf9dfd9acc6c4f0a3e74d8a6273ee5a573ed6818e3095b60903f33bc98f9d2ea3511f2e24f3358557c815abd7713c9318af9f4dfab4441898ecd619acb1cb75c1a5946fbaf716d227199a6479a678d10a6d95512d674fb7703d85b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918") + "03e6d51da7bc2bf24cf9dfd9acc6c4f0a3e74d8a6273ee5a573ed6818e3095b60903f33bc98f9d2ea3511f2e24f3358557c815abd7713c9318af9f4dfab4441898ecd619acb1cb75c1a5946fbaf716d227199a6479a678d10a6d95512d674fb7703d85b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918" + ) ECAdaptorSignature( - "03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c03f33bc98f9d2ea3511f2e24f3358557c815abd7713c9318af9f4dfab4441898ecd619acb1cb75c1a5946fbaf716d227199a6479a678d10a6d95512d674fb7703d85b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918") + "03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c03f33bc98f9d2ea3511f2e24f3358557c815abd7713c9318af9f4dfab4441898ecd619acb1cb75c1a5946fbaf716d227199a6479a678d10a6d95512d674fb7703d85b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918" + ) ECAdaptorSignature( - "03e6d51da7bc2bf24cf9dfd9acc6c4f0a3e74d8a6273ee5a573ed6818e3095b60903fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2cd619acb1cb75c1a5946fbaf716d227199a6479a678d10a6d95512d674fb7703d85b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918") + "03e6d51da7bc2bf24cf9dfd9acc6c4f0a3e74d8a6273ee5a573ed6818e3095b60903fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2cd619acb1cb75c1a5946fbaf716d227199a6479a678d10a6d95512d674fb7703d85b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918" + ) } assert(goodSigsT.isSuccess) - assertThrows[IllegalArgumentException](ECAdaptorSignature( - "03e6d51da7bc2bf24cf9dfd9acc6c4f0a3e74d8a6273ee5a573ed6818e3095b60903f33bc98f9d2ea3511f2e24f3358557c815abd7713c9318af9f4dfab4441898ec000000000000000000000000000000000000000000000000000000000000000085b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918")) - assertThrows[IllegalArgumentException](ECAdaptorSignature( - "03e6d51da7bc2bf24cf9dfd9acc6c4f0a3e74d8a6273ee5a573ed6818e3095b60903f33bc98f9d2ea3511f2e24f3358557c815abd7713c9318af9f4dfab4441898ecfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414185b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918")) + assertThrows[IllegalArgumentException]( + ECAdaptorSignature( + "03e6d51da7bc2bf24cf9dfd9acc6c4f0a3e74d8a6273ee5a573ed6818e3095b60903f33bc98f9d2ea3511f2e24f3358557c815abd7713c9318af9f4dfab4441898ec000000000000000000000000000000000000000000000000000000000000000085b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918" + ) + ) + assertThrows[IllegalArgumentException]( + ECAdaptorSignature( + "03e6d51da7bc2bf24cf9dfd9acc6c4f0a3e74d8a6273ee5a573ed6818e3095b60903f33bc98f9d2ea3511f2e24f3358557c815abd7713c9318af9f4dfab4441898ecfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414185b58980b8e6c54bd20616bdb9461dccd8eebb7d7e7c83a91452cc20edf53be5b0fe0db44dddaaafbe737678c684b6e89b9b4b679b1855aa6ed644498b89c918" + ) + ) } } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/ECDigitalSignatureTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/ECDigitalSignatureTest.scala index 1ac9c9ba14..d4819e1e91 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/ECDigitalSignatureTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/ECDigitalSignatureTest.scala @@ -17,19 +17,22 @@ class ECDigitalSignatureTest extends BitcoinSCryptoTest { it must "say that a signature taken from a p2sh transaction is a valid DER encoded signature" in { val signature = ECDigitalSignature( - "304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf80") + "304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf80" + ) signature.isDEREncoded must be(true) } it must "say that signature taken from a p2pkh transaction is a valid DER encoded signature" in { val signature = ECDigitalSignature( - "3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac") + "3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac" + ) signature.isDEREncoded must be(true) } it must "say that a signature taken from a p2pk transaction is a valid DER encoded signature" in { val signature = ECDigitalSignature( - "304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b7420") + "304402200a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa102201fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b7420" + ) signature.isDEREncoded must be(true) } @@ -67,9 +70,11 @@ class ECDigitalSignatureTest extends BitcoinSCryptoTest { } it must "must not reuse r values" in { - forAll(CryptoGenerators.privateKey, - CryptoGenerators.doubleSha256Digest, - CryptoGenerators.doubleSha256Digest) { case (key, hash1, hash2) => + forAll( + CryptoGenerators.privateKey, + CryptoGenerators.doubleSha256Digest, + CryptoGenerators.doubleSha256Digest + ) { case (key, hash1, hash2) => val sig1 = key.sign(hash1) val sig2 = key.sign(hash2) assert(sig1.r != sig2.r) @@ -115,12 +120,15 @@ class ECDigitalSignatureTest extends BitcoinSCryptoTest { } it must "not append a HashType if one is already there" in { - forAll(CryptoGenerators.digitalSignature, - CryptoGenerators.hashType, - CryptoGenerators.hashType) { case (sig, hashType, hashType2) => + forAll( + CryptoGenerators.digitalSignature, + CryptoGenerators.hashType, + CryptoGenerators.hashType + ) { case (sig, hashType, hashType2) => val sigWithHashType = sig.appendHashType(hashType) assertThrows[IllegalArgumentException]( - sigWithHashType.appendHashType(hashType2)) + sigWithHashType.appendHashType(hashType2) + ) } } } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/ECPrivateKeyTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/ECPrivateKeyTest.scala index 0d7ad97434..c129f520fa 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/ECPrivateKeyTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/ECPrivateKeyTest.scala @@ -38,24 +38,27 @@ class ECPrivateKeyTest extends BitcoinSCryptoTest { assert(pubKey.bytes.tail == negPubKey.bytes.tail) assert(pubKey.bytes.head != negPubKey.bytes.head) assert( - privKey.fieldElement.add(negPrivKey.fieldElement) == FieldElement.zero) + privKey.fieldElement.add(negPrivKey.fieldElement) == FieldElement.zero + ) } } it must "correctly execute the ecdsa single signer adaptor signature protocol" in { - forAll(CryptoGenerators.privateKey, - CryptoGenerators.privateKey, - NumberGenerator.bytevector(32)) { - case (privKey, adaptorSecret, msg) => - val adaptorSig = privKey.adaptorSign(adaptorSecret.publicKey, msg) - assert( - privKey.publicKey - .adaptorVerify(msg, adaptorSecret.publicKey, adaptorSig)) - val sig = adaptorSecret.completeAdaptorSignature(adaptorSig) - val secret = - adaptorSecret.publicKey.extractAdaptorSecret(adaptorSig, sig) - assert(secret == adaptorSecret) - assert(privKey.publicKey.verify(msg, sig)) + forAll( + CryptoGenerators.privateKey, + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32) + ) { case (privKey, adaptorSecret, msg) => + val adaptorSig = privKey.adaptorSign(adaptorSecret.publicKey, msg) + assert( + privKey.publicKey + .adaptorVerify(msg, adaptorSecret.publicKey, adaptorSig) + ) + val sig = adaptorSecret.completeAdaptorSignature(adaptorSig) + val secret = + adaptorSecret.publicKey.extractAdaptorSecret(adaptorSig, sig) + assert(secret == adaptorSecret) + assert(privKey.publicKey.verify(msg, sig)) } } } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/ECPublicKeyTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/ECPublicKeyTest.scala index 5e8d0902fa..066d5ad662 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/ECPublicKeyTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/ECPublicKeyTest.scala @@ -7,10 +7,12 @@ class ECPublicKeyTest extends BitcoinSCryptoTest { it must "be able to decompress keys" in { val uncompressed = ECPublicKey( - hex"044f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa385b6b1b8ead809ca67454d9683fcf2ba03456d6fe2c4abe2b07f0fbdbb2f1c1") + hex"044f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa385b6b1b8ead809ca67454d9683fcf2ba03456d6fe2c4abe2b07f0fbdbb2f1c1" + ) val compressed = ECPublicKey( - hex"034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa") + hex"034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa" + ) assert(uncompressed.isFullyValid) assert(compressed.isFullyValid) @@ -50,10 +52,14 @@ class ECPublicKeyTest extends BitcoinSCryptoTest { assertThrows[RuntimeException](ECPublicKey(badHex)) assertThrows[RuntimeException]( ECPublicKey( - "02FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30")) + "02FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30" + ) + ) assertThrows[RuntimeException]( ECPublicKey( - "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30")) + "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30" + ) + ) } it must "be able to compress/decompress public keys" in { @@ -92,9 +98,11 @@ class ECPublicKeyTest extends BitcoinSCryptoTest { assertThrows[Exception](CryptoUtil.add(pubkey1, pubkey2)) assertThrows[Exception]( - CryptoUtil.add(pubkey1.compressed, pubkey2.compressed)) + CryptoUtil.add(pubkey1.compressed, pubkey2.compressed) + ) assertThrows[Exception]( - CryptoUtil.add(pubkey1.decompressed, pubkey2.decompressed)) + CryptoUtil.add(pubkey1.decompressed, pubkey2.decompressed) + ) } it must "be able to add multiple public keys together with sub-sums of 0x00" in { @@ -114,13 +122,17 @@ class ECPublicKeyTest extends BitcoinSCryptoTest { ECPublicKey.fromBytes(ByteVector(firstByte2) ++ pubkey3.bytes.tail) assert( - CryptoUtil.combinePubKeys(Vector(pubkey1, pubkey2, pubkey3)) == pubkey3) + CryptoUtil.combinePubKeys(Vector(pubkey1, pubkey2, pubkey3)) == pubkey3 + ) assert( - CryptoUtil.combinePubKeys(Vector(pubkey3, pubkey1, pubkey2)) == pubkey3) + CryptoUtil.combinePubKeys(Vector(pubkey3, pubkey1, pubkey2)) == pubkey3 + ) assertThrows[Exception]( - CryptoUtil.combinePubKeys(Vector(pubkey1, pubkey2, pubkey3, pubkey4))) + CryptoUtil.combinePubKeys(Vector(pubkey1, pubkey2, pubkey3, pubkey4)) + ) assertThrows[Exception]( - CryptoUtil.combinePubKeys(Vector(pubkey1, pubkey3, pubkey2, pubkey4))) + CryptoUtil.combinePubKeys(Vector(pubkey1, pubkey3, pubkey2, pubkey4)) + ) } it must "correctly compress keys" in { @@ -144,16 +156,19 @@ class ECPublicKeyTest extends BitcoinSCryptoTest { pubKeyCompressed.bytes.tail == pubKeyDecompressed.decompressedBytes .splitAt(33) ._1 - .tail) + .tail + ) } } it must "succeed with valid coordinates above the curve order" in { val _ = { ECPublicKey( - "02fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c").toPoint + "02fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c" + ).toPoint ECPublicKey( - "03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c").toPoint + "03fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c" + ).toPoint } succeed } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/FieldElementTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/FieldElementTest.scala index 1bb38d364a..f268455e84 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/FieldElementTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/FieldElementTest.scala @@ -37,8 +37,10 @@ class FieldElementTest extends BitcoinSCryptoTest { } it must "add small numbers correctly" in { - forAll(CryptoGenerators.smallFieldElement, - CryptoGenerators.smallFieldElement) { case (fe1, fe2) => + forAll( + CryptoGenerators.smallFieldElement, + CryptoGenerators.smallFieldElement + ) { case (fe1, fe2) => val feSum = fe1.add(fe2).toBigInteger val bigIntSum = fe1.toBigInteger.add(fe2.toBigInteger) @@ -47,8 +49,10 @@ class FieldElementTest extends BitcoinSCryptoTest { } it must "add large numbers correctly" in { - forAll(CryptoGenerators.largeFieldElement, - CryptoGenerators.largeFieldElement) { case (fe1, fe2) => + forAll( + CryptoGenerators.largeFieldElement, + CryptoGenerators.largeFieldElement + ) { case (fe1, fe2) => val feSum = fe1.add(fe2).toBigInteger val bigIntSum = fe1.toBigInteger.add(fe2.toBigInteger).subtract(N) @@ -75,15 +79,18 @@ class FieldElementTest extends BitcoinSCryptoTest { it must "wrap around correctly" in { assert( - FieldElement.orderMinusOne.add(FieldElement.one) == FieldElement.zero) + FieldElement.orderMinusOne.add(FieldElement.one) == FieldElement.zero + ) assert( - FieldElement.zero.subtract( - FieldElement.one) == FieldElement.orderMinusOne) + FieldElement.zero.subtract(FieldElement.one) == FieldElement.orderMinusOne + ) } it must "multiply small numbers correctly" in { - forAll(CryptoGenerators.reallySmallFieldElement, - CryptoGenerators.reallySmallFieldElement) { case (fe1, fe2) => + forAll( + CryptoGenerators.reallySmallFieldElement, + CryptoGenerators.reallySmallFieldElement + ) { case (fe1, fe2) => val feProduct = fe1.multiply(fe2).toBigInteger val bigIntProduct = fe1.toBigInteger.multiply(fe2.toBigInteger) diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/HashTypeTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/HashTypeTest.scala index b70019079f..21cee14fd1 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/HashTypeTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/HashTypeTest.scala @@ -33,7 +33,7 @@ class HashTypeTest extends BitcoinSCryptoTest { } it must "find hashType for number 1190874345" in { - //1190874345 & 0x80 = 0x80 + // 1190874345 & 0x80 = 0x80 val num = 1190874345 HashType(num).isInstanceOf[SIGHASH_ANYONECANPAY] must be(true) HashType(ByteVector.fromInt(num)) @@ -67,18 +67,22 @@ class HashTypeTest extends BitcoinSCryptoTest { } it must "find each specific hashType from byte sequence of default value" in { - //tests each hashtypes overriding fromBytes function + // tests each hashtypes overriding fromBytes function HashType(HashType.sigHashAll.num) must be(HashType.sigHashAll) HashType(HashType.sigHashNone.num) must be(HashType.sigHashNone) HashType(HashType.sigHashSingle.num) must be(HashType.sigHashSingle) HashType(HashType.sigHashAnyoneCanPay.num) must be( - HashType.sigHashAnyoneCanPay) + HashType.sigHashAnyoneCanPay + ) HashType(HashType.sigHashAllAnyoneCanPay.num) must be( - HashType.sigHashAllAnyoneCanPay) + HashType.sigHashAllAnyoneCanPay + ) HashType(HashType.sigHashNoneAnyoneCanPay.num) must be( - HashType.sigHashNoneAnyoneCanPay) + HashType.sigHashNoneAnyoneCanPay + ) HashType(HashType.sigHashSingleAnyoneCanPay.num) must be( - HashType.sigHashSingleAnyoneCanPay) + HashType.sigHashSingleAnyoneCanPay + ) } it must "find a hashtype with only an integer" in { @@ -91,11 +95,11 @@ class HashTypeTest extends BitcoinSCryptoTest { hashType.num == i32.toInt() && i32.last == hashType.byte && - //this check cannot check the other 3 bytes in - //hash type as they are discarded from inclusion - //on a bitcoin digital signature. Not sure why satoshi - //would have just used a uint8_t to represent a hash type - //instead of a uint32_t. + // this check cannot check the other 3 bytes in + // hash type as they are discarded from inclusion + // on a bitcoin digital signature. Not sure why satoshi + // would have just used a uint8_t to represent a hash type + // instead of a uint32_t. HashType.fromByte(hashType.byte).byte == hashType.byte } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrDigitalSignatureTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrDigitalSignatureTest.scala index d833b4de08..edaf660ec3 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrDigitalSignatureTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrDigitalSignatureTest.scala @@ -22,9 +22,11 @@ class SchnorrDigitalSignatureTest extends BitcoinSCryptoTest { } it must "must not reuse R values" in { - forAll(CryptoGenerators.privateKey, - NumberGenerator.bytevector(32), - NumberGenerator.bytevector(32)) { case (privKey, bytes1, bytes2) => + forAll( + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32), + NumberGenerator.bytevector(32) + ) { case (privKey, bytes1, bytes2) => val sig1 = privKey.schnorrSign(bytes1) val sig2 = privKey.schnorrSign(bytes2) assert(sig1.bytes != sig2.bytes) @@ -33,9 +35,11 @@ class SchnorrDigitalSignatureTest extends BitcoinSCryptoTest { } it must "generate R values correctly" in { - forAll(CryptoGenerators.privateKey, - NumberGenerator.bytevector(32), - NumberGenerator.bytevector(32)) { case (privKey, auxRand, bytes) => + forAll( + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32), + NumberGenerator.bytevector(32) + ) { case (privKey, auxRand, bytes) => val nonce = SchnorrNonce.kFromBipSchnorr(privKey, bytes, auxRand) val sig1 = privKey.schnorrSign(bytes, auxRand) @@ -57,9 +61,11 @@ class SchnorrDigitalSignatureTest extends BitcoinSCryptoTest { } it must "correctly compute signature points for sigs with fixed nonces" in { - forAll(CryptoGenerators.privateKey, - NumberGenerator.bytevector(32), - CryptoGenerators.privateKey) { case (privKey, data, nonce) => + forAll( + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32), + CryptoGenerators.privateKey + ) { case (privKey, data, nonce) => val pubKey = privKey.publicKey val sig = privKey.schnorrSignWithNonce(data, nonce) assert(sig.rx == nonce.schnorrNonce) @@ -69,59 +75,59 @@ class SchnorrDigitalSignatureTest extends BitcoinSCryptoTest { } } - /** Schnorr signatures have the property that if two messages are signed with the same key - * and nonce, then they are leaked: + /** Schnorr signatures have the property that if two messages are signed with + * the same key and nonce, then they are leaked: * - * sig1 = nonce + message1*privKey - * sig2 = nonce + message2*privKey + * sig1 = nonce + message1*privKey sig2 = nonce + message2*privKey * - * => sig1 - sig2 = (message1 - message2)*privKey - * => privKey = (sig1 - sig2) * inverse(message1 - message2) + * \=> sig1 - sig2 = (message1 - message2)*privKey \=> privKey = (sig1 - + * sig2) * inverse(message1 - message2) */ it must "leak keys if two messages are signed" in { - forAll(CryptoGenerators.nonZeroPrivKey, - CryptoGenerators.nonZeroPrivKey, - NumberGenerator.bytevector(32), - NumberGenerator.bytevector(32)) { - case (privKey, nonce, message1, message2) => - // This will only work if we sign two different messages - assert(message1 != message2) + forAll( + CryptoGenerators.nonZeroPrivKey, + CryptoGenerators.nonZeroPrivKey, + NumberGenerator.bytevector(32), + NumberGenerator.bytevector(32) + ) { case (privKey, nonce, message1, message2) => + // This will only work if we sign two different messages + assert(message1 != message2) - // Sign both messages using the same privKey and nonce - val sig1 = privKey.schnorrSignWithNonce(message1, nonce) - val sig2 = privKey.schnorrSignWithNonce(message2, nonce) + // Sign both messages using the same privKey and nonce + val sig1 = privKey.schnorrSignWithNonce(message1, nonce) + val sig2 = privKey.schnorrSignWithNonce(message2, nonce) - // s1 = nonce + e1*privKey - val s1 = sig1.sig - // s2 = nonce + e2*privKey - val s2 = sig2.sig + // s1 = nonce + e1*privKey + val s1 = sig1.sig + // s2 = nonce + e2*privKey + val s2 = sig2.sig - // When signing a message you actually sign SHA256_challenge(Rx || pubKey || message) - val bytesToHash1 = - sig1.rx.bytes ++ privKey.schnorrPublicKey.bytes ++ message1 - val e1Bytes = CryptoUtil.sha256SchnorrChallenge(bytesToHash1).bytes + // When signing a message you actually sign SHA256_challenge(Rx || pubKey || message) + val bytesToHash1 = + sig1.rx.bytes ++ privKey.schnorrPublicKey.bytes ++ message1 + val e1Bytes = CryptoUtil.sha256SchnorrChallenge(bytesToHash1).bytes - val bytesToHash2 = - sig2.rx.bytes ++ privKey.schnorrPublicKey.bytes ++ message2 - val e2Bytes = CryptoUtil.sha256SchnorrChallenge(bytesToHash2).bytes + val bytesToHash2 = + sig2.rx.bytes ++ privKey.schnorrPublicKey.bytes ++ message2 + val e2Bytes = CryptoUtil.sha256SchnorrChallenge(bytesToHash2).bytes - val e1 = CryptoNumberUtil.uintToFieldElement(e1Bytes) - val e2 = CryptoNumberUtil.uintToFieldElement(e2Bytes) + val e1 = CryptoNumberUtil.uintToFieldElement(e1Bytes) + val e2 = CryptoNumberUtil.uintToFieldElement(e2Bytes) - val k = nonce.nonceKey.fieldElement - val x = privKey.schnorrKey.fieldElement + val k = nonce.nonceKey.fieldElement + val x = privKey.schnorrKey.fieldElement - // Test that we have correctly computed the components - assert(k.add(e1.multiply(x)) == s1) - assert(k.add(e2.multiply(x)) == s2) + // Test that we have correctly computed the components + assert(k.add(e1.multiply(x)) == s1) + assert(k.add(e2.multiply(x)) == s2) - // Note that all of s1, s2, e1, and e2 are public information: - // s1 - s2 = nonce + e1*privKey - (nonce + e2*privKey) = privKey*(e1-e2) - // => privKey = (s1 - s2) * modInverse(e1 - e2) - val privNum = s1.subtract(s2).multInv(e1.subtract(e2)) + // Note that all of s1, s2, e1, and e2 are public information: + // s1 - s2 = nonce + e1*privKey - (nonce + e2*privKey) = privKey*(e1-e2) + // => privKey = (s1 - s2) * modInverse(e1 - e2) + val privNum = s1.subtract(s2).multInv(e1.subtract(e2)) - // Assert that we've correctly recovered the private key form public info - assert(privNum == x) + // Assert that we've correctly recovered the private key form public info + assert(privNum == x) } } } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrNonceTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrNonceTest.scala index a884fa13db..daec35f65b 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrNonceTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrNonceTest.scala @@ -10,26 +10,35 @@ class SchnorrNonceTest extends BitcoinSCryptoTest { it must "fail for incorrect lengths" in { assertThrows[IllegalArgumentException]( SchnorrNonce( - "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a")) + "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a" + ) + ) assertThrows[IllegalArgumentException]( SchnorrNonce( - "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a010203")) + "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a010203" + ) + ) } it must "fail for invalid x coordinate" in { assertThrows[IllegalArgumentException]( SchnorrNonce( - "EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34")) + "EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34" + ) + ) assertThrows[IllegalArgumentException]( SchnorrNonce( - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30")) + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30" + ) + ) } it must "succeed for valid large x coordinates above the curve order" in { val _ = SchnorrNonce( - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c").xCoord + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c" + ).xCoord succeed } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrPublicKeyTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrPublicKeyTest.scala index 5d5024f6b9..1dfc933b1a 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrPublicKeyTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/SchnorrPublicKeyTest.scala @@ -10,26 +10,35 @@ class SchnorrPublicKeyTest extends BitcoinSCryptoTest { it must "fail for incorrect lengths" in { assertThrows[IllegalArgumentException]( SchnorrPublicKey( - "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a")) + "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a" + ) + ) assertThrows[IllegalArgumentException]( SchnorrPublicKey( - "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a010203")) + "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a010203" + ) + ) } it must "fail for invalid x coordinate" in { assertThrows[IllegalArgumentException]( SchnorrPublicKey( - "EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34")) + "EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34" + ) + ) assertThrows[IllegalArgumentException]( SchnorrPublicKey( - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30")) + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30" + ) + ) } it must "succeed for valid large x coordinates above the curve order" in { val _ = SchnorrPublicKey( - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c").xCoord + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c" + ).xCoord succeed } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/SignTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/SignTest.scala index e3450531d6..185f354c3e 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/SignTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/SignTest.scala @@ -7,8 +7,8 @@ class SignTest extends BitcoinSCryptoTest { implicit override val generatorDrivenConfig: PropertyCheckConfiguration = generatorDrivenConfigNewCode - //ECPrivateKey implements the sign interface - //so just use it for testing purposes + // ECPrivateKey implements the sign interface + // so just use it for testing purposes val privKey: Sign = ECPrivateKey.freshPrivateKey val pubKey: ECPublicKey = privKey.publicKey @@ -16,14 +16,18 @@ class SignTest extends BitcoinSCryptoTest { it must "identify DER encoded signatures" in { val privateKey = ECPrivateKey.fromHex( - "109cc9befbae8ff3e8b342f08091bf6e6a36d2b6e7acfa9b477d9abc71eb94b4") + "109cc9befbae8ff3e8b342f08091bf6e6a36d2b6e7acfa9b477d9abc71eb94b4" + ) val publicKey = privateKey.publicKey val data = ByteVector.fromValidHex( - "258592575c6bd6d489c38662199f3d469fa9296b56d5873159eb66775035919e") + "258592575c6bd6d489c38662199f3d469fa9296b56d5873159eb66775035919e" + ) val sigCompact = ECDigitalSignature.fromHex( - "b4b07c3373ec271ccf0c51e7491f6d82cdc7b0c50f8ea11130fa266348824a2a2e3f190a4d139faa3e17c677cd8fdcc96c51aee7c1cb2e6edb1d6f8637063f20") + "b4b07c3373ec271ccf0c51e7491f6d82cdc7b0c50f8ea11130fa266348824a2a2e3f190a4d139faa3e17c677cd8fdcc96c51aee7c1cb2e6edb1d6f8637063f20" + ) val sigDER = ECDigitalSignature.fromHex( - "3045022100b4b07c3373ec271ccf0c51e7491f6d82cdc7b0c50f8ea11130fa266348824a2a02202e3f190a4d139faa3e17c677cd8fdcc96c51aee7c1cb2e6edb1d6f8637063f20") + "3045022100b4b07c3373ec271ccf0c51e7491f6d82cdc7b0c50f8ea11130fa266348824a2a02202e3f190a4d139faa3e17c677cd8fdcc96c51aee7c1cb2e6edb1d6f8637063f20" + ) assert(DERSignatureUtil.isDEREncoded(sigDER)) assert(!DERSignatureUtil.isDEREncoded(sigCompact)) assert(publicKey.verify(data, sigDER)) diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/SipHashTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/SipHashTest.scala index d8ec7a5ef8..462aaef9cc 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/SipHashTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/SipHashTest.scala @@ -26,9 +26,11 @@ class SipHashTest extends AnyFlatSpec with Matchers { "8f12b7c16e2c9fc61a2cd869f95fc65da404216ac4542217d33c5135561d5c17,e4638504c41785fa60eb151bd1d7b386,-2965963461982941101" ).tail.map { line => val arr = line.split(",") - (ByteVector.fromValidHex(arr(0)), - SipHashKey(ByteVector.fromValidHex(arr(1))), - arr(2).toLong) + ( + ByteVector.fromValidHex(arr(0)), + SipHashKey(ByteVector.fromValidHex(arr(1))), + arr(2).toLong + ) } it must "compute SipHash" in { diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/XOnlyPubKeyTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/XOnlyPubKeyTest.scala index 50f905e4a8..6050365167 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/XOnlyPubKeyTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/XOnlyPubKeyTest.scala @@ -9,26 +9,35 @@ class XOnlyPubKeyTest extends BitcoinSCryptoTest { it must "fail for incorrect lengths" in { assertThrows[IllegalArgumentException]( XOnlyPubKey( - "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a")) + "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a" + ) + ) assertThrows[IllegalArgumentException]( XOnlyPubKey( - "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a010203")) + "676f8c22de526e0c0904719847e63bda47b4eceb6986bdbaf8695db362811a010203" + ) + ) } it must "fail for invalid x coordinate" in { assertThrows[IllegalArgumentException]( XOnlyPubKey( - "EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34")) + "EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34" + ) + ) assertThrows[IllegalArgumentException]( XOnlyPubKey( - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30")) + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30" + ) + ) } it must "succeed for valid large x coordinates above the curve order" in { val _ = XOnlyPubKey( - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c").coord + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2c" + ).coord succeed } diff --git a/crypto-test/src/test/scala/org/bitcoins/crypto/musig/MuSigTest.scala b/crypto-test/src/test/scala/org/bitcoins/crypto/musig/MuSigTest.scala index beb5d26b4a..b0d0dbd7ba 100644 --- a/crypto-test/src/test/scala/org/bitcoins/crypto/musig/MuSigTest.scala +++ b/crypto-test/src/test/scala/org/bitcoins/crypto/musig/MuSigTest.scala @@ -26,12 +26,15 @@ class MuSigTest extends BitcoinSCryptoTest { sign(noncePriv, aggMuSigNoncePub, privKey, msg, keySet) assert( - partialSigVerify(s, - noncePub, - aggMuSigNoncePub, - pubKey.schnorrPublicKey, - keySet, - msg)) + partialSigVerify( + s, + noncePub, + aggMuSigNoncePub, + pubKey.schnorrPublicKey, + keySet, + msg + ) + ) val sig = signAgg(Vector(s), aggNonce) @@ -42,16 +45,19 @@ class MuSigTest extends BitcoinSCryptoTest { assert( aggPub.schnorrPublicKey == pubKey .multiply(keySet.keyAggCoef(pubKey.schnorrPublicKey)) - .schnorrPublicKey) + .schnorrPublicKey + ) assert(aggPub.schnorrPublicKey.verify(msg, sig)) } } it should "work for two parties" in { - forAll(CryptoGenerators.privateKey, - CryptoGenerators.privateKey, - NumberGenerator.bytevector(32)) { case (priv1, priv2, msg) => + forAll( + CryptoGenerators.privateKey, + CryptoGenerators.privateKey, + NumberGenerator.bytevector(32) + ) { case (priv1, priv2, msg) => val pub1 = priv1.publicKey val noncePriv1: MuSigNoncePriv = MuSigNoncePriv.gen() val noncePub1: MuSigNoncePub = noncePriv1.toPublicNonces @@ -68,19 +74,25 @@ class MuSigTest extends BitcoinSCryptoTest { assert(aggNonce1 == aggNonce2) assert( - partialSigVerify(s1, - noncePub1, - aggMuSigNoncePub, - pub1.schnorrPublicKey, - keySet, - msg)) + partialSigVerify( + s1, + noncePub1, + aggMuSigNoncePub, + pub1.schnorrPublicKey, + keySet, + msg + ) + ) assert( - partialSigVerify(s2, - noncePub2, - aggMuSigNoncePub, - pub2.schnorrPublicKey, - keySet, - msg)) + partialSigVerify( + s2, + noncePub2, + aggMuSigNoncePub, + pub2.schnorrPublicKey, + keySet, + msg + ) + ) val sig = signAgg(Vector(s1, s2), aggNonce1) val aggPub = keySet.aggPubKey @@ -114,12 +126,14 @@ class MuSigTest extends BitcoinSCryptoTest { assert(partialSigs.map(_._1).forall(_ == partialSigs.head._1)) // All partial sigs are valid assert(partialSigs.map(_._2).zipWithIndex.forall { case (s, i) => - partialSigVerify(s, - noncePubs(i), - aggMuSigNoncePub, - privKeys(i).schnorrPublicKey, - keySet, - msg) + partialSigVerify( + s, + noncePubs(i), + aggMuSigNoncePub, + privKeys(i).schnorrPublicKey, + keySet, + msg + ) }) val sig = signAgg(partialSigs.map(_._2), partialSigs.head._1) @@ -138,9 +152,11 @@ class MuSigTest extends BitcoinSCryptoTest { val tweaksGen: Gen[Vector[MuSigTweak]] = Gen .choose[Int](0, 10) .flatMap(n => - Gen.listOfN(n, - CryptoGenerators.fieldElement.flatMap(x => - NumberGenerator.bool.map((x, _))))) + Gen.listOfN( + n, + CryptoGenerators.fieldElement.flatMap(x => + NumberGenerator.bool.map((x, _))) + )) .map(_.toVector) .map(_.map { case (x, b) => MuSigTweak(x, b) }) @@ -165,12 +181,14 @@ class MuSigTest extends BitcoinSCryptoTest { assert(partialSigs.map(_._1).forall(_ == partialSigs.head._1)) // All partial sigs are valid assert(partialSigs.map(_._2).zipWithIndex.forall { case (s, i) => - partialSigVerify(s, - noncePubs(i), - aggMuSigNoncePub, - privKeys(i).schnorrPublicKey, - keySet, - msg) + partialSigVerify( + s, + noncePubs(i), + aggMuSigNoncePub, + privKeys(i).schnorrPublicKey, + keySet, + msg + ) }) val sig = signAgg(partialSigs.map(_._2), aggMuSigNoncePub, keySet, msg) @@ -200,34 +218,43 @@ class MuSigTest extends BitcoinSCryptoTest { assert(UnsortedKeySet(inputs).aggPubKey.schnorrPublicKey == expected(0)) // Vector 2 assert( - UnsortedKeySet(inputs.reverse).aggPubKey.schnorrPublicKey == expected(1)) + UnsortedKeySet(inputs.reverse).aggPubKey.schnorrPublicKey == expected(1) + ) // Vector 3 assert( UnsortedKeySet( - Vector.fill(3)(inputs(0))).aggPubKey.schnorrPublicKey == expected(2)) + Vector.fill(3)(inputs(0)) + ).aggPubKey.schnorrPublicKey == expected(2) + ) // Vector 4 assert( UnsortedKeySet( - Vector(inputs(0), - inputs(0), - inputs(1), - inputs(1))).aggPubKey.schnorrPublicKey == expected(3)) + Vector(inputs(0), inputs(0), inputs(1), inputs(1)) + ).aggPubKey.schnorrPublicKey == expected(3) + ) // The following errors must be handled by the caller as we can't even represent them // Vector 5 assertThrows[IllegalArgumentException]( SchnorrPublicKey.fromHex( - "0000000000000000000000000000000000000000000000000000000000000005")) + "0000000000000000000000000000000000000000000000000000000000000005" + ) + ) // Vector 6 assertThrows[IllegalArgumentException]( SchnorrPublicKey.fromHex( - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30")) + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30" + ) + ) // Vector 7 assertThrows[IllegalArgumentException]( MuSigTweak( FieldElement( - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"), - isXOnlyT = true)) + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141" + ), + isXOnlyT = true + ) + ) // Vector 8 val schnorrG = CryptoParams.getG.schnorrPublicKey val keySetNoTweak = KeySet(schnorrG) @@ -290,17 +317,23 @@ class MuSigTest extends BitcoinSCryptoTest { assertThrows[IllegalArgumentException]( MuSigNoncePub( "04FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A6" ++ - "0248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B833")) + "0248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B833" + ) + ) // Vector 3 assertThrows[IllegalArgumentException]( MuSigNoncePub( "03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A6" ++ - "0248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B831")) + "0248C264CDD57D3C24D79990B0F865674EB62A0F9018277A95011B41BFC193B831" + ) + ) // Vector 4 assertThrows[IllegalArgumentException]( MuSigNoncePub( "03FF406FFD8ADB9CD29877E4985014F66A59F6CD01C0E88CAA8E5F3166B1F676A6" ++ - "02FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30")) + "02FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30" + ) + ) // Vector 5 val g = CryptoParams.getG.toPoint @@ -321,7 +354,8 @@ class MuSigTest extends BitcoinSCryptoTest { val privNonce = MuSigNoncePriv( "508B81A611F100A6B2B6B29656590898AF488BCF2E1F55CF22E5CFB84421FE61" ++ - "FA27FD49B1D50085B481285E1CA205D55C82CC1B31FF5CD54A489829355901F7") + "FA27FD49B1D50085B481285E1CA205D55C82CC1B31FF5CD54A489829355901F7" + ) val pubNonces = Vector( "0337C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA" ++ @@ -338,15 +372,18 @@ class MuSigTest extends BitcoinSCryptoTest { val aggNonce = MuSigNoncePub( "028465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61" ++ - "037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9") + "037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9" + ) assert(aggNonce == MuSigNoncePub.aggregate(pubNonces.take(3))) val sk = ECPrivateKey( - "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671") + "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671" + ) val pk = sk.schnorrPublicKey val msg = ByteVector.fromValidHex( - "F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF") + "F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF" + ) val expected = Vector( "68537CC5234E505BD14061F8DA9E90C220A181855FD8BDB7F127BB12403B4D3B", @@ -378,75 +415,103 @@ class MuSigTest extends BitcoinSCryptoTest { // Vector 5, 17 assertThrows[IllegalArgumentException]( SchnorrPublicKey( - "0000000000000000000000000000000000000000000000000000000000000007")) + "0000000000000000000000000000000000000000000000000000000000000007" + ) + ) // Vector 6 assertThrows[IllegalArgumentException]( MuSigNoncePub( "048465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61" ++ - "037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9")) + "037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9" + ) + ) // Vector 7 assertThrows[IllegalArgumentException]( MuSigNoncePub( "028465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61" ++ - "020000000000000000000000000000000000000000000000000000000000000009")) + "020000000000000000000000000000000000000000000000000000000000000009" + ) + ) // Vector 8 assertThrows[IllegalArgumentException]( MuSigNoncePub( "028465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61" ++ - "02FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30")) + "02FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30" + ) + ) // Verification test vectors // Vector 9 assert( - partialSigVerify(expected(0), - pubNonces.take(3), - keySet1, - msg, - signerIndex = 0)) + partialSigVerify( + expected(0), + pubNonces.take(3), + keySet1, + msg, + signerIndex = 0 + ) + ) // Vector 10 assert( - partialSigVerify(expected(1), - Vector(pubNonces(1), pubNonces(0), pubNonces(2)), - keySet2, - msg, - signerIndex = 1)) + partialSigVerify( + expected(1), + Vector(pubNonces(1), pubNonces(0), pubNonces(2)), + keySet2, + msg, + signerIndex = 1 + ) + ) // Vector 11 assert( - partialSigVerify(expected(2), - Vector(pubNonces(1), pubNonces(2), pubNonces(0)), - keySet3, - msg, - signerIndex = 2)) + partialSigVerify( + expected(2), + Vector(pubNonces(1), pubNonces(2), pubNonces(0)), + keySet3, + msg, + signerIndex = 2 + ) + ) // Vector 12 assert( - partialSigVerify(expected(3), - Vector(pubNonces(0), pubNonces(3)), - keySet4, - msg, - signerIndex = 0)) + partialSigVerify( + expected(3), + Vector(pubNonces(0), pubNonces(3)), + keySet4, + msg, + signerIndex = 0 + ) + ) // Vector 13 val badSig = FieldElement( - "97AC833ADCB1AFA42EBF9E0725616F3C9A0D5B614F6FE283CEAAA37A8FFAF406") + "97AC833ADCB1AFA42EBF9E0725616F3C9A0D5B614F6FE283CEAAA37A8FFAF406" + ) assert(!partialSigVerify(badSig, pubNonces, keySet1, msg, signerIndex = 0)) // Vector 14 assert( - !partialSigVerify(expected(0), - pubNonces.take(3), - keySet1, - msg, - signerIndex = 1)) + !partialSigVerify( + expected(0), + pubNonces.take(3), + keySet1, + msg, + signerIndex = 1 + ) + ) // The following errors must be handled by the caller as we can't even represent them // Vector 15 assertThrows[IllegalArgumentException]( FieldElement( - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")) + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141" + ) + ) // Vector 16 assertThrows[IllegalArgumentException]( MuSigNoncePub( "020000000000000000000000000000000000000000000000000000000000000009" ++ - pubNonces.head.bytes.drop(33).toHex)) + pubNonces.head.bytes.drop(33).toHex + ) + ) } // https://github.com/jonasnick/bips/blob/musig2/bip-musig2/reference.py#L629 @@ -458,7 +523,8 @@ class MuSigTest extends BitcoinSCryptoTest { val secnonce = MuSigNoncePriv( "508B81A611F100A6B2B6B29656590898AF488BCF2E1F55CF22E5CFB84421FE61" ++ - "FA27FD49B1D50085B481285E1CA205D55C82CC1B31FF5CD54A489829355901F7") + "FA27FD49B1D50085B481285E1CA205D55C82CC1B31FF5CD54A489829355901F7" + ) val pnonce = Vector( "0337C87821AFD50A8644D820A8F3E02E499C931865C2360FB43D0A0D20DAFE07EA" ++ @@ -471,12 +537,15 @@ class MuSigTest extends BitcoinSCryptoTest { val aggnonce = MuSigNoncePub( "028465FCF0BBDBCF443AABCCE533D42B4B5A10966AC09A49655E8C42DAAB8FCD61" ++ - "037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9") + "037496A3CC86926D452CAFCFD55D25972CA1675D549310DE296BFF42F72EEEA8C9" + ) val sk = ECPrivateKey( - "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671") + "7FB9E0E687ADA1EEBF7ECFE2F21E73EBDB51A7D450948DFE8D76D7F2D1007671" + ) val msg = ByteVector.fromValidHex( - "F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF") + "F95466D086770E689964664219266FE5ED215C92AE20BAB5C9D79ADDDDF3C0CF" + ) val tweaks = Vector( "E8F791FF9225A2AF0102AFFF4A9A723D9612A682A25EBE79802B263CDFCD83BB", @@ -502,40 +571,51 @@ class MuSigTest extends BitcoinSCryptoTest { val keySet1 = keySet.withTweaks(tweaks1) assert(sign(secnonce, aggnonce, sk, msg, keySet1)._2 == expected(0)) assert( - partialSigVerify(expected(0), pnonces, keySet1, msg, signerIndex = 2)) + partialSigVerify(expected(0), pnonces, keySet1, msg, signerIndex = 2) + ) // Vector 2 val tweaks2 = Vector(MuSigTweak(tweaks(0), isXOnlyT = false)) val keySet2 = keySet.withTweaks(tweaks2) assert(sign(secnonce, aggnonce, sk, msg, keySet2)._2 == expected(1)) assert( - partialSigVerify(expected(1), pnonces, keySet2, msg, signerIndex = 2)) + partialSigVerify(expected(1), pnonces, keySet2, msg, signerIndex = 2) + ) // Vector 3 - val tweaks3 = Vector(MuSigTweak(tweaks(0), isXOnlyT = false), - MuSigTweak(tweaks(1), isXOnlyT = true)) + val tweaks3 = Vector( + MuSigTweak(tweaks(0), isXOnlyT = false), + MuSigTweak(tweaks(1), isXOnlyT = true) + ) val keySet3 = keySet.withTweaks(tweaks3) assert(sign(secnonce, aggnonce, sk, msg, keySet3)._2 == expected(2)) assert( - partialSigVerify(expected(2), pnonces, keySet3, msg, signerIndex = 2)) + partialSigVerify(expected(2), pnonces, keySet3, msg, signerIndex = 2) + ) // Vector 4 - val tweaks4 = Vector(MuSigTweak(tweaks(0), isXOnlyT = true), - MuSigTweak(tweaks(1), isXOnlyT = false), - MuSigTweak(tweaks(2), isXOnlyT = true), - MuSigTweak(tweaks(3), isXOnlyT = false)) + val tweaks4 = Vector( + MuSigTweak(tweaks(0), isXOnlyT = true), + MuSigTweak(tweaks(1), isXOnlyT = false), + MuSigTweak(tweaks(2), isXOnlyT = true), + MuSigTweak(tweaks(3), isXOnlyT = false) + ) val keySet4 = keySet.withTweaks(tweaks4) assert(sign(secnonce, aggnonce, sk, msg, keySet4)._2 == expected(3)) assert( - partialSigVerify(expected(3), pnonces, keySet4, msg, signerIndex = 2)) + partialSigVerify(expected(3), pnonces, keySet4, msg, signerIndex = 2) + ) // The following error must be handled by the caller as we can't even represent it // Vector 5 assertThrows[IllegalArgumentException]( MuSigTweak( FieldElement( - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"), - isXOnlyT = false)) + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141" + ), + isXOnlyT = false + ) + ) } // https://github.com/jonasnick/bips/blob/263a765a77e20efe883ed3b28dc155a0d8c7d61a/bip-musig2/reference.py#L702 @@ -561,7 +641,8 @@ class MuSigTest extends BitcoinSCryptoTest { ).map(MuSigNoncePub.fromHex) val msg = ByteVector.fromValidHex( - "599C67EA410D005B9DA90817CF03ED3B1C868E4DA4EDF00A5880B0082C237869") + "599C67EA410D005B9DA90817CF03ED3B1C868E4DA4EDF00A5880B0082C237869" + ) val tweaks = Vector( "B511DA492182A91B0FFB9A98020D55F260AE86D7ECBD0399C7383D59A5F2AF7C", @@ -611,9 +692,11 @@ class MuSigTest extends BitcoinSCryptoTest { assert(keySet3.aggPubKey.schnorrPublicKey.verify(msg, sig3)) // Vector 4 - val tweaks4 = Vector(MuSigTweak(tweaks(0), isXOnlyT = true), - MuSigTweak(tweaks(1), isXOnlyT = false), - MuSigTweak(tweaks(2), isXOnlyT = true)) + val tweaks4 = Vector( + MuSigTweak(tweaks(0), isXOnlyT = true), + MuSigTweak(tweaks(1), isXOnlyT = false), + MuSigTweak(tweaks(2), isXOnlyT = true) + ) val keySet4 = UnsortedKeySet(Vector(pubKeys(0), pubKeys(3)), tweaks4) val sig4 = signAgg(psig.slice(6, 8), aggNonce(3), keySet4, msg) assert(sig4 == expected(3)) @@ -623,6 +706,8 @@ class MuSigTest extends BitcoinSCryptoTest { // Vector 5 assertThrows[IllegalArgumentException]( FieldElement( - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")) + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141" + ) + ) } } diff --git a/crypto/.js/src/main/scala/org/bitcoins/crypto/BCryptoCryptoRuntime.scala b/crypto/.js/src/main/scala/org/bitcoins/crypto/BCryptoCryptoRuntime.scala index ffdd0d4cdc..be4f6faf3d 100644 --- a/crypto/.js/src/main/scala/org/bitcoins/crypto/BCryptoCryptoRuntime.scala +++ b/crypto/.js/src/main/scala/org/bitcoins/crypto/BCryptoCryptoRuntime.scala @@ -8,8 +8,8 @@ import scala.scalajs.js import scala.scalajs.js.JSStringOps._ import scala.scalajs.js.{JavaScriptException, UnicodeNormalizationForm} -/** This is an implementation of [[CryptoRuntime]] that defaults to - * Bcrypto (https://github.com/bcoin-org/bcrypto) when possible. +/** This is an implementation of [[CryptoRuntime]] that defaults to Bcrypto + * (https://github.com/bcoin-org/bcrypto) when possible. */ trait BCryptoCryptoRuntime extends CryptoRuntime { override val cryptoContext: CryptoContext = CryptoContext.BCrypto @@ -59,14 +59,18 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { /** Converts a private key -> public key * - * @param privateKey the private key we want the corresponding public key for - * @param isCompressed whether the returned public key should be compressed or not + * @param privateKey + * the private key we want the corresponding public key for + * @param isCompressed + * whether the returned public key should be compressed or not */ override def toPublicKey(privateKey: ECPrivateKeyBytes): ECPublicKey = { val buffer = CryptoJsUtil.toNodeBuffer(privateKey.bytes) val pubKeyBuffer = - SECP256k1.publicKeyCreate(key = buffer, - compressed = privateKey.isCompressed) + SECP256k1.publicKeyCreate( + key = buffer, + compressed = privateKey.isCompressed + ) val privKeyByteVec = CryptoJsUtil.toByteVector(pubKeyBuffer) ECPublicKey.fromBytes(privKeyByteVec) } @@ -135,17 +139,24 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { override def normalize(str: String): String = str.normalize(UnicodeNormalizationForm.NFC) - /** Recover public keys from a signature and the message that was signed. This method will return 2 public keys, and the signature - * can be verified with both, but only one of them matches that private key that was used to generate the signature. + /** Recover public keys from a signature and the message that was signed. This + * method will return 2 public keys, and the signature can be verified with + * both, but only one of them matches that private key that was used to + * generate the signature. * - * @param signature signature - * @param message message that was signed - * @return a (pub1, pub2) tuple where pub1 and pub2 are candidates public keys. If you have the recovery id then use - * pub1 if the recovery id is even and pub2 if it is odd + * @param signature + * signature + * @param message + * message that was signed + * @return + * a (pub1, pub2) tuple where pub1 and pub2 are candidates public keys. If + * you have the recovery id then use pub1 if the recovery id is even and + * pub2 if it is odd */ override def recoverPublicKey( signature: ECDigitalSignature, - message: ByteVector): (ECPublicKey, ECPublicKey) = { + message: ByteVector + ): (ECPublicKey, ECPublicKey) = { val msgBuffer = CryptoJsUtil.toNodeBuffer(message) val sigBuffer = CryptoJsUtil.toNodeBuffer(signature.bytes) val keyBytes = @@ -179,7 +190,8 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { override def sign( privateKey: ECPrivateKey, - dataToSign: ByteVector): ECDigitalSignature = { + dataToSign: ByteVector + ): ECDigitalSignature = { val privBuffer = CryptoJsUtil.toNodeBuffer(privateKey.bytes) val dataBuffer = CryptoJsUtil.toNodeBuffer(dataToSign) val buffer = SECP256k1.signDER(dataBuffer, privBuffer) @@ -190,7 +202,8 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { override def signWithEntropy( privateKey: ECPrivateKey, bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature = ??? + entropy: ByteVector + ): ECDigitalSignature = ??? override def secKeyVerify(privateKeybytes: ByteVector): Boolean = { val buffer = CryptoJsUtil.toNodeBuffer(privateKeybytes) @@ -200,7 +213,8 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { override def verify( publicKey: ECPublicKeyApi, data: ByteVector, - signature: ECDigitalSignature): Boolean = { + signature: ECDigitalSignature + ): Boolean = { val dataBuffer = CryptoJsUtil.toNodeBuffer(data) val sigBuffer = CryptoJsUtil.toNodeBuffer(signature.bytes) val pubKeyBuffer = CryptoJsUtil.toNodeBuffer(publicKey.bytes) @@ -209,7 +223,8 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { override def tweakMultiply( publicKey: ECPublicKey, - tweak: FieldElement): ECPublicKey = { + tweak: FieldElement + ): ECPublicKey = { val pubKeyBuffer = CryptoJsUtil.toNodeBuffer(publicKey.decompressedBytes) val tweakBuffer = CryptoJsUtil.toNodeBuffer(tweak.bytes) val keyBuffer = @@ -223,8 +238,10 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { val pk2Buffer = CryptoJsUtil.toNodeBuffer(pk2.decompressedBytes) try { val keyBuffer = - SECP256k1.publicKeyCombine(js.Array(pk1Buffer, pk2Buffer), - compress = true) + SECP256k1.publicKeyCombine( + js.Array(pk1Buffer, pk2Buffer), + compress = true + ) val keyBytes = CryptoJsUtil.toByteVector(keyBuffer) ECPublicKey.fromBytes(keyBytes) } catch { @@ -235,7 +252,8 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { // check for infinity if ((k1.head ^ k2.head) == 0x01 && k1.tail == k2.tail) { throw new IllegalArgumentException( - s"Invalid public key sum, got 0x00 = $pk1 + $pk2") + s"Invalid public key sum, got 0x00 = $pk1 + $pk2" + ) } else { throw ex } @@ -244,7 +262,8 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { override def pubKeyTweakAdd( pubkey: ECPublicKey, - privkey: ECPrivateKey): ECPublicKey = { + privkey: ECPrivateKey + ): ECPublicKey = { val pubKeyBuffer = CryptoJsUtil.toNodeBuffer(pubkey.decompressedBytes) val privKeyBuffer = CryptoJsUtil.toNodeBuffer(privkey.bytes) val keyBuffer = @@ -278,8 +297,10 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { if (decoded.isInfinity()) SecpPointInfinity else - SecpPoint(new BigInteger(decoded.getX().toString()), - new BigInteger(decoded.getY().toString())) + SecpPoint( + new BigInteger(decoded.getX().toString()), + new BigInteger(decoded.getY().toString()) + ) } } @@ -287,17 +308,20 @@ trait BCryptoCryptoRuntime extends CryptoRuntime { pass: ByteVector, salt: ByteVector, iterationCount: Int, - derivedKeyLength: Int): ByteVector = { + derivedKeyLength: Int + ): ByteVector = { // bcrypto uses bytes instead of bits for length, so divide by 8 val keyLengthBytes = derivedKeyLength / 8 val buffer = - PBKDF2.derive(sha512, - CryptoJsUtil.toNodeBuffer(pass), - CryptoJsUtil.toNodeBuffer(salt), - iterationCount, - keyLengthBytes) + PBKDF2.derive( + sha512, + CryptoJsUtil.toNodeBuffer(pass), + CryptoJsUtil.toNodeBuffer(salt), + iterationCount, + keyLengthBytes + ) CryptoJsUtil.toByteVector(buffer) } } diff --git a/crypto/.js/src/main/scala/org/bitcoins/crypto/CryptoJsUtil.scala b/crypto/.js/src/main/scala/org/bitcoins/crypto/CryptoJsUtil.scala index 0de05b5c04..b02c764644 100644 --- a/crypto/.js/src/main/scala/org/bitcoins/crypto/CryptoJsUtil.scala +++ b/crypto/.js/src/main/scala/org/bitcoins/crypto/CryptoJsUtil.scala @@ -12,7 +12,7 @@ object CryptoJsUtil { toByteVector(buffer, buffer.length) def toByteVector(buffer: Buffer, len: Int): ByteVector = { - //is this right? + // is this right? val iter: js.Iterator[Int] = buffer.values() val accum = new scala.collection.mutable.ArrayBuffer[Int](len) @@ -26,14 +26,16 @@ object CryptoJsUtil { accum += entry.value } } - require(accum.length == len, - s"Need $len bytes for buffer -> bytevector conversion") + require( + accum.length == len, + s"Need $len bytes for buffer -> bytevector conversion" + ) ByteVector(accum.map(_.toByte)) } def toNodeBuffer(byteVector: ByteVector): Buffer = { - //the implicit used here is this - //https://github.com/scala-js/scala-js/blob/b5a93bb99a0b0b5044141d4b2871ea260ef17798/library/src/main/scala/scala/scalajs/js/typedarray/package.scala#L33 + // the implicit used here is this + // https://github.com/scala-js/scala-js/blob/b5a93bb99a0b0b5044141d4b2871ea260ef17798/library/src/main/scala/scala/scalajs/js/typedarray/package.scala#L33 Buffer.from(byteVector.toArray.toTypedArray.buffer) } } diff --git a/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/Buffer.scala b/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/Buffer.scala index 6837d59b9d..430976855f 100644 --- a/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/Buffer.scala +++ b/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/Buffer.scala @@ -7,19 +7,26 @@ import scala.scalajs.js.| //Copied from //https://github.com/scalajs-io/nodejs/blob/master/app/common/src/main/scala/io/scalajs/nodejs/buffer/Buffer.scala -/** Prior to the introduction of TypedArray in ECMAScript 2015 (ES6), the JavaScript language had no mechanism for - * reading or manipulating streams of binary data. The Buffer class was introduced as part of the Node.js API to - * make it possible to interact with octet streams in the context of things like TCP streams and file system operations. +/** Prior to the introduction of TypedArray in ECMAScript 2015 (ES6), the + * JavaScript language had no mechanism for reading or manipulating streams of + * binary data. The Buffer class was introduced as part of the Node.js API to + * make it possible to interact with octet streams in the context of things + * like TCP streams and file system operations. * - * Now that TypedArray has been added in ES6, the Buffer class implements the Uint8Array API in a manner that is more - * optimized and suitable for Node.js' use cases. + * Now that TypedArray has been added in ES6, the Buffer class implements the + * Uint8Array API in a manner that is more optimized and suitable for Node.js' + * use cases. * - * Instances of the Buffer class are similar to arrays of integers but correspond to fixed-sized, raw memory - * allocations outside the V8 heap. The size of the Buffer is established when it is created and cannot be resized. + * Instances of the Buffer class are similar to arrays of integers but + * correspond to fixed-sized, raw memory allocations outside the V8 heap. The + * size of the Buffer is established when it is created and cannot be resized. * - * The Buffer class is a global within Node.js, making it unlikely that one would need to ever use require('buffer'). - * @see https://nodejs.org/api/buffer.html - * @author lawrence.daniels@gmail.com + * The Buffer class is a global within Node.js, making it unlikely that one + * would need to ever use require('buffer'). + * @see + * https://nodejs.org/api/buffer.html + * @author + * lawrence.daniels@gmail.com */ @js.native @JSImport("buffer", "Buffer") @@ -29,65 +36,83 @@ class Buffer() extends js.Object { // Constructors ///////////////////////////////////////////////////////////////////////////////// - /** @example new Buffer(size) + /** @example + * new Buffer(size) */ @inline def this(size: Int) = this() - /** @example new Buffer(str, [encoding]) + /** @example + * new Buffer(str, [encoding]) */ @inline @deprecated("Use Buffer.from(str[, encoding]) instead.", since = "6.0.0") def this(str: String, encoding: String = js.native) = this() - /** @example new Buffer(array) + /** @example + * new Buffer(array) */ @inline @deprecated("Use Buffer.from(array) instead.", since = "6.0.0") def this(array: js.Array[Int]) = this() - /** @example new Buffer(buffer) + /** @example + * new Buffer(buffer) */ @inline @deprecated("Use Buffer.from(buffer) instead.", since = "6.0.0") def this(buffer: Buffer) = this() - /** @example {{{ new Buffer(arrayBuffer[, byteOffset[, length]]) }}} + /** @example + * {{{new Buffer(arrayBuffer[, byteOffset[, length]])}}} */ @inline - @deprecated("Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.", - since = "6.0.0") + @deprecated( + "Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.", + since = "6.0.0" + ) def this(arrayBuffer: ArrayBuffer, byteOffset: Int, length: Int) = this() - /** @example {{{ new Buffer(arrayBuffer[, byteOffset[, length]]) }}} + /** @example + * {{{new Buffer(arrayBuffer[, byteOffset[, length]])}}} */ @inline - @deprecated("Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.", - since = "6.0.0") + @deprecated( + "Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.", + since = "6.0.0" + ) def this(arrayBuffer: ArrayBuffer, byteOffset: Int) = this() - /** @example {{{ new Buffer(arrayBuffer[, byteOffset[, length]]) }}} + /** @example + * {{{new Buffer(arrayBuffer[, byteOffset[, length]])}}} */ @inline - @deprecated("Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.", - since = "6.0.0") + @deprecated( + "Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.", + since = "6.0.0" + ) def this(arrayBuffer: ArrayBuffer) = this() ///////////////////////////////////////////////////////////////////////////////// // Accessors and Mutators ///////////////////////////////////////////////////////////////////////////////// - /** The index operator [index] can be used to get and set the octet at position index in buf. The values refer - * to individual bytes, so the legal value range is between 0x00 and 0xFF (hex) or 0 and 255 (decimal). - * @param index the given index - * @return the value at the given index + /** The index operator [index] can be used to get and set the octet at + * position index in buf. The values refer to individual bytes, so the legal + * value range is between 0x00 and 0xFF (hex) or 0 and 255 (decimal). + * @param index + * the given index + * @return + * the value at the given index */ @JSBracketAccess def apply(index: Int): Int = js.native - /** The index operator [index] can be used to get and set the octet at position index in buf. The values refer - * to individual bytes, so the legal value range is between 0x00 and 0xFF (hex) or 0 and 255 (decimal). - * @param index the given index + /** The index operator [index] can be used to get and set the octet at + * position index in buf. The values refer to individual bytes, so the legal + * value range is between 0x00 and 0xFF (hex) or 0 and 255 (decimal). + * @param index + * the given index */ @JSBracketAccess def update(index: Int, value: Int): Unit = js.native @@ -96,772 +121,1106 @@ class Buffer() extends js.Object { // Methods ///////////////////////////////////////////////////////////////////////////////// - /** Compares buf with target and returns a number indicating whether buf comes before, after, or is the same - * as target in sort order. Comparison is based on the actual sequence of bytes in each Buffer. - * @param target A Buffer to compare to - * @param targetStart The offset within target at which to begin comparison. Default: 0 - * @param targetEnd The offset with target at which to end comparison (not inclusive). Ignored when targetStart - * is undefined. Default: target.length - * @param sourceStart The offset within buf at which to begin comparison. Ignored when targetStart is undefined. Default: 0 - * @param sourceEnd The offset within buf at which to end comparison (not inclusive). - * Ignored when targetStart is undefined. Default: buf.length - * @return 0 is returned if target is the same as buf - * 1 is returned if target should come before buf when sorted. - * -1 is returned if target should come after buf when sorted. - * @example {{{ buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]]) }}} + /** Compares buf with target and returns a number indicating whether buf comes + * before, after, or is the same as target in sort order. Comparison is based + * on the actual sequence of bytes in each Buffer. + * @param target + * A Buffer to compare to + * @param targetStart + * The offset within target at which to begin comparison. Default: 0 + * @param targetEnd + * The offset with target at which to end comparison (not inclusive). + * Ignored when targetStart is undefined. Default: target.length + * @param sourceStart + * The offset within buf at which to begin comparison. Ignored when + * targetStart is undefined. Default: 0 + * @param sourceEnd + * The offset within buf at which to end comparison (not inclusive). + * Ignored when targetStart is undefined. Default: buf.length + * @return + * 0 is returned if target is the same as buf 1 is returned if target + * should come before buf when sorted. -1 is returned if target should come + * after buf when sorted. + * @example + * {{{buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])}}} */ def compare( target: Buffer, targetStart: Int = js.native, targetEnd: Int = js.native, sourceStart: Int = js.native, - sourceEnd: Int = js.native): Int = js.native + sourceEnd: Int = js.native + ): Int = js.native - /** Copies data from a region of buf to a region in target even if the target memory region overlaps with buf. - * @param target A Buffer to copy into. - * @param targetStart The offset within target at which to begin copying to. Default: 0 - * @param sourceStart The offset within buf at which to begin copying from. - * Ignored when targetStart is undefined. Default: 0 - * @param sourceEnd The offset within buf at which to stop copying (not inclusive). - * Ignored when sourceStart is undefined. Default: buf.length - * @return The number of bytes copied. - * @example {{{ buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]]) }}} + /** Copies data from a region of buf to a region in target even if the target + * memory region overlaps with buf. + * @param target + * A Buffer to copy into. + * @param targetStart + * The offset within target at which to begin copying to. Default: 0 + * @param sourceStart + * The offset within buf at which to begin copying from. Ignored when + * targetStart is undefined. Default: 0 + * @param sourceEnd + * The offset within buf at which to stop copying (not inclusive). Ignored + * when sourceStart is undefined. Default: buf.length + * @return + * The number of bytes copied. + * @example + * {{{buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])}}} */ def copy( target: Buffer, targetStart: Int = js.native, sourceStart: Int = js.native, - sourceEnd: Int = js.native): Int = js.native + sourceEnd: Int = js.native + ): Int = js.native - /** Creates and returns an iterator of [index, byte] pairs from the Buffer contents. - * @return an [[Iterator]] + /** Creates and returns an iterator of [index, byte] pairs from the Buffer + * contents. + * @return + * an [[Iterator]] */ def entries(): js.Iterator[js.Array[Int]] = js.native - /** Returns true if both buf and otherBuffer have exactly the same bytes, false otherwise. - * @param otherBuffer A Buffer to compare to - * @return true if both buf and otherBuffer have exactly the same bytes, false otherwise. - * @example buf.equals(otherBuffer) + /** Returns true if both buf and otherBuffer have exactly the same bytes, + * false otherwise. + * @param otherBuffer + * A Buffer to compare to + * @return + * true if both buf and otherBuffer have exactly the same bytes, false + * otherwise. + * @example + * buf.equals(otherBuffer) */ def equals(otherBuffer: Buffer): Boolean = js.native - /** Fills buf with the specified value. If the offset and end are not given, the entire buf will be filled. - * This is meant to be a small simplification to allow the creation and filling of a Buffer to be done on a single line. - * @param value The value to fill buf with - * @param offset Where to start filling buf. Default: 0 - * @param end Where to stop filling buf (not inclusive). Default: buf.length - * @param encoding If value is a string, this is its encoding. Default: 'utf8' - * @return A reference to buf - * @example {{{ buf.fill(value[, offset[, end]][, encoding]) }}} + /** Fills buf with the specified value. If the offset and end are not given, + * the entire buf will be filled. This is meant to be a small simplification + * to allow the creation and filling of a Buffer to be done on a single line. + * @param value + * The value to fill buf with + * @param offset + * Where to start filling buf. Default: 0 + * @param end + * Where to stop filling buf (not inclusive). Default: buf.length + * @param encoding + * If value is a string, this is its encoding. Default: 'utf8' + * @return + * A reference to buf + * @example + * {{{buf.fill(value[, offset[, end]][, encoding])}}} */ def fill( value: Buffer | Int | String, offset: Int = js.native, end: Int = js.native, - encoding: String = js.native): this.type = js.native + encoding: String = js.native + ): this.type = js.native - /** Returns the index of the first occurrence of value in buf or -1 if buf does not contain value - * @param value What to search for - * @param byteOffset Where to begin searching in buf. Default: 0 - * @param encoding If value is a string, this is its encoding. Default: 'utf8' - * @return The index of the first occurrence of value in buf or -1 if buf does not contain value - * @example {{{ buf.indexOf(value[, byteOffset][, encoding]) }}} + /** Returns the index of the first occurrence of value in buf or -1 if buf + * does not contain value + * @param value + * What to search for + * @param byteOffset + * Where to begin searching in buf. Default: 0 + * @param encoding + * If value is a string, this is its encoding. Default: 'utf8' + * @return + * The index of the first occurrence of value in buf or -1 if buf does not + * contain value + * @example + * {{{buf.indexOf(value[, byteOffset][, encoding])}}} */ def indexOf( value: Buffer | Int | String, byteOffset: Int = js.native, - encoding: String = js.native): Int = js.native + encoding: String = js.native + ): Int = js.native /** Equivalent to buf.indexOf() !== -1. - * @param value What to search for - * @param byteOffset Where to begin searching in buf. Default: 0 - * @param encoding If value is a string, this is its encoding. Default: 'utf8' - * @return true if value was found in buf, false otherwise - * @example {{{ buf.includes(value[, byteOffset][, encoding]) }}} + * @param value + * What to search for + * @param byteOffset + * Where to begin searching in buf. Default: 0 + * @param encoding + * If value is a string, this is its encoding. Default: 'utf8' + * @return + * true if value was found in buf, false otherwise + * @example + * {{{buf.includes(value[, byteOffset][, encoding])}}} */ def includes( value: Buffer | Int | String, byteOffset: Int = js.native, - encoding: String = js.native): Boolean = + encoding: String = js.native + ): Boolean = js.native /** Creates and returns an iterator of buf keys (indices). - * @return an [[Iterator]] - * @example buf.keys() + * @return + * an [[Iterator]] + * @example + * buf.keys() */ def keys(): js.Iterator[Int] = js.native - /** The largest size allowed for a single Buffer instance. - * On 32-bit architectures, this value is (2^30)-1 (~1GB). On 64-bit architectures, this value is (2^31)-1 (~2GB). - * Note that this is a property on the buffer module returned by require('buffer'), not on the Buffer global or - * a Buffer instance. - * @return the largest size allowed + /** The largest size allowed for a single Buffer instance. On 32-bit + * architectures, this value is (2^30)-1 (~1GB). On 64-bit architectures, + * this value is (2^31)-1 (~2GB). Note that this is a property on the buffer + * module returned by require('buffer'), not on the Buffer global or a Buffer + * instance. + * @return + * the largest size allowed */ def kMaxLength: Int = js.native - /** Identical to buf.indexOf(), except buf is searched from back to front instead of front to back. - * @param value What to search for - * @param byteOffset Where to begin searching in buf. Default: 0 - * @param encoding If value is a string, this is its encoding. Default: 'utf8' - * @return The index of the last occurrence of value in buf or -1 if buf does not contain value - * @example {{{ buf.lastIndexOf(value[, byteOffset][, encoding]) }}} + /** Identical to buf.indexOf(), except buf is searched from back to front + * instead of front to back. + * @param value + * What to search for + * @param byteOffset + * Where to begin searching in buf. Default: 0 + * @param encoding + * If value is a string, this is its encoding. Default: 'utf8' + * @return + * The index of the last occurrence of value in buf or -1 if buf does not + * contain value + * @example + * {{{buf.lastIndexOf(value[, byteOffset][, encoding])}}} */ def lastIndexOf( value: Buffer | Int | String, byteOffset: Int = js.native, - encoding: String = js.native): Int = + encoding: String = js.native + ): Int = js.native - /** Returns the amount of memory allocated for buf in bytes. - * Note that this does not necessarily reflect the amount of "usable" data within buf. - * @return the amount of memory allocated for buf in bytes. - * @example buf.length + /** Returns the amount of memory allocated for buf in bytes. Note that this + * does not necessarily reflect the amount of "usable" data within buf. + * @return + * the amount of memory allocated for buf in bytes. + * @example + * buf.length */ def length: Int = js.native - /** Reads a 64-bit double from buf at the specified offset with specified endian format (readDoubleBE() - * returns big endian, readDoubleLE() returns little endian). + /** Reads a 64-bit double from buf at the specified offset with specified + * endian format (readDoubleBE() returns big endian, readDoubleLE() returns + * little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 8 - * @param noAssert Skip offset validation? Default: false - * @return a [[Double]] value - * @example {{{ buf.readDoubleBE(offset[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 8 + * @param noAssert + * Skip offset validation? Default: false + * @return + * a [[Double]] value + * @example + * {{{buf.readDoubleBE(offset[, noAssert])}}} */ def readDoubleBE(offset: Int, noAssert: Boolean = js.native): Double = js.native - /** Reads a 64-bit double from buf at the specified offset with specified endian format (readDoubleBE() - * returns big endian, readDoubleLE() returns little endian). + /** Reads a 64-bit double from buf at the specified offset with specified + * endian format (readDoubleBE() returns big endian, readDoubleLE() returns + * little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 8 - * @param noAssert Skip offset validation? Default: false - * @return a [[Double]] value - * @example {{{ buf.readDoubleBE(offset[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 8 + * @param noAssert + * Skip offset validation? Default: false + * @return + * a [[Double]] value + * @example + * {{{buf.readDoubleBE(offset[, noAssert])}}} */ def readDoubleLE(offset: Int, noAssert: Boolean = js.native): Double = js.native - /** Reads a 32-bit float from buf at the specified offset with specified endian format (readFloatBE() - * returns big endian, readFloatLE() returns little endian). + /** Reads a 32-bit float from buf at the specified offset with specified + * endian format (readFloatBE() returns big endian, readFloatLE() returns + * little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip offset validation? Default: false - * @return a [[Double]] value - * @example {{{ buf.readFloatBE(offset[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip offset validation? Default: false + * @return + * a [[Double]] value + * @example + * {{{buf.readFloatBE(offset[, noAssert])}}} */ def readFloatBE(offset: Int, noAssert: Boolean = js.native): Double = js.native - /** Reads a 32-bit float from buf at the specified offset with specified endian format (readFloatBE() - * returns big endian, readFloatLE() returns little endian). + /** Reads a 32-bit float from buf at the specified offset with specified + * endian format (readFloatBE() returns big endian, readFloatLE() returns + * little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip offset validation? Default: false - * @return a [[Double]] value - * @example {{{ buf.readFloatLE(offset[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip offset validation? Default: false + * @return + * a [[Double]] value + * @example + * {{{buf.readFloatLE(offset[, noAssert])}}} */ def readFloatLE(offset: Int, noAssert: Boolean = js.native): Double = js.native /** Reads a signed 8-bit integer from buf at the specified offset. * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be considered undefined behavior. + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. * - * Integers read from a Buffer are interpreted as two's complement signed values. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 1 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readInt8(offset[, noAssert]) }}} + * Integers read from a Buffer are interpreted as two's complement signed + * values. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 1 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readInt8(offset[, noAssert])}}} */ def readInt8(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads a signed 16-bit integer from buf at the specified offset with the specified endian format - * (readInt16BE() returns big endian, readInt16LE() returns little endian). + /** Reads a signed 16-bit integer from buf at the specified offset with the + * specified endian format (readInt16BE() returns big endian, readInt16LE() + * returns little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. * - * Integers read from a Buffer are interpreted as two's complement signed values. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 2 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readInt16BE(offset[, noAssert]) }}} + * Integers read from a Buffer are interpreted as two's complement signed + * values. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 2 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readInt16BE(offset[, noAssert])}}} */ def readInt16BE(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads a signed 16-bit integer from buf at the specified offset with the specified endian format - * (readInt16BE() returns big endian, readInt16LE() returns little endian). + /** Reads a signed 16-bit integer from buf at the specified offset with the + * specified endian format (readInt16BE() returns big endian, readInt16LE() + * returns little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. * - * Integers read from a Buffer are interpreted as two's complement signed values. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 2 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readInt16LE(offset[, noAssert]) }}} + * Integers read from a Buffer are interpreted as two's complement signed + * values. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 2 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readInt16LE(offset[, noAssert])}}} */ def readInt16LE(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads a signed 32-bit integer from buf at the specified offset with the specified endian format - * (readInt32BE() returns big endian, readInt32LE() returns little endian). + /** Reads a signed 32-bit integer from buf at the specified offset with the + * specified endian format (readInt32BE() returns big endian, readInt32LE() + * returns little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. * - * Integers read from a Buffer are interpreted as two's complement signed values. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readInt32BE(offset[, noAssert]) }}} + * Integers read from a Buffer are interpreted as two's complement signed + * values. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readInt32BE(offset[, noAssert])}}} */ def readInt32BE(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads a signed 32-bit integer from buf at the specified offset with the specified endian format - * (readInt32BE() returns big endian, readInt32LE() returns little endian). + /** Reads a signed 32-bit integer from buf at the specified offset with the + * specified endian format (readInt32BE() returns big endian, readInt32LE() + * returns little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. * - * Integers read from a Buffer are interpreted as two's complement signed values. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readInt32LE(offset[, noAssert]) }}} + * Integers read from a Buffer are interpreted as two's complement signed + * values. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readInt32LE(offset[, noAssert])}}} */ def readInt32LE(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads byteLength number of bytes from buf at the specified offset and interprets the result as a - * two's complement signed value. Supports up to 48 bits of accuracy. + /** Reads byteLength number of bytes from buf at the specified offset and + * interprets the result as a two's complement signed value. Supports up to + * 48 bits of accuracy. * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - byteLength - * @param byteLength How many bytes to read. Must satisfy: 0 < byteLength <= 6 - * @param noAssert Skip offset and byteLength validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readIntBE(offset, byteLength[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - + * byteLength + * @param byteLength + * How many bytes to read. Must satisfy: 0 < byteLength <= 6 + * @param noAssert + * Skip offset and byteLength validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readIntBE(offset, byteLength[, noAssert])}}} */ def readIntBE( offset: Int, byteLength: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Reads byteLength number of bytes from buf at the specified offset and interprets the result as a - * two's complement signed value. Supports up to 48 bits of accuracy. + /** Reads byteLength number of bytes from buf at the specified offset and + * interprets the result as a two's complement signed value. Supports up to + * 48 bits of accuracy. * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - byteLength - * @param byteLength How many bytes to read. Must satisfy: 0 < byteLength <= 6 - * @param noAssert Skip offset and byteLength validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readIntLE(offset, byteLength[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - + * byteLength + * @param byteLength + * How many bytes to read. Must satisfy: 0 < byteLength <= 6 + * @param noAssert + * Skip offset and byteLength validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readIntLE(offset, byteLength[, noAssert])}}} */ def readIntLE( offset: Int, byteLength: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Reads an unsigned 8-bit integer from buf at the specified offset. - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 1 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readUInt8(offset[, noAssert]) }}} + /** Reads an unsigned 8-bit integer from buf at the specified offset. Setting + * noAssert to true allows offset to be beyond the end of buf, but the result + * should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 1 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readUInt8(offset[, noAssert])}}} */ def readUInt8(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads an unsigned 16-bit integer from buf at the specified offset with specified endian format - * (readUInt16BE() returns big endian, readUInt16LE() returns little endian). + /** Reads an unsigned 16-bit integer from buf at the specified offset with + * specified endian format (readUInt16BE() returns big endian, readUInt16LE() + * returns little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 2 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readUInt16BE(offset[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 2 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readUInt16BE(offset[, noAssert])}}} */ def readUInt16BE(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads an unsigned 16-bit integer from buf at the specified offset with specified endian format - * (readUInt16BE() returns big endian, readUInt16LE() returns little endian). + /** Reads an unsigned 16-bit integer from buf at the specified offset with + * specified endian format (readUInt16BE() returns big endian, readUInt16LE() + * returns little endian). * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 2 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readUInt16LE(offset[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 2 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readUInt16LE(offset[, noAssert])}}} */ def readUInt16LE(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads an unsigned 32-bit integer from buf at the specified offset with specified endian format - * (readUInt32BE() returns big endian, readUInt32LE() returns little endian). - * * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readUInt32BE(offset[, noAssert]) }}} + /** Reads an unsigned 32-bit integer from buf at the specified offset with + * specified endian format (readUInt32BE() returns big endian, readUInt32LE() + * returns little endian). * Setting noAssert to true allows offset to be + * beyond the end of buf, but the result should be considered undefined + * behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readUInt32BE(offset[, noAssert])}}} */ def readUInt32BE(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads an unsigned 32-bit integer from buf at the specified offset with specified endian format - * (readUInt32BE() returns big endian, readUInt32LE() returns little endian). - * * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip offset validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readUInt32LE(offset[, noAssert]) }}} + /** Reads an unsigned 32-bit integer from buf at the specified offset with + * specified endian format (readUInt32BE() returns big endian, readUInt32LE() + * returns little endian). * Setting noAssert to true allows offset to be + * beyond the end of buf, but the result should be considered undefined + * behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip offset validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readUInt32LE(offset[, noAssert])}}} */ def readUInt32LE(offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Reads byteLength number of bytes from buf at the specified offset and interprets the result - * as an unsigned integer. Supports up to 48 bits of accuracy. + /** Reads byteLength number of bytes from buf at the specified offset and + * interprets the result as an unsigned integer. Supports up to 48 bits of + * accuracy. * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - byteLength - * @param byteLength How many bytes to read. Must satisfy: 0 < byteLength <= 6 - * @param noAssert Skip offset and byteLength validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readUIntBE(offset, byteLength[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - + * byteLength + * @param byteLength + * How many bytes to read. Must satisfy: 0 < byteLength <= 6 + * @param noAssert + * Skip offset and byteLength validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readUIntBE(offset, byteLength[, noAssert])}}} */ def readUIntBE( offset: Int, byteLength: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Reads byteLength number of bytes from buf at the specified offset and interprets the result - * as an unsigned integer. Supports up to 48 bits of accuracy. + /** Reads byteLength number of bytes from buf at the specified offset and + * interprets the result as an unsigned integer. Supports up to 48 bits of + * accuracy. * - * Setting noAssert to true allows offset to be beyond the end of buf, but the result should be - * considered undefined behavior. - * @param offset Where to start reading. Must satisfy: 0 <= offset <= buf.length - byteLength - * @param byteLength How many bytes to read. Must satisfy: 0 < byteLength <= 6 - * @param noAssert Skip offset and byteLength validation? Default: false - * @return the [[Int integer]] value - * @example {{{ buf.readUIntLE(offset, byteLength[, noAssert]) }}} + * Setting noAssert to true allows offset to be beyond the end of buf, but + * the result should be considered undefined behavior. + * @param offset + * Where to start reading. Must satisfy: 0 <= offset <= buf.length - + * byteLength + * @param byteLength + * How many bytes to read. Must satisfy: 0 < byteLength <= 6 + * @param noAssert + * Skip offset and byteLength validation? Default: false + * @return + * the [[Int integer]] value + * @example + * {{{buf.readUIntLE(offset, byteLength[, noAssert])}}} */ def readUIntLE( offset: Int, byteLength: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Returns a new Buffer that references the same memory as the original, but offset and cropped by - * the start and end indices. + /** Returns a new Buffer that references the same memory as the original, but + * offset and cropped by the start and end indices. * - * Note that modifying the new Buffer slice will modify the memory in the original Buffer because the - * allocated memory of the two objects overlap. - * @param start Where the new Buffer will start. Default: 0 - * @param end Where the new Buffer will end (not inclusive). Default: buf.length - * @return a [[Buffer]] - * @example {{{ buf.slice([start[, end]]) }}} + * Note that modifying the new Buffer slice will modify the memory in the + * original Buffer because the allocated memory of the two objects overlap. + * @param start + * Where the new Buffer will start. Default: 0 + * @param end + * Where the new Buffer will end (not inclusive). Default: buf.length + * @return + * a [[Buffer]] + * @example + * {{{buf.slice([start[, end]])}}} */ def slice(start: Int = js.native, end: Int = js.native): this.type = js.native - /** Interprets buf as an array of unsigned 16-bit integers and swaps the byte-order in-place. - * Throws a RangeError if buf.length is not a multiple of 2. - * @return A reference to buf - * @example buf.swap16() + /** Interprets buf as an array of unsigned 16-bit integers and swaps the + * byte-order in-place. Throws a RangeError if buf.length is not a multiple + * of 2. + * @return + * A reference to buf + * @example + * buf.swap16() */ def swap16(): this.type = js.native - /** Interprets buf as an array of unsigned 32-bit integers and swaps the byte-order in-place. - * Throws a RangeError if buf.length is not a multiple of 4. - * @return A reference to buf - * @example buf.swap32() + /** Interprets buf as an array of unsigned 32-bit integers and swaps the + * byte-order in-place. Throws a RangeError if buf.length is not a multiple + * of 4. + * @return + * A reference to buf + * @example + * buf.swap32() */ def swap32(): this.type = js.native - /** Interprets buf as an array of unsigned 64-bit numbers and swaps the byte-order in-place. - * Throws a RangeError if buf.length is not a multiple of 8. - * @return A reference to buf - * @example buf.swap64() + /** Interprets buf as an array of unsigned 64-bit numbers and swaps the + * byte-order in-place. Throws a RangeError if buf.length is not a multiple + * of 8. + * @return + * A reference to buf + * @example + * buf.swap64() */ def swap64(): this.type = js.native - /** Returns a JSON representation of buf. - * JSON.stringify() implicitly calls this function when stringifying a Buffer instance. - * @return a JSON representation of buf. - * @example buf.toJSON() + /** Returns a JSON representation of buf. JSON.stringify() implicitly calls + * this function when stringifying a Buffer instance. + * @return + * a JSON representation of buf. + * @example + * buf.toJSON() */ def toJSON(): String = js.native - /** Decodes buf to a string according to the specified character encoding in encoding. start and end may be passed - * to decode only a subset of buf. - * @param encoding The character encoding to decode to. Default: 'utf8' - * @param start The byte offset to start decoding at. Default: 0 - * @param end The byte offset to stop decoding at (not inclusive). Default: buf.length - * @return a string according to the specified character encoding in encoding. - * @example {{{ buf.toString([encoding[, start[, end]]]) }}} + /** Decodes buf to a string according to the specified character encoding in + * encoding. start and end may be passed to decode only a subset of buf. + * @param encoding + * The character encoding to decode to. Default: 'utf8' + * @param start + * The byte offset to start decoding at. Default: 0 + * @param end + * The byte offset to stop decoding at (not inclusive). Default: buf.length + * @return + * a string according to the specified character encoding in encoding. + * @example + * {{{buf.toString([encoding[, start[, end]]])}}} */ def toString( encoding: String = js.native, start: Int = js.native, - end: Int = js.native): String = js.native + end: Int = js.native + ): String = js.native - /** Re-encodes the given Buffer instance from one character encoding to another. Returns a new Buffer instance. - * Throws if the fromEnc or toEnc specify invalid character encodings or if conversion from fromEnc to toEnc + /** Re-encodes the given Buffer instance from one character encoding to + * another. Returns a new Buffer instance. Throws if the fromEnc or toEnc + * specify invalid character encodings or if conversion from fromEnc to toEnc * is not permitted. - * @param source A Buffer instance - * @param fromEnc The current encoding - * @param toEnc To target encoding - * @return a new [[Buffer]] + * @param source + * A Buffer instance + * @param fromEnc + * The current encoding + * @param toEnc + * To target encoding + * @return + * a new [[Buffer]] */ def transcode(source: Buffer, fromEnc: String, toEnc: String): Buffer = js.native - /** Creates and returns an iterator for buf values (bytes). This function is called automatically when a [[Buffer]] - * is used in a for..of statement. - * @return an iterator for buf values (bytes) - * @example buf.values() + /** Creates and returns an iterator for buf values (bytes). This function is + * called automatically when a [[Buffer]] is used in a for..of statement. + * @return + * an iterator for buf values (bytes) + * @example + * buf.values() */ def values(): js.Iterator[Int] = js.native - /** Writes string to buf at offset according to the character encoding in encoding. The length parameter is - * the number of bytes to write. If buf did not contain enough space to fit the entire string, only a partial - * amount of string will be written. However, partially encoded characters will not be written. - * @param string String to be written to buf - * @param offset Where to start writing string. Default: 0 - * @param length How many bytes to write. Default: buf.length - offset - * @param encoding The character encoding of string. Default: 'utf8' - * @return the Number of bytes written - * @example {{{ buf.write(string[, offset[, length]][, encoding]) }}} + /** Writes string to buf at offset according to the character encoding in + * encoding. The length parameter is the number of bytes to write. If buf did + * not contain enough space to fit the entire string, only a partial amount + * of string will be written. However, partially encoded characters will not + * be written. + * @param string + * String to be written to buf + * @param offset + * Where to start writing string. Default: 0 + * @param length + * How many bytes to write. Default: buf.length - offset + * @param encoding + * The character encoding of string. Default: 'utf8' + * @return + * the Number of bytes written + * @example + * {{{buf.write(string[, offset[, length]][, encoding])}}} */ def write( string: String, offset: Int = js.native, length: Int = js.native, - encoding: String = js.native): Int = + encoding: String = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeDoubleBE() writes big endian, - * writeDoubleLE() writes little endian). value should be a valid 64-bit double. Behavior is undefined when value - * is anything other than a 64-bit double. + /** Writes value to buf at the specified offset with specified endian format + * (writeDoubleBE() writes big endian, writeDoubleLE() writes little endian). + * value should be a valid 64-bit double. Behavior is undefined when value is + * anything other than a 64-bit double. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result should - * be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 8 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeDoubleBE(value, offset[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 8 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeDoubleBE(value, offset[, noAssert])}}} */ def writeDoubleBE( value: Double, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeDoubleBE() writes big endian, - * writeDoubleLE() writes little endian). value should be a valid 64-bit double. Behavior is undefined when value - * is anything other than a 64-bit double. + /** Writes value to buf at the specified offset with specified endian format + * (writeDoubleBE() writes big endian, writeDoubleLE() writes little endian). + * value should be a valid 64-bit double. Behavior is undefined when value is + * anything other than a 64-bit double. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 8 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeDoubleLE(value, offset[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 8 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeDoubleLE(value, offset[, noAssert])}}} */ def writeDoubleLE( value: Double, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeFloatBE() writes big endian, - * writeFloatLE() writes little endian). value should be a valid 32-bit float. Behavior is undefined when value - * is anything other than a 32-bit float. + /** Writes value to buf at the specified offset with specified endian format + * (writeFloatBE() writes big endian, writeFloatLE() writes little endian). + * value should be a valid 32-bit float. Behavior is undefined when value is + * anything other than a 32-bit float. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeFloatBE(value, offset[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeFloatBE(value, offset[, noAssert])}}} */ def writeFloatBE( value: Float, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeFloatBE() writes big endian, - * writeFloatLE() writes little endian). value should be a valid 32-bit float. Behavior is undefined when value - * is anything other than a 32-bit float. + /** Writes value to buf at the specified offset with specified endian format + * (writeFloatBE() writes big endian, writeFloatLE() writes little endian). + * value should be a valid 32-bit float. Behavior is undefined when value is + * anything other than a 32-bit float. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeFloatLE(value, offset[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeFloatLE(value, offset[, noAssert])}}} */ def writeFloatLE( value: Float, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset. value should be a valid signed 8-bit integer. Behavior is - * undefined when value is anything other than a signed 8-bit integer. + /** Writes value to buf at the specified offset. value should be a valid + * signed 8-bit integer. Behavior is undefined when value is anything other + * than a signed 8-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. * * value is interpreted and written as a two's complement signed integer. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 1 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeInt8(value, offset[, noAssert]) }}} + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 1 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeInt8(value, offset[, noAssert])}}} */ def writeInt8(value: Int, offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeInt16BE() writes big endian, - * writeInt16LE() writes little endian). value should be a valid signed 16-bit integer. Behavior is undefined - * when value is anything other than a signed 16-bit integer. + /** Writes value to buf at the specified offset with specified endian format + * (writeInt16BE() writes big endian, writeInt16LE() writes little endian). + * value should be a valid signed 16-bit integer. Behavior is undefined when + * value is anything other than a signed 16-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. * * value is interpreted and written as a two's complement signed integer. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 2 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeInt16BE(value, offset[, noAssert]) }}} + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 2 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeInt16BE(value, offset[, noAssert])}}} */ def writeInt16BE( value: Int, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeInt16BE() writes big endian, - * writeInt16LE() writes little endian). value should be a valid signed 16-bit integer. Behavior is undefined - * when value is anything other than a signed 16-bit integer. + /** Writes value to buf at the specified offset with specified endian format + * (writeInt16BE() writes big endian, writeInt16LE() writes little endian). + * value should be a valid signed 16-bit integer. Behavior is undefined when + * value is anything other than a signed 16-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. * * value is interpreted and written as a two's complement signed integer. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 2 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeInt16BE(value, offset[, noAssert]) }}} + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 2 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeInt16BE(value, offset[, noAssert])}}} */ def writeInt16LE( value: Int, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeInt32BE() writes big endian, - * writeInt32LE() writes little endian). value should be a valid signed 32-bit integer. Behavior is undefined - * when value is anything other than a signed 32-bit integer. + /** Writes value to buf at the specified offset with specified endian format + * (writeInt32BE() writes big endian, writeInt32LE() writes little endian). + * value should be a valid signed 32-bit integer. Behavior is undefined when + * value is anything other than a signed 32-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. * * value is interpreted and written as a two's complement signed integer. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeInt32BE(value, offset[, noAssert]) }}} + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeInt32BE(value, offset[, noAssert])}}} */ def writeInt32BE( value: Int, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeInt32BE() writes big endian, - * writeInt32LE() writes little endian). value should be a valid signed 32-bit integer. Behavior is undefined - * when value is anything other than a signed 32-bit integer. + /** Writes value to buf at the specified offset with specified endian format + * (writeInt32BE() writes big endian, writeInt32LE() writes little endian). + * value should be a valid signed 32-bit integer. Behavior is undefined when + * value is anything other than a signed 32-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. * * value is interpreted and written as a two's complement signed integer. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeInt32BE(value, offset[, noAssert]) }}} + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeInt32BE(value, offset[, noAssert])}}} */ def writeInt32LE( value: Int, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes byteLength bytes of value to buf at the specified offset. Supports up to 48 bits of accuracy. - * Behavior is undefined when value is anything other than a signed integer. + /** Writes byteLength bytes of value to buf at the specified offset. Supports + * up to 48 bits of accuracy. Behavior is undefined when value is anything + * other than a signed integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the - * result should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - byteLength - * @param byteLength How many bytes to write. Must satisfy: 0 < byteLength <= 6 - * @param noAssert Skip value, offset, and byteLength validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeIntBE(value, offset, byteLength[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - + * byteLength + * @param byteLength + * How many bytes to write. Must satisfy: 0 < byteLength <= 6 + * @param noAssert + * Skip value, offset, and byteLength validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeIntBE(value, offset, byteLength[, noAssert])}}} */ def writeIntBE( value: Int, offset: Int, byteLength: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes byteLength bytes of value to buf at the specified offset. Supports up to 48 bits of accuracy. - * Behavior is undefined when value is anything other than a signed integer. + /** Writes byteLength bytes of value to buf at the specified offset. Supports + * up to 48 bits of accuracy. Behavior is undefined when value is anything + * other than a signed integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the - * result should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - byteLength - * @param byteLength How many bytes to write. Must satisfy: 0 < byteLength <= 6 - * @param noAssert Skip value, offset, and byteLength validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeIntLE(value, offset, byteLength[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - + * byteLength + * @param byteLength + * How many bytes to write. Must satisfy: 0 < byteLength <= 6 + * @param noAssert + * Skip value, offset, and byteLength validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeIntLE(value, offset, byteLength[, noAssert])}}} */ def writeIntLE( value: Int, offset: Int, byteLength: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset. value should be a valid unsigned 8-bit integer. Behavior - * is undefined when value is anything other than an unsigned 8-bit integer. + /** Writes value to buf at the specified offset. value should be a valid + * unsigned 8-bit integer. Behavior is undefined when value is anything other + * than an unsigned 8-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 1 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeUInt8(value, offset[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 1 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeUInt8(value, offset[, noAssert])}}} */ def writeUInt8(value: Int, offset: Int, noAssert: Boolean = js.native): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeUInt16BE() writes big endian, - * writeUInt16LE() writes little endian). value should be a valid unsigned 16-bit integer. Behavior is undefined + /** Writes value to buf at the specified offset with specified endian format + * (writeUInt16BE() writes big endian, writeUInt16LE() writes little endian). + * value should be a valid unsigned 16-bit integer. Behavior is undefined * when value is anything other than an unsigned 16-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Number to be written to buf - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeUInt16BE(value, offset[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Number to be written to buf + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeUInt16BE(value, offset[, noAssert])}}} */ def writeUInt16BE( value: Int, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeUInt16BE() writes big endian, - * writeUInt16LE() writes little endian). value should be a valid unsigned 16-bit integer. Behavior is undefined + /** Writes value to buf at the specified offset with specified endian format + * (writeUInt16BE() writes big endian, writeUInt16LE() writes little endian). + * value should be a valid unsigned 16-bit integer. Behavior is undefined * when value is anything other than an unsigned 16-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Number to be written to buf - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeUInt16BE(value, offset[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Number to be written to buf + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeUInt16BE(value, offset[, noAssert])}}} */ def writeUInt16LE( value: Int, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeUInt32BE() writes big endian, - * writeUInt32LE() writes little endian). value should be a valid unsigned 32-bit integer. Behavior is undefined + /** Writes value to buf at the specified offset with specified endian format + * (writeUInt32BE() writes big endian, writeUInt32LE() writes little endian). + * value should be a valid unsigned 32-bit integer. Behavior is undefined * when value is anything other than an unsigned 32-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeUInt32BE(value, offset[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeUInt32BE(value, offset[, noAssert])}}} */ def writeUInt32BE( value: Int, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes value to buf at the specified offset with specified endian format (writeUInt32BE() writes big endian, - * writeUInt32LE() writes little endian). value should be a valid unsigned 32-bit integer. Behavior is undefined + /** Writes value to buf at the specified offset with specified endian format + * (writeUInt32BE() writes big endian, writeUInt32LE() writes little endian). + * value should be a valid unsigned 32-bit integer. Behavior is undefined * when value is anything other than an unsigned 32-bit integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the result - * should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 - * @param noAssert Skip value and offset validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeUInt32LE(value, offset[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - 4 + * @param noAssert + * Skip value and offset validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeUInt32LE(value, offset[, noAssert])}}} */ def writeUInt32LE( value: Int, offset: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes byteLength bytes of value to buf at the specified offset. Supports up to 48 bits of accuracy. - * Behavior is undefined when value is anything other than an unsigned integer. + /** Writes byteLength bytes of value to buf at the specified offset. Supports + * up to 48 bits of accuracy. Behavior is undefined when value is anything + * other than an unsigned integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the - * result should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - byteLength - * @param byteLength How many bytes to write. Must satisfy: 0 < byteLength <= 6 - * @param noAssert Skip value, offset, and byteLength validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeUIntBE(value, offset, byteLength[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - + * byteLength + * @param byteLength + * How many bytes to write. Must satisfy: 0 < byteLength <= 6 + * @param noAssert + * Skip value, offset, and byteLength validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeUIntBE(value, offset, byteLength[, noAssert])}}} */ def writeUIntBE( value: Int, offset: Int, byteLength: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native - /** Writes byteLength bytes of value to buf at the specified offset. Supports up to 48 bits of accuracy. - * Behavior is undefined when value is anything other than an unsigned integer. + /** Writes byteLength bytes of value to buf at the specified offset. Supports + * up to 48 bits of accuracy. Behavior is undefined when value is anything + * other than an unsigned integer. * - * Setting noAssert to true allows the encoded form of value to extend beyond the end of buf, but the - * result should be considered undefined behavior. - * @param value Number to be written to buf - * @param offset Where to start writing. Must satisfy: 0 <= offset <= buf.length - byteLength - * @param byteLength How many bytes to write. Must satisfy: 0 < byteLength <= 6 - * @param noAssert Skip value, offset, and byteLength validation? Default: false - * @return the offset plus the number of bytes written - * @example {{{ buf.writeUIntLE(value, offset, byteLength[, noAssert]) }}} + * Setting noAssert to true allows the encoded form of value to extend beyond + * the end of buf, but the result should be considered undefined behavior. + * @param value + * Number to be written to buf + * @param offset + * Where to start writing. Must satisfy: 0 <= offset <= buf.length - + * byteLength + * @param byteLength + * How many bytes to write. Must satisfy: 0 < byteLength <= 6 + * @param noAssert + * Skip value, offset, and byteLength validation? Default: false + * @return + * the offset plus the number of bytes written + * @example + * {{{buf.writeUIntLE(value, offset, byteLength[, noAssert])}}} */ def writeUIntLE( value: Int, offset: Int, byteLength: Int, - noAssert: Boolean = js.native): Int = js.native + noAssert: Boolean = js.native + ): Int = js.native } @@ -873,21 +1232,24 @@ object Buffer extends js.Object { // Properties ///////////////////////////////////////////////////////////////////////////////// - /** Returns the maximum number of bytes that will be returned when buf.inspect() is called. - * This can be overridden by user modules. See util.inspect() for more details on buf.inspect() behavior. + /** Returns the maximum number of bytes that will be returned when + * buf.inspect() is called. This can be overridden by user modules. See + * util.inspect() for more details on buf.inspect() behavior. * - * Note that this is a property on the buffer module returned by require('buffer'), not on the - * Buffer global or a Buffer instance. + * Note that this is a property on the buffer module returned by + * require('buffer'), not on the Buffer global or a Buffer instance. */ val INSPECT_MAX_BYTES: Int = js.native - /** On 32-bit architectures, this value is (2^30)-1 (~1GB). On 64-bit architectures, this value is (2^31)-1 (~2GB).F - * Note that this is a property on the buffer module returned by require('buffer'), not on the Buffer global or a Buffer instance. + /** On 32-bit architectures, this value is (2^30)-1 (~1GB). On 64-bit + * architectures, this value is (2^31)-1 (~2GB).F Note that this is a + * property on the buffer module returned by require('buffer'), not on the + * Buffer global or a Buffer instance. */ val kMaxLength: Int = js.native - /** This is the number of bytes used to determine the size of pre-allocated, internal Buffer instances used for pooling. - * This value may be modified. + /** This is the number of bytes used to determine the size of pre-allocated, + * internal Buffer instances used for pooling. This value may be modified. */ var poolSize: Int = js.native @@ -895,132 +1257,186 @@ object Buffer extends js.Object { // Methods ///////////////////////////////////////////////////////////////////////////////// - /** Allocates a new Buffer of size bytes. If fill is undefined, the Buffer will be zero-filled. - * @param size The desired length of the new Buffer - * @param fill A value to pre-fill the new Buffer with. Default: 0 - * @param encoding If fill is a string, this is its encoding. Default: 'utf8' - * @return a new [[Buffer]] - * @example {{{ Buffer.alloc(size[, fill[, encoding]]) }}} + /** Allocates a new Buffer of size bytes. If fill is undefined, the Buffer + * will be zero-filled. + * @param size + * The desired length of the new Buffer + * @param fill + * A value to pre-fill the new Buffer with. Default: 0 + * @param encoding + * If fill is a string, this is its encoding. Default: 'utf8' + * @return + * a new [[Buffer]] + * @example + * {{{Buffer.alloc(size[, fill[, encoding]])}}} */ def alloc( size: Int, fill: Buffer | Int | String = js.native, - encoding: String = js.native): Buffer = js.native + encoding: String = js.native + ): Buffer = js.native - /** Calling Buffer.alloc(size) can be significantly slower than the alternative Buffer.allocUnsafe(size) but ensures - * that the newly created Buffer instance contents will never contain sensitive data. - * @param size the allocated size. - * @example Buffer.allocUnsafe(size) + /** Calling Buffer.alloc(size) can be significantly slower than the + * alternative Buffer.allocUnsafe(size) but ensures that the newly created + * Buffer instance contents will never contain sensitive data. + * @param size + * the allocated size. + * @example + * Buffer.allocUnsafe(size) */ def allocUnsafe(size: Int): Buffer = js.native - /** Allocates a new non-zero-filled and non-pooled Buffer of size bytes. The size must be less than or equal to the - * value of require('buffer').kMaxLength (on 64-bit architectures, kMaxLength is {{{ (2^31)-1). }}} Otherwise, a RangeError - * is thrown. A zero-length Buffer will be created if a size less than or equal to 0 is specified. + /** Allocates a new non-zero-filled and non-pooled Buffer of size bytes. The + * size must be less than or equal to the value of + * require('buffer').kMaxLength (on 64-bit architectures, kMaxLength is + * {{{(2^31)-1).}}} Otherwise, a RangeError is thrown. A zero-length Buffer + * will be created if a size less than or equal to 0 is specified. * - * The underlying memory for Buffer instances created in this way is not initialized. The contents of the newly - * created Buffer are unknown and may contain sensitive data. Use buf.fill(0) to initialize such Buffer instances to zeroes. + * The underlying memory for Buffer instances created in this way is not + * initialized. The contents of the newly created Buffer are unknown and may + * contain sensitive data. Use buf.fill(0) to initialize such Buffer + * instances to zeroes. * - * When using Buffer.allocUnsafe() to allocate new Buffer instances, allocations under 4KB are, by default, sliced - * from a single pre-allocated Buffer. This allows applications to avoid the garbage collection overhead of creating - * many individually allocated Buffers. This approach improves both performance and memory usage by eliminating the - * need to track and cleanup as many Persistent objects. + * When using Buffer.allocUnsafe() to allocate new Buffer instances, + * allocations under 4KB are, by default, sliced from a single pre-allocated + * Buffer. This allows applications to avoid the garbage collection overhead + * of creating many individually allocated Buffers. This approach improves + * both performance and memory usage by eliminating the need to track and + * cleanup as many Persistent objects. * - * However, in the case where a developer may need to retain a small chunk of memory from a pool for an indeterminate - * amount of time, it may be appropriate to create an un-pooled Buffer instance using Buffer.allocUnsafeSlow() then - * copy out the relevant bits. - * @param size the allocated size. - * @example Buffer.allocUnsafeSlow(size) + * However, in the case where a developer may need to retain a small chunk of + * memory from a pool for an indeterminate amount of time, it may be + * appropriate to create an un-pooled Buffer instance using + * Buffer.allocUnsafeSlow() then copy out the relevant bits. + * @param size + * the allocated size. + * @example + * Buffer.allocUnsafeSlow(size) */ def allocUnsafeSlow(size: Int): Buffer = js.native - /** Returns the actual byte length of a string. This is not the same as String.prototype.length since that returns - * the number of characters in a string. - * @param string | | | | - * @param encoding the optional encoding (default "utf8") - * @example Buffer.byteLength(string[, encoding]) + /** Returns the actual byte length of a string. This is not the same as + * String.prototype.length since that returns the number of characters in a + * string. + * @param string + * | | | | + * @param encoding + * the optional encoding (default "utf8") + * @example + * Buffer.byteLength(string[, encoding]) */ def byteLength(string: js.Any, encoding: String = "utf8"): Int = js.native - /** Compares buf1 to buf2 typically for the purpose of sorting arrays of Buffers. - * This is equivalent is calling buf1.compare(buf2). + /** Compares buf1 to buf2 typically for the purpose of sorting arrays of + * Buffers. This is equivalent is calling buf1.compare(buf2). */ def compare(buf1: Buffer, buf2: Buffer): Int = js.native - /** Returns a new Buffer which is the result of concatenating all the Buffers in the list together. - * If the list has no items, or if the totalLength is 0, then a new zero-length Buffer is returned. - * If totalLength is not provided, it is calculated from the Buffers in the list. This, however, adds an additional - * loop to the function, so it is faster to provide the length explicitly. - * @param list the list of Buffer objects to concat - * @param totalLength the optional total length - * @example Buffer.concat(list[, totalLength]) + /** Returns a new Buffer which is the result of concatenating all the Buffers + * in the list together. If the list has no items, or if the totalLength is + * 0, then a new zero-length Buffer is returned. If totalLength is not + * provided, it is calculated from the Buffers in the list. This, however, + * adds an additional loop to the function, so it is faster to provide the + * length explicitly. + * @param list + * the list of Buffer objects to concat + * @param totalLength + * the optional total length + * @example + * Buffer.concat(list[, totalLength]) */ def concat(list: js.Array[Buffer], totalLength: Int): Buffer = js.native - /** Returns a new Buffer which is the result of concatenating all the Buffers in the list together. - * If the list has no items, or if the totalLength is 0, then a new zero-length Buffer is returned. - * If totalLength is not provided, it is calculated from the Buffers in the list. This, however, adds an additional - * loop to the function, so it is faster to provide the length explicitly. - * @param list the list of Buffer objects to concat - * @example Buffer.concat(list[, totalLength]) + /** Returns a new Buffer which is the result of concatenating all the Buffers + * in the list together. If the list has no items, or if the totalLength is + * 0, then a new zero-length Buffer is returned. If totalLength is not + * provided, it is calculated from the Buffers in the list. This, however, + * adds an additional loop to the function, so it is faster to provide the + * length explicitly. + * @param list + * the list of Buffer objects to concat + * @example + * Buffer.concat(list[, totalLength]) */ def concat(list: js.Array[Buffer]): Buffer = js.native - /** When passed a reference to the .buffer property of a TypedArray instance, the newly created Buffer - * will share the same allocated memory as the TypedArray. - * @example {{{ Buffer.from(arrayBuffer[, byteOffset[, length]]) }}} + /** When passed a reference to the .buffer property of a TypedArray instance, + * the newly created Buffer will share the same allocated memory as the + * TypedArray. + * @example + * {{{Buffer.from(arrayBuffer[, byteOffset[, length]])}}} */ def from(arrayBuffer: ArrayBuffer, byteOffset: Int, length: Int): Buffer = js.native - /** When passed a reference to the .buffer property of a TypedArray instance, the newly created Buffer - * will share the same allocated memory as the TypedArray. - * @example {{{ Buffer.from(arrayBuffer[, byteOffset[, length]]) }}} + /** When passed a reference to the .buffer property of a TypedArray instance, + * the newly created Buffer will share the same allocated memory as the + * TypedArray. + * @example + * {{{Buffer.from(arrayBuffer[, byteOffset[, length]])}}} */ def from(arrayBuffer: ArrayBuffer, byteOffset: Int): Buffer = js.native - /** When passed a reference to the .buffer property of a TypedArray instance, the newly created Buffer - * will share the same allocated memory as the TypedArray. - * @example {{{ Buffer.from(arrayBuffer[, byteOffset[, length]]) }}} + /** When passed a reference to the .buffer property of a TypedArray instance, + * the newly created Buffer will share the same allocated memory as the + * TypedArray. + * @example + * {{{Buffer.from(arrayBuffer[, byteOffset[, length]])}}} */ def from(arrayBuffer: ArrayBuffer): Buffer = js.native /** Allocates a new Buffer using an array of octets. - * @example Buffer.from(array) + * @example + * Buffer.from(array) */ def from(array: js.Array[Int]): Buffer = js.native - /** Creates a new Buffer containing the given JavaScript string str. If provided, the encoding parameter identifies - * the strings character encoding. - * @param str the source string - * @param encoding the given encoding - * @return a new Buffer + /** Creates a new Buffer containing the given JavaScript string str. If + * provided, the encoding parameter identifies the strings character + * encoding. + * @param str + * the source string + * @param encoding + * the given encoding + * @return + * a new Buffer */ def from(str: String, encoding: String = js.native): Buffer = js.native /** Returns true if obj is a Buffer, false otherwise. - * @param obj the given object - * @return true if obj is a Buffer, false otherwise. + * @param obj + * the given object + * @return + * true if obj is a Buffer, false otherwise. */ def isBuffer(obj: js.Any): Boolean = js.native - /** Returns true if encoding contains a supported character encoding, or false otherwise. - * @param encoding A character encoding name to check - * @return true if encoding contains a supported character encoding, or false otherwise. + /** Returns true if encoding contains a supported character encoding, or false + * otherwise. + * @param encoding + * A character encoding name to check + * @return + * true if encoding contains a supported character encoding, or false + * otherwise. */ def isEncoding(encoding: String): Boolean = js.native - /** Re-encodes the given Buffer instance from one character encoding to another. Returns a new Buffer instance. + /** Re-encodes the given Buffer instance from one character encoding to + * another. Returns a new Buffer instance. * - * Throws if the fromEnc or toEnc specify invalid character encodings or if conversion from fromEnc to toEnc - * is not permitted. + * Throws if the fromEnc or toEnc specify invalid character encodings or if + * conversion from fromEnc to toEnc is not permitted. * - * The transcoding process will use substitution characters if a given byte sequence cannot be adequately - * represented in the target encoding. - * @param source A Buffer instance - * @param fromEnc The current encoding - * @param toEnc To target encoding - * @return a new Buffer instance. + * The transcoding process will use substitution characters if a given byte + * sequence cannot be adequately represented in the target encoding. + * @param source + * A Buffer instance + * @param fromEnc + * The current encoding + * @param toEnc + * To target encoding + * @return + * a new Buffer instance. */ def transcode(source: Buffer, fromEnc: String, toEnc: String): Buffer = js.native diff --git a/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/PBKDF2.scala b/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/PBKDF2.scala index 756b29e9e1..475e5ab679 100644 --- a/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/PBKDF2.scala +++ b/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/PBKDF2.scala @@ -17,5 +17,6 @@ object PBKDF2 extends js.Object { pass: Buffer, salt: Buffer, iter: Int, - len: Int): Buffer = js.native + len: Int + ): Buffer = js.native } diff --git a/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/SECP256k1.scala b/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/SECP256k1.scala index fda20d7652..fe15f0c688 100644 --- a/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/SECP256k1.scala +++ b/crypto/.js/src/main/scala/org/bitcoins/crypto/facade/SECP256k1.scala @@ -44,13 +44,15 @@ object SECP256k1 extends js.Object { msg: Buffer, sig: Buffer, param: Byte, - compress: Boolean): Buffer = js.native + compress: Boolean + ): Buffer = js.native def recoverDER( msg: Buffer, sig: Buffer, param: Byte, - compress: Boolean): Buffer = js.native + compress: Boolean + ): Buffer = js.native val curve: js.Dynamic = js.native } diff --git a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleCryptoParams.scala b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleCryptoParams.scala index 1ad703a516..b907b82f4f 100644 --- a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleCryptoParams.scala +++ b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleCryptoParams.scala @@ -9,8 +9,10 @@ object BouncyCastleCryptoParams { /** The curve that bitcoin uses. */ val curve = - new ECDomainParameters(params.getCurve, - params.getG, - params.getN, - params.getH) + new ECDomainParameters( + params.getCurve, + params.getG, + params.getN, + params.getH + ) } diff --git a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleUtil.scala b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleUtil.scala index daeba605a2..360d9ca508 100644 --- a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleUtil.scala +++ b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncyCastleUtil.scala @@ -36,7 +36,8 @@ object BouncyCastleUtil { private[crypto] def decodePubKey( point: ECPoint, - isCompressed: Boolean = true): ECPublicKey = { + isCompressed: Boolean = true + ): ECPublicKey = { val bytes = point.getEncoded(isCompressed) ECPublicKey.fromBytes(ByteVector(bytes)) } @@ -76,77 +77,94 @@ object BouncyCastleUtil { def sign( dataToSign: ByteVector, - privateKey: ECPrivateKey): ECDigitalSignature = { + privateKey: ECPrivateKey + ): ECDigitalSignature = { val signer: ECDSASigner = new ECDSASigner( - new HMacDSAKCalculator(new SHA256Digest())) + new HMacDSAKCalculator(new SHA256Digest()) + ) val privKey: ECPrivateKeyParameters = - new ECPrivateKeyParameters(getBigInteger(privateKey.bytes), - BouncyCastleCryptoParams.curve) + new ECPrivateKeyParameters( + getBigInteger(privateKey.bytes), + BouncyCastleCryptoParams.curve + ) signer.init(true, privKey) val components: Array[BigInteger] = signer.generateSignature(dataToSign.toArray) val (r, s) = (components(0), components(1)) val signature = ECDigitalSignature(r, s) - //make sure the signature follows BIP62's low-s value - //https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures - //bitcoinj implementation - //https://github.com/bitcoinj/bitcoinj/blob/1e66b9a8e38d9ad425507bf5f34d64c5d3d23bb8/core/src/main/java/org/bitcoinj/core/ECKey.java#L551 + // make sure the signature follows BIP62's low-s value + // https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures + // bitcoinj implementation + // https://github.com/bitcoinj/bitcoinj/blob/1e66b9a8e38d9ad425507bf5f34d64c5d3d23bb8/core/src/main/java/org/bitcoinj/core/ECKey.java#L551 val signatureLowS = DERSignatureUtil.lowS(signature) require( signatureLowS.isDEREncoded, - "We must create DER encoded signatures when signing a piece of data, got: " + signatureLowS) + "We must create DER encoded signatures when signing a piece of data, got: " + signatureLowS + ) signatureLowS } /** Create an ECDSA signature adding specified entropy. * - * This can be used to include your own entropy to nonce generation - * in addition to the message and private key, while still doing so deterministically. + * This can be used to include your own entropy to nonce generation in + * addition to the message and private key, while still doing so + * deterministically. * * In particular, this is used when generating low R signatures. - * @see [[https://github.com/bitcoin/bitcoin/pull/13666/]] + * @see + * [[https://github.com/bitcoin/bitcoin/pull/13666/]] */ def signWithEntropy( dataToSign: ByteVector, privateKey: ECPrivateKey, - entropy: ByteVector): ECDigitalSignature = { + entropy: ByteVector + ): ECDigitalSignature = { val signer: ECDSASigner = new ECDSASigner( - new HMacDSAKCalculatorWithEntropy(new SHA256Digest(), entropy)) + new HMacDSAKCalculatorWithEntropy(new SHA256Digest(), entropy) + ) val privKey: ECPrivateKeyParameters = - new ECPrivateKeyParameters(getBigInteger(privateKey.bytes), - BouncyCastleCryptoParams.curve) + new ECPrivateKeyParameters( + getBigInteger(privateKey.bytes), + BouncyCastleCryptoParams.curve + ) signer.init(true, privKey) val components: Array[BigInteger] = signer.generateSignature(dataToSign.toArray) val (r, s) = (components(0), components(1)) val signature = ECDigitalSignature(r, s) - //make sure the signature follows BIP62's low-s value - //https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures - //bitcoinj implementation - //https://github.com/bitcoinj/bitcoinj/blob/1e66b9a8e38d9ad425507bf5f34d64c5d3d23bb8/core/src/main/java/org/bitcoinj/core/ECKey.java#L551 + // make sure the signature follows BIP62's low-s value + // https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures + // bitcoinj implementation + // https://github.com/bitcoinj/bitcoinj/blob/1e66b9a8e38d9ad425507bf5f34d64c5d3d23bb8/core/src/main/java/org/bitcoinj/core/ECKey.java#L551 val signatureLowS = DERSignatureUtil.lowS(signature) require( signatureLowS.isDEREncoded, - "We must create DER encoded signatures when signing a piece of data, got: " + signatureLowS) + "We must create DER encoded signatures when signing a piece of data, got: " + signatureLowS + ) signatureLowS } def verifyDigitalSignature( data: ByteVector, publicKey: ECPublicKeyApi, - signature: ECDigitalSignature): Boolean = { + signature: ECDigitalSignature + ): Boolean = { val resultTry = Try { val publicKeyParams = - new ECPublicKeyParameters(decodePoint(publicKey.bytes), - BouncyCastleCryptoParams.curve) + new ECPublicKeyParameters( + decodePoint(publicKey.bytes), + BouncyCastleCryptoParams.curve + ) val signer = new ECDSASigner signer.init(false, publicKeyParams) signature match { case EmptyDigitalSignature => - signer.verifySignature(data.toArray, - java.math.BigInteger.valueOf(0), - java.math.BigInteger.valueOf(0)) + signer.verifySignature( + data.toArray, + java.math.BigInteger.valueOf(0), + java.math.BigInteger.valueOf(0) + ) case _: ECDigitalSignature => val (r, s) = signature.decodeSignature signer.verifySignature(data.toArray, r.bigInteger, s.bigInteger) diff --git a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncycastleCryptoRuntime.scala b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncycastleCryptoRuntime.scala index 9686e29686..b6b9a84fd3 100644 --- a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncycastleCryptoRuntime.scala +++ b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/BouncycastleCryptoRuntime.scala @@ -14,8 +14,8 @@ import scodec.bits.ByteVector import java.math.BigInteger import java.security.{MessageDigest, SecureRandom} -/** This is an implementation of [[CryptoRuntime]] that defaults to Bouncy Castle (https://bouncycastle.org/) - * and [[java.security]]. +/** This is an implementation of [[CryptoRuntime]] that defaults to Bouncy + * Castle (https://bouncycastle.org/) and [[java.security]]. */ trait BouncycastleCryptoRuntime extends CryptoRuntime { private[this] lazy val secureRandom = new SecureRandom() @@ -23,7 +23,8 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { override val cryptoContext: CryptoContext = CryptoContext.BouncyCastle /** Cribbed from ECKeyPairGenerator::generateKeyPair - * @see https://github.com/bcgit/bc-java/blob/63b18eb973f5731e403f655ee81d6b8456f5b256/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java#L39 + * @see + * https://github.com/bcgit/bc-java/blob/63b18eb973f5731e403f655ee81d6b8456f5b256/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java#L39 */ override def freshPrivateKey: ECPrivateKey = { val n = CryptoParams.getN @@ -36,9 +37,9 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { priv = BigIntegers.createRandomBigInteger(bitLength, secureRandom) if (priv.compareTo(BigInteger.ONE) < 0 || (priv.compareTo(n) >= 0)) { - () //do nothing, keep iterating + () // do nothing, keep iterating } else if (WNafUtil.getNafWeight(priv) < minWeight) { - () //do nothing, keep iterating + () // do nothing, keep iterating } else { foundNum = true } @@ -47,9 +48,11 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { ECPrivateKey.fromBytes(bytes.padLeft(33)) } - /** @param x x coordinate - * @return a tuple (p1, p2) where p1 and p2 are points on the curve and p1.x = p2.x = x - * p1.y is even, p2.y is odd + /** @param x + * x coordinate + * @return + * a tuple (p1, p2) where p1 and p2 are points on the curve and p1.x = p2.x + * \= x p1.y is even, p2.y is odd */ def recoverPoint(x: BigInteger): (ECPoint, ECPoint) = { val bytes = ByteVector(x.toByteArray) @@ -62,16 +65,20 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { bytes.tail } else { throw new IllegalArgumentException( - s"Field element cannot have more than 32 bytes, got $bytes from $x") + s"Field element cannot have more than 32 bytes, got $bytes from $x" + ) } - (BouncyCastleUtil.decodePoint(ECPublicKey(0x02.toByte +: bytes32)), - BouncyCastleUtil.decodePoint(ECPublicKey(0x03.toByte +: bytes32))) + ( + BouncyCastleUtil.decodePoint(ECPublicKey(0x02.toByte +: bytes32)), + BouncyCastleUtil.decodePoint(ECPublicKey(0x03.toByte +: bytes32)) + ) } override def recoverPublicKey( signature: ECDigitalSignature, - message: ByteVector): (ECPublicKey, ECPublicKey) = { + message: ByteVector + ): (ECPublicKey, ECPublicKey) = { val curve = BouncyCastleCryptoParams.curve val (r, s) = (signature.r.bigInteger, signature.s.bigInteger) @@ -113,7 +120,7 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { } override def ripeMd160(bytes: ByteVector): RipeMd160Digest = { - //from this tutorial http://rosettacode.org/wiki/RIPEMD-160#Scala + // from this tutorial http://rosettacode.org/wiki/RIPEMD-160#Scala val messageDigest = new RIPEMD160Digest val raw = bytes.toArray messageDigest.update(raw, 0, raw.length) @@ -152,14 +159,16 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { override def sign( privateKey: ECPrivateKey, - dataToSign: ByteVector): ECDigitalSignature = { + dataToSign: ByteVector + ): ECDigitalSignature = { BouncyCastleUtil.sign(dataToSign, privateKey) } override def signWithEntropy( privateKey: ECPrivateKey, bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature = + entropy: ByteVector + ): ECDigitalSignature = BouncyCastleUtil.signWithEntropy(bytes, privateKey, entropy) override def secKeyVerify(privateKeyBytes: ByteVector): Boolean = { @@ -173,7 +182,8 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { override def verify( publicKey: ECPublicKeyApi, data: ByteVector, - signature: ECDigitalSignature): Boolean = + signature: ECDigitalSignature + ): Boolean = BouncyCastleUtil.verifyDigitalSignature(data, publicKey, signature) override def publicKey(privateKey: ECPrivateKeyBytes): ECPublicKey = @@ -181,7 +191,8 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { override def tweakMultiply( publicKey: ECPublicKey, - tweak: FieldElement): ECPublicKey = + tweak: FieldElement + ): ECPublicKey = BouncyCastleUtil.pubKeyTweakMul(publicKey, tweak.bytes) override def add(pk1: ECPublicKey, pk2: ECPublicKey): ECPublicKey = { @@ -193,7 +204,8 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { def pubKeyTweakAdd( pubkey: ECPublicKey, - privkey: ECPrivateKey): ECPublicKey = { + privkey: ECPrivateKey + ): ECPublicKey = { val tweak = privkey.publicKey pubkey.add(tweak) } @@ -221,15 +233,18 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime { if (decoded.isInfinity) SecpPointInfinity else - SecpPoint(decoded.getRawXCoord.getEncoded, - decoded.getRawYCoord.getEncoded) + SecpPoint( + decoded.getRawXCoord.getEncoded, + decoded.getRawYCoord.getEncoded + ) } override def pbkdf2WithSha512( pass: ByteVector, salt: ByteVector, iterationCount: Int, - derivedKeyLength: Int): ByteVector = { + derivedKeyLength: Int + ): ByteVector = { val bytes = PBKDF2.withSha512(pass, salt, iterationCount, derivedKeyLength).getEncoded ByteVector(bytes) diff --git a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/HMacDSAKCalculatorWithEntropy.scala b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/HMacDSAKCalculatorWithEntropy.scala index 80ce2e263c..4d2c879464 100644 --- a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/HMacDSAKCalculatorWithEntropy.scala +++ b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/HMacDSAKCalculatorWithEntropy.scala @@ -10,12 +10,14 @@ import scodec.bits.ByteVector import java.math.BigInteger import java.security.SecureRandom -/** Entirely copied from [[org.bouncycastle.crypto.signers.HMacDSAKCalculator HMacDSAKCalculator]] - * with an added entropy parameter as well as two lines added adding the entropy to the hash. +/** Entirely copied from + * [[org.bouncycastle.crypto.signers.HMacDSAKCalculator HMacDSAKCalculator]] + * with an added entropy parameter as well as two lines added adding the + * entropy to the hash. * - * For a reference in secp256k1, see nonce_function_rfc6979 in secp256k1.c - * For a description of the altered part, see RFC 6979 section 3.2d - * here [[https://tools.ietf.org/html/rfc6979#section-3.2]] + * For a reference in secp256k1, see nonce_function_rfc6979 in secp256k1.c For + * a description of the altered part, see RFC 6979 section 3.2d here + * [[https://tools.ietf.org/html/rfc6979#section-3.2]] * * The added lines are marked below with comments. */ @@ -40,7 +42,8 @@ class HMacDSAKCalculatorWithEntropy(digest: Digest, entropy: ByteVector) override def init( n: BigInteger, d: BigInteger, - message: Array[Byte]): Unit = { + message: Array[Byte] + ): Unit = { this.n = n Arrays.fill(V, 0x01.toByte) diff --git a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/LibSecp256k1CryptoRuntime.scala b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/LibSecp256k1CryptoRuntime.scala index 5f9c9d9337..8db1dfa3f0 100644 --- a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/LibSecp256k1CryptoRuntime.scala +++ b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/LibSecp256k1CryptoRuntime.scala @@ -4,8 +4,8 @@ import org.bitcoin.NativeSecp256k1 import scodec.bits.ByteVector /** This is an implementation of [[CryptoRuntime]] that defaults to libsecp256k1 - * (https://github.com/bitcoin-core/secp256k1) when possible. All unsupported functions - * are delegated to [[BouncycastleCryptoRuntime]]. + * (https://github.com/bitcoin-core/secp256k1) when possible. All unsupported + * functions are delegated to [[BouncycastleCryptoRuntime]]. */ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { @@ -16,7 +16,8 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { override def recoverPublicKey( signature: ECDigitalSignature, - message: ByteVector): (ECPublicKey, ECPublicKey) = + message: ByteVector + ): (ECPublicKey, ECPublicKey) = BouncycastleCryptoRuntime.recoverPublicKey(signature, message) override def hmac512(key: ByteVector, data: ByteVector): ByteVector = @@ -51,15 +52,18 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { override def toPublicKey(privateKey: ECPrivateKeyBytes): ECPublicKey = { val pubKeyBytes: Array[Byte] = - NativeSecp256k1.computePubkey(privateKey.bytes.toArray, - privateKey.isCompressed) + NativeSecp256k1.computePubkey( + privateKey.bytes.toArray, + privateKey.isCompressed + ) val pubBytes = ByteVector(pubKeyBytes) ECPublicKey(pubBytes) } override def sign( privateKey: ECPrivateKey, - dataToSign: ByteVector): ECDigitalSignature = { + dataToSign: ByteVector + ): ECDigitalSignature = { val signature = NativeSecp256k1.sign(dataToSign.toArray, privateKey.bytes.toArray) ECDigitalSignature(ByteVector(signature)) @@ -68,10 +72,13 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { override def signWithEntropy( privateKey: ECPrivateKey, bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature = { - val sigBytes = NativeSecp256k1.signWithEntropy(bytes.toArray, - privateKey.bytes.toArray, - entropy.toArray) + entropy: ByteVector + ): ECDigitalSignature = { + val sigBytes = NativeSecp256k1.signWithEntropy( + bytes.toArray, + privateKey.bytes.toArray, + entropy.toArray + ) ECDigitalSignature(ByteVector(sigBytes)) } @@ -82,18 +89,21 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { override def verify( publicKey: ECPublicKeyApi, data: ByteVector, - signature: ECDigitalSignature): Boolean = { + signature: ECDigitalSignature + ): Boolean = { val result = - NativeSecp256k1.verify(data.toArray, - signature.bytes.toArray, - publicKey.bytes.toArray) + NativeSecp256k1.verify( + data.toArray, + signature.bytes.toArray, + publicKey.bytes.toArray + ) if (!result) { - //if signature verification fails with libsecp256k1 we need to use our old - //verification function from spongy castle, this is needed because early blockchain - //transactions can have weird non strict der encoded digital signatures - //bitcoin core implements this functionality here: - //https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.cpp#L16-L165 + // if signature verification fails with libsecp256k1 we need to use our old + // verification function from spongy castle, this is needed because early blockchain + // transactions can have weird non strict der encoded digital signatures + // bitcoin core implements this functionality here: + // https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.cpp#L16-L165 BouncycastleCryptoRuntime.verify(publicKey, data, signature) } else result @@ -106,18 +116,23 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { override def publicKey(privateKey: ECPrivateKeyBytes): ECPublicKey = { val pubKeyBytes: Array[Byte] = - NativeSecp256k1.computePubkey(privateKey.bytes.toArray, - privateKey.isCompressed) + NativeSecp256k1.computePubkey( + privateKey.bytes.toArray, + privateKey.isCompressed + ) val pubBytes = ByteVector(pubKeyBytes) ECPublicKey(pubBytes) } override def tweakMultiply( publicKey: ECPublicKey, - tweak: FieldElement): ECPublicKey = { - val mulBytes = NativeSecp256k1.pubKeyTweakMul(publicKey.bytes.toArray, - tweak.bytes.toArray, - true) + tweak: FieldElement + ): ECPublicKey = { + val mulBytes = NativeSecp256k1.pubKeyTweakMul( + publicKey.bytes.toArray, + tweak.bytes.toArray, + true + ) ECPublicKey(ByteVector(mulBytes)) } @@ -143,7 +158,8 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { override def combinePubKeys( pubKeys: Vector[ECPublicKey], - isCompressed: Boolean = true): ECPublicKey = { + isCompressed: Boolean = true + ): ECPublicKey = { val summands = pubKeys.map(_.decompressedBytes.toArray).toArray val sumKey = NativeSecp256k1.pubKeyCombine(summands, isCompressed) @@ -152,43 +168,54 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { override def pubKeyTweakAdd( pubkey: ECPublicKey, - privkey: ECPrivateKey): ECPublicKey = { + privkey: ECPrivateKey + ): ECPublicKey = { val tweaked = NativeSecp256k1.pubKeyTweakAdd( pubkey.decompressedBytes.toArray, privkey.bytes.toArray, - true) + true + ) ECPublicKey(ByteVector(tweaked)) } override def schnorrSign( dataToSign: ByteVector, privateKey: ECPrivateKey, - auxRand: ByteVector): SchnorrDigitalSignature = { + auxRand: ByteVector + ): SchnorrDigitalSignature = { val sigBytes = - NativeSecp256k1.schnorrSign(dataToSign.toArray, - privateKey.bytes.toArray, - auxRand.toArray) + NativeSecp256k1.schnorrSign( + dataToSign.toArray, + privateKey.bytes.toArray, + auxRand.toArray + ) SchnorrDigitalSignature(ByteVector(sigBytes)) } override def schnorrSignWithNonce( dataToSign: ByteVector, privateKey: ECPrivateKey, - nonceKey: ECPrivateKey): SchnorrDigitalSignature = { + nonceKey: ECPrivateKey + ): SchnorrDigitalSignature = { val sigBytes = - NativeSecp256k1.schnorrSignWithNonce(dataToSign.toArray, - privateKey.bytes.toArray, - nonceKey.bytes.toArray) + NativeSecp256k1.schnorrSignWithNonce( + dataToSign.toArray, + privateKey.bytes.toArray, + nonceKey.bytes.toArray + ) SchnorrDigitalSignature(ByteVector(sigBytes)) } override def schnorrVerify( data: ByteVector, schnorrPubKey: SchnorrPublicKey, - signature: SchnorrDigitalSignature): Boolean = { - NativeSecp256k1.schnorrVerify(signature.bytes.toArray, - data.toArray, - schnorrPubKey.bytes.toArray) + signature: SchnorrDigitalSignature + ): Boolean = { + NativeSecp256k1.schnorrVerify( + signature.bytes.toArray, + data.toArray, + schnorrPubKey.bytes.toArray + ) } // TODO: add a native implementation @@ -196,43 +223,53 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { data: ByteVector, nonce: SchnorrNonce, pubKey: SchnorrPublicKey, - compressed: Boolean): ECPublicKey = { - BouncycastleCryptoRuntime.schnorrComputeSigPoint(data, - nonce, - pubKey, - compressed) + compressed: Boolean + ): ECPublicKey = { + BouncycastleCryptoRuntime.schnorrComputeSigPoint( + data, + nonce, + pubKey, + compressed + ) } override def adaptorSign( key: ECPrivateKey, adaptorPoint: ECPublicKey, msg: ByteVector, - auxRand: ByteVector): ECAdaptorSignature = { + auxRand: ByteVector + ): ECAdaptorSignature = { val sig = NativeSecp256k1.adaptorSign( key.bytes.toArray, adaptorPoint.decompressedBytes.toArray, msg.toArray, - auxRand.toArray) + auxRand.toArray + ) ECAdaptorSignature(ByteVector(sig)) } override def adaptorComplete( key: ECPrivateKey, - adaptorSignature: ECAdaptorSignature): ECDigitalSignature = { + adaptorSignature: ECAdaptorSignature + ): ECDigitalSignature = { val sigBytes = - NativeSecp256k1.adaptorAdapt(key.bytes.toArray, - adaptorSignature.bytes.toArray) + NativeSecp256k1.adaptorAdapt( + key.bytes.toArray, + adaptorSignature.bytes.toArray + ) ECDigitalSignature.fromBytes(ByteVector(sigBytes)) } override def extractAdaptorSecret( signature: ECDigitalSignature, adaptorSignature: ECAdaptorSignature, - key: ECPublicKey): ECPrivateKey = { + key: ECPublicKey + ): ECPrivateKey = { val secretBytes = NativeSecp256k1.adaptorExtractSecret( signature.bytes.toArray, adaptorSignature.bytes.toArray, - key.decompressedBytes.toArray) + key.decompressedBytes.toArray + ) ECPrivateKey(ByteVector(secretBytes)) } @@ -241,15 +278,19 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { adaptorSignature: ECAdaptorSignature, key: ECPublicKey, msg: ByteVector, - adaptorPoint: ECPublicKey): Boolean = { - NativeSecp256k1.adaptorVerify(adaptorSignature.bytes.toArray, - key.decompressedBytes.toArray, - msg.toArray, - adaptorPoint.decompressedBytes.toArray) + adaptorPoint: ECPublicKey + ): Boolean = { + NativeSecp256k1.adaptorVerify( + adaptorSignature.bytes.toArray, + key.decompressedBytes.toArray, + msg.toArray, + adaptorPoint.decompressedBytes.toArray + ) } override def isValidSignatureEncoding( - signature: ECDigitalSignature): Boolean = + signature: ECDigitalSignature + ): Boolean = BouncycastleCryptoRuntime.isValidSignatureEncoding(signature) override def isDEREncoded(signature: ECDigitalSignature): Boolean = @@ -279,11 +320,14 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime { pass: ByteVector, salt: ByteVector, iterationCount: Int, - derivedKeyLength: Int): ByteVector = { - BouncycastleCryptoRuntime.pbkdf2WithSha512(pass, - salt, - iterationCount, - derivedKeyLength) + derivedKeyLength: Int + ): ByteVector = { + BouncycastleCryptoRuntime.pbkdf2WithSha512( + pass, + salt, + iterationCount, + derivedKeyLength + ) } } diff --git a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/PBKDF2.scala b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/PBKDF2.scala index f9d6077880..ef874473d1 100644 --- a/crypto/.jvm/src/main/scala/org/bitcoins/crypto/PBKDF2.scala +++ b/crypto/.jvm/src/main/scala/org/bitcoins/crypto/PBKDF2.scala @@ -5,8 +5,9 @@ import scodec.bits.ByteVector import javax.crypto.spec.PBEKeySpec import javax.crypto.{SecretKey, SecretKeyFactory} -/** @define keyStretch Derives the provided value and salt to a secret key - * using the PBKDF2 key derivation function +/** @define keyStretch + * Derives the provided value and salt to a secret key using the PBKDF2 key + * derivation function * * Utilities related to the PBKDF2 key derivation function */ @@ -14,7 +15,8 @@ object PBKDF2 { /** This variant of PBKDF2 is used in * [[https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#from-mnemonic-to-seed BIP39]] - * and is generally speaking a recommended pseudo random function for PBKDF2. See for example + * and is generally speaking a recommended pseudo random function for PBKDF2. + * See for example * [[https://stackoverflow.com/questions/19348501/pbkdf2withhmacsha512-vs-pbkdf2withhmacsha1 this SO question]]. */ private val PSEUDO_RANDOM_FUNCTION = "PBKDF2WithHmacSHA512" @@ -27,7 +29,8 @@ object PBKDF2 { bytes: ByteVector, salt: ByteVector, iterationCount: Int, - derivedKeyLength: Int): SecretKey = { + derivedKeyLength: Int + ): SecretKey = { val keySpec = new PBEKeySpec( bytes.toArray.map(_.toChar), diff --git a/crypto/src/main/scala/org/bitcoins/crypto/AdaptorUtil.scala b/crypto/src/main/scala/org/bitcoins/crypto/AdaptorUtil.scala index ff056022c3..f2a7c2356d 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/AdaptorUtil.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/AdaptorUtil.scala @@ -8,18 +8,13 @@ import scodec.bits.ByteVector * Note that the naming is not entirely consistent between the specification * and this file in hopes of making this code more readable. * - * The naming in this file more closely matches the naming in the secp256k1-zkp implementation: + * The naming in this file more closely matches the naming in the secp256k1-zkp + * implementation: * https://github.com/ElementsProject/secp256k1-zkp/tree/master/src/modules/ecdsa_adaptor * - * Legend: - * x <> privKey - * X <> pubKey - * y <> adaptorSecret - * Y <> adaptorPoint/adaptor - * messageHash <> dataToSign/data/message - * R_a <> untweakedNonce - * R <> tweakedNonce - * proof <> (e, s) + * Legend: x <> privKey X <> pubKey y <> adaptorSecret Y <> + * adaptorPoint/adaptor messageHash <> dataToSign/data/message R_a <> + * untweakedNonce R <> tweakedNonce proof <> (e, s) */ object AdaptorUtil { @@ -31,7 +26,8 @@ object AdaptorUtil { privKey: ECPrivateKey, adaptorPoint: ECPublicKey, algoName: String, - auxRand: ByteVector): FieldElement = { + auxRand: ByteVector + ): FieldElement = { val randHash = CryptoUtil.sha256ECDSAAdaptorAux(auxRand).bytes val maskedKey = randHash.xor(privKey.bytes) @@ -45,19 +41,21 @@ object AdaptorUtil { FieldElement(nonceHash.bytes) } - /** Computes s_a = inverse(k) * (dataToSign + rx*privateKey) - * which is the third from last step in + /** Computes s_a = inverse(k) * (dataToSign + rx*privateKey) which is the + * third from last step in * https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#encrypted-signing */ private def adaptorSignHelper( dataToSign: ByteVector, k: FieldElement, r: ECPublicKey, - privateKey: ECPrivateKey): FieldElement = { + privateKey: ECPrivateKey + ): FieldElement = { CryptoUtil.decodePoint(r) match { case SecpPointInfinity => throw new IllegalArgumentException( - s"Invalid point, got=$SecpPointInfinity") + s"Invalid point, got=$SecpPointInfinity" + ) case point: SecpPointFinite => val rx = FieldElement(point.x.toBigInteger) val x = privateKey.fieldElement @@ -68,17 +66,22 @@ object AdaptorUtil { } } - /** Implements https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#encrypted-signing */ + /** Implements + * https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#encrypted-signing + */ def adaptorSign( privateKey: ECPrivateKey, adaptorPoint: ECPublicKey, dataToSign: ByteVector, - auxRand: ByteVector): ECAdaptorSignature = { - val k = adaptorNonce(dataToSign, - privateKey, - adaptorPoint, - "ECDSAadaptor/non", - auxRand) + auxRand: ByteVector + ): ECAdaptorSignature = { + val k = adaptorNonce( + dataToSign, + privateKey, + adaptorPoint, + "ECDSAadaptor/non", + auxRand + ) if (k.isZero) { throw new RuntimeException("Nonce cannot be zero.") @@ -96,12 +99,15 @@ object AdaptorUtil { ECAdaptorSignature(tweakedNonce, untweakedNonce, adaptedSig, proofE, proofS) } - /** Computes R = inverse(s) * (msg*G + rx*pubKey) = inverse(s) * (msg + rx*privKey) * G */ + /** Computes R = inverse(s) * (msg*G + rx*pubKey) = inverse(s) * (msg + + * rx*privKey) * G + */ private def adaptorVerifyHelper( rx: FieldElement, s: FieldElement, pubKey: ECPublicKey, - msg: ByteVector): FieldElement = { + msg: ByteVector + ): FieldElement = { val m = FieldElement(msg) val untweakedPoint = m.getPublicKey.add(pubKey.multiply(rx)).multiply(s.inverse) @@ -109,12 +115,14 @@ object AdaptorUtil { FieldElement(untweakedPoint.bytes.tail) } - /** https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#encryption-verification */ + /** https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#encryption-verification + */ def adaptorVerify( adaptorSig: ECAdaptorSignature, pubKey: ECPublicKey, data: ByteVector, - adaptor: ECPublicKey): Boolean = { + adaptor: ECPublicKey + ): Boolean = { val validProof = DLEQUtil.dleqVerify( adaptorSig.dleqProofS, adaptorSig.dleqProofE, @@ -125,7 +133,8 @@ object AdaptorUtil { if (validProof) { val tweakedNoncex = FieldElement( - CurveCoordinate(adaptorSig.tweakedNonce.bytes.tail).toBigInteger) + CurveCoordinate(adaptorSig.tweakedNonce.bytes.tail).toBigInteger + ) val untweakedNoncex = FieldElement(adaptorSig.untweakedNonce.bytes.tail) if (tweakedNoncex.isZero || untweakedNoncex.isZero) { @@ -142,30 +151,42 @@ object AdaptorUtil { } } - /** Implements https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#decryption */ + /** Implements + * https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#decryption + */ def adaptorComplete( adaptorSecret: ECPrivateKey, - adaptorSig: ECAdaptorSignature): ECDigitalSignature = { + adaptorSig: ECAdaptorSignature + ): ECDigitalSignature = { val rx = FieldElement(adaptorSig.tweakedNonce.bytes.tail) val correctedS = adaptorSig.adaptedS.multInv(adaptorSecret.fieldElement) - val sig = ECDigitalSignature.fromRS(BigInt(rx.toBigInteger), - BigInt(correctedS.toBigInteger)) + val sig = ECDigitalSignature.fromRS( + BigInt(rx.toBigInteger), + BigInt(correctedS.toBigInteger) + ) DERSignatureUtil.lowS(sig) } - /** Implements https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#key-recovery */ + /** Implements + * https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#key-recovery + */ def extractAdaptorSecret( sig: ECDigitalSignature, adaptorSig: ECAdaptorSignature, - adaptor: ECPublicKey): ECPrivateKey = { - require(adaptorSig.tweakedNonce.bytes.tail == sig.rBytes, - "Adaptor signature must be related to signature") + adaptor: ECPublicKey + ): ECPrivateKey = { + require( + adaptorSig.tweakedNonce.bytes.tail == sig.rBytes, + "Adaptor signature must be related to signature" + ) val secretOrNeg = adaptorSig.adaptedS.multInv(FieldElement(sig.s)) - require(secretOrNeg.getPublicKey.bytes.tail == adaptor.bytes.tail, - s"Invalid inputs: $sig, $adaptorSig, and $adaptor") + require( + secretOrNeg.getPublicKey.bytes.tail == adaptor.bytes.tail, + s"Invalid inputs: $sig, $adaptorSig, and $adaptor" + ) if (secretOrNeg.getPublicKey == adaptor) { secretOrNeg.toPrivateKey diff --git a/crypto/src/main/scala/org/bitcoins/crypto/AesCrypt.scala b/crypto/src/main/scala/org/bitcoins/crypto/AesCrypt.scala index 83baf6c023..4ea26c61e0 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/AesCrypt.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/AesCrypt.scala @@ -6,18 +6,16 @@ import javax.crypto.spec.{IvParameterSpec, SecretKeySpec} import javax.crypto.{BadPaddingException, Cipher, SecretKey} import scala.util.{Failure, Success, Try} -/** Represents a encrypted cipher text with it's accompanying - * initialization vector (IV). Both the cipher text and the IV - * is needed to decrypt the cipher text. +/** Represents a encrypted cipher text with it's accompanying initialization + * vector (IV). Both the cipher text and the IV is needed to decrypt the cipher + * text. */ final case class AesEncryptedData(cipherText: ByteVector, iv: AesIV) extends NetworkElement { - /** We serialize IV and ciphertext by prepending the IV - * to the ciphertext, and converting it to base64. - * Since the IV is of static length, deserializing is a matter - * of taking the first bytes as IV, and the rest as - * ciphertext. + /** We serialize IV and ciphertext by prepending the IV to the ciphertext, and + * converting it to base64. Since the IV is of static length, deserializing + * is a matter of taking the first bytes as IV, and the rest as ciphertext. */ lazy val toBase64: String = { bytes.toBase64 @@ -29,11 +27,9 @@ final case class AesEncryptedData(cipherText: ByteVector, iv: AesIV) object AesEncryptedData extends Factory[AesEncryptedData] { - /** We serialize IV and ciphertext by prepending the IV - * to the ciphertext, and converting it to base64. - * Since the IV is of static length, deserializing is a matter - * of taking the first bytes as IV, and the rest as - * ciphertext. + /** We serialize IV and ciphertext by prepending the IV to the ciphertext, and + * converting it to base64. Since the IV is of static length, deserializing + * is a matter of taking the first bytes as IV, and the rest as ciphertext. */ def fromBase64(base64: String): Option[AesEncryptedData] = { ByteVector.fromBase64(base64) match { @@ -46,11 +42,9 @@ object AesEncryptedData extends Factory[AesEncryptedData] { } } - /** We serialize IV and ciphertext by prepending the IV - * to the ciphertext, and converting it to base64. - * Since the IV is of static length, deserializing is a matter - * of taking the first bytes as IV, and the rest as - * ciphertext. + /** We serialize IV and ciphertext by prepending the IV to the ciphertext, and + * converting it to base64. Since the IV is of static length, deserializing + * is a matter of taking the first bytes as IV, and the rest as ciphertext. */ def fromValidBase64(base64: String): AesEncryptedData = fromBase64(base64) match { @@ -65,15 +59,15 @@ object AesEncryptedData extends Factory[AesEncryptedData] { override def fromBytes(bytes: ByteVector): AesEncryptedData = { require( bytes.length > AesIV.length, - s"AesEncryptedData must be longer than ${AesIV.length} bytes, got $bytes") + s"AesEncryptedData must be longer than ${AesIV.length} bytes, got $bytes" + ) val (ivBytes, cipherText) = bytes.splitAt(AesIV.length) val iv = AesIV.fromValidBytes(ivBytes) AesEncryptedData(cipherText, iv) } } -/** Represents a salt used to derive a AES key from - * a human-readable passphrase. +/** Represents a salt used to derive a AES key from a human-readable passphrase. */ final case class AesSalt( bytes: ByteVector @@ -83,8 +77,7 @@ object AesSalt extends Factory[AesSalt] { override def fromBytes(bytes: ByteVector): AesSalt = new AesSalt(bytes) - /** Generates a random AES salt - * of 32 bytes + /** Generates a random AES salt of 32 bytes */ def random: AesSalt = { val bytes = CryptoUtil.randomBytes(32) @@ -99,7 +92,8 @@ final case class AesPassword private (private val value: String) /** Converts this password into an AES key * - * @return A tuple of the derived key and generated salt + * @return + * A tuple of the derived key and generated salt */ def toKey: (AesKey, AesSalt) = { val salt = AesSalt.random @@ -108,8 +102,8 @@ final case class AesPassword private (private val value: String) (key, salt) } - /** Given some salt, converts this password to an AES key - * using PBKDF2 key stretching. + /** Given some salt, converts this password to an AES key using PBKDF2 key + * stretching. */ def toKey(salt: AesSalt): AesKey = { @@ -122,7 +116,8 @@ final case class AesPassword private (private val value: String) passwordBytes, salt.bytes, iterationCount = AesPassword.ITERATIONS, - derivedKeyLength = AesPassword.KEY_SIZE) + derivedKeyLength = AesPassword.KEY_SIZE + ) AesKey.fromValidBytes(secretKey) } @@ -138,8 +133,8 @@ object AesPassword extends StringFactory[AesPassword] { // to remove apply constructor from case class private[AesPassword] def apply(value: String) = new AesPassword(value) - /** Tries to construct a password from the given string. Fails - * if the string is empty. + /** Tries to construct a password from the given string. Fails if the string + * is empty. */ override def fromStringOpt(string: String): Option[AesPassword] = { if (string.isEmpty) None else Some(AesPassword(string)) @@ -150,30 +145,30 @@ object AesPassword extends StringFactory[AesPassword] { case Some(password) => password case None => sys.error( - s"Could not construct AesPassword from given string, not logging in case it's sensitive") + s"Could not construct AesPassword from given string, not logging in case it's sensitive" + ) } } - /** Constructs a password from the given string. Throws - * if the string is empty. + /** Constructs a password from the given string. Throws if the string is + * empty. */ def fromNonEmptyString(string: String): AesPassword = fromStringOpt(string).getOrElse( throw new IllegalArgumentException( - "Cannot construct empty AES passwords!")) + "Cannot construct empty AES passwords!" + ) + ) } -/** Represents a encryption/decryption key. - * AES keys can be converted to - * [[javax.crypto.SecretKey SecretKey]]s, - * and have certain length requirements. +/** Represents a encryption/decryption key. AES keys can be converted to + * [[javax.crypto.SecretKey SecretKey]]s, and have certain length requirements. */ final case class AesKey private (bytes: ByteVector) extends MaskedToString with NetworkElement { - /** The Java [[javax.crypto.SecretKey SecretKey]] representation - * of this key. + /** The Java [[javax.crypto.SecretKey SecretKey]] representation of this key. */ def toSecretKey: SecretKey = new SecretKeySpec(bytes.toArray, "AES") @@ -188,9 +183,8 @@ object AesKey { // to remove apply constructor from case class private[AesKey] def apply(bytes: ByteVector): AesKey = new AesKey(bytes) - /** Tries to construct an AES key from the - * given bytes. AES keys have size constraints, - * and must be 16, 24 or 32 bytes long. + /** Tries to construct an AES key from the given bytes. AES keys have size + * constraints, and must be 16, 24 or 32 bytes long. */ def fromBytes(bytes: ByteVector): Option[AesKey] = { if (keylengths.exists(k => k == bytes.length)) { @@ -206,14 +200,15 @@ object AesKey { AesKey.fromValidBytes(bytes) } - /** Construct a AES key from the given bytes, - * throwing an exception if the provided bytes - * are of invalid length. + /** Construct a AES key from the given bytes, throwing an exception if the + * provided bytes are of invalid length. */ def fromValidBytes(bytes: ByteVector): AesKey = { fromBytes(bytes).getOrElse( throw new IllegalArgumentException( - s"Given bytes (${bytes.toHex}) had bad length")) + s"Given bytes (${bytes.toHex}) had bad length" + ) + ) } /** Allowed AES key lengths, bytes */ @@ -234,8 +229,7 @@ object AesKey { def get256Bit(): AesKey = get(32) } -/** Represents an initialization vector (IV) used - * in AES encryption. +/** Represents an initialization vector (IV) used in AES encryption. */ final case class AesIV private (bytes: ByteVector) extends AnyVal @@ -243,24 +237,28 @@ final case class AesIV private (bytes: ByteVector) object AesIV { - /** Length of IV in bytes (for CFB mode, other modes have different lengths) */ + /** Length of IV in bytes (for CFB mode, other modes have different lengths) + */ private[crypto] val length = 16 // this is here to remove apply constructor private[AesIV] def apply(bytes: ByteVector): AesIV = new AesIV(bytes) - /** Tries to construct an AES IV from the - * given bytes. IVs must be 16 bytes long - * (in CFB mode, which is what we use here). + /** Tries to construct an AES IV from the given bytes. IVs must be 16 bytes + * long (in CFB mode, which is what we use here). */ def fromBytes(bytes: ByteVector): Option[AesIV] = if (bytes.length == AesIV.length) Some(new AesIV(bytes)) else None - /** Constructs an AES IV from the given bytes. Throws if the given bytes are invalid */ + /** Constructs an AES IV from the given bytes. Throws if the given bytes are + * invalid + */ def fromValidBytes(bytes: ByteVector): AesIV = fromBytes(bytes).getOrElse( throw new IllegalArgumentException( - s"Given bytes must be of length 16! Got: ${bytes.length}")) + s"Given bytes must be of length 16! Got: ${bytes.length}" + ) + ) /** Generates a random IV */ def random: AesIV = { @@ -272,9 +270,8 @@ object AesIV { */ object AesCrypt { - /** AES encryption with CFB block cipher mode - * and no padding, such that arbitrary plaintexts - * can be encrypted. + /** AES encryption with CFB block cipher mode and no padding, such that + * arbitrary plaintexts can be encrypted. */ private val aesCipherType: String = "AES/CFB/NoPadding" @@ -285,11 +282,14 @@ object AesCrypt { private def decryptionCipher( secret: AesKey, - initializationVector: AesIV): Cipher = { + initializationVector: AesIV + ): Cipher = { val cipher = getCipher - cipher.init(Cipher.DECRYPT_MODE, - secret.toSecretKey, - new IvParameterSpec(initializationVector.bytes.toArray)) + cipher.init( + Cipher.DECRYPT_MODE, + secret.toSecretKey, + new IvParameterSpec(initializationVector.bytes.toArray) + ) cipher } @@ -297,7 +297,8 @@ object AesCrypt { */ def decrypt( encrypted: AesEncryptedData, - key: AesKey): Either[AesDecryptionException, ByteVector] = { + key: AesKey + ): Either[AesDecryptionException, ByteVector] = { val cipher = decryptionCipher(key, encrypted.iv) val decryptionAttempt = Try { @@ -318,22 +319,24 @@ object AesCrypt { private def encryptionCipher(secret: AesKey, iv: AesIV): Cipher = { val cipher = getCipher - cipher.init(Cipher.ENCRYPT_MODE, - secret.toSecretKey, - new IvParameterSpec(iv.bytes.toArray)) + cipher.init( + Cipher.ENCRYPT_MODE, + secret.toSecretKey, + new IvParameterSpec(iv.bytes.toArray) + ) cipher } - /** Encrypts the given plaintext, by explicitly passing in a - * intialization vector. This is unsafe if the user passes - * in a bad IV, so this method is kept private within - * Bitcoin-S. It is useful for testing purposes, so that's - * why we expose it in the first place. + /** Encrypts the given plaintext, by explicitly passing in a intialization + * vector. This is unsafe if the user passes in a bad IV, so this method is + * kept private within Bitcoin-S. It is useful for testing purposes, so + * that's why we expose it in the first place. */ private[crypto] def encryptWithIV( plainText: ByteVector, iv: AesIV, - key: AesKey): AesEncryptedData = { + key: AesKey + ): AesEncryptedData = { val cipher = encryptionCipher(key, iv) val cipherText = cipher.doFinal(plainText.toArray) diff --git a/crypto/src/main/scala/org/bitcoins/crypto/CryptoBytesUtil.scala b/crypto/src/main/scala/org/bitcoins/crypto/CryptoBytesUtil.scala index 9d6aa0e9f0..9eb6f33ba3 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/CryptoBytesUtil.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/CryptoBytesUtil.scala @@ -16,8 +16,8 @@ trait CryptoBytesUtil { def encodeHex(byte: Byte): String = encodeHex(ByteVector(byte)) - /** Encodes a long number to a hex string, pads it with an extra '0' char - * if the hex string is an odd amount of characters. + /** Encodes a long number to a hex string, pads it with an extra '0' char if + * the hex string is an odd amount of characters. */ def encodeHex(long: Long): String = { val hex = long.toHexString.length % 2 match { @@ -48,7 +48,7 @@ trait CryptoBytesUtil { /** Tests if a given string is a hexadecimal string. */ def isHex(str: String): Boolean = { - //check valid characters & hex strings have to have an even number of chars + // check valid characters & hex strings have to have an even number of chars str.matches("^[0-9a-f]+$") && (str.length % 2 == 0) } @@ -66,10 +66,10 @@ trait CryptoBytesUtil { private val Z: Char = '0' - /** Adds the amount padding bytes needed to fix the size of the hex string - * for instance, ints are required to be 4 bytes. If the number is just 1 - * it will only take 1 byte. We need to pad the byte with an extra 3 bytes so the result is - * 00000001 instead of just 1. + /** Adds the amount padding bytes needed to fix the size of the hex string for + * instance, ints are required to be 4 bytes. If the number is just 1 it will + * only take 1 byte. We need to pad the byte with an extra 3 bytes so the + * result is 00000001 instead of just 1. */ @inline final def addPadding(paddingNeeded: Int, hex: String): String = { val builder = new StringBuilder diff --git a/crypto/src/main/scala/org/bitcoins/crypto/CryptoNumberUtil.scala b/crypto/src/main/scala/org/bitcoins/crypto/CryptoNumberUtil.scala index f55f90dc33..8acb756bcd 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/CryptoNumberUtil.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/CryptoNumberUtil.scala @@ -26,12 +26,12 @@ trait CryptoNumberUtil { /** Converts a sequence of bytes to twos complement signed number. */ def toBigInt(bytes: ByteVector): BigInt = { - //BigInt interprets the number as an unsigned number then applies the given - //sign in front of that number, therefore if we have a negative number we need to invert it - //since twos complement is an inverted number representation for negative numbers - //see [[https://en.wikipedia.org/wiki/Two%27s_complement]] + // BigInt interprets the number as an unsigned number then applies the given + // sign in front of that number, therefore if we have a negative number we need to invert it + // since twos complement is an inverted number representation for negative numbers + // see [[https://en.wikipedia.org/wiki/Two%27s_complement]] if (bytes.isEmpty) BigInt(0) - //check if sign bit is set + // check if sign bit is set else if ((0x80.toByte & bytes.head) != 0) { val invertedBytes = bytes.tail.map(b => (b ^ 0xff.toByte).toByte) val firstByteInverted = (bytes.head ^ 0xff.toByte).toByte diff --git a/crypto/src/main/scala/org/bitcoins/crypto/CryptoParams.scala b/crypto/src/main/scala/org/bitcoins/crypto/CryptoParams.scala index 198eb35c28..5504e7f2c3 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/CryptoParams.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/CryptoParams.scala @@ -4,8 +4,8 @@ import scodec.bits.ByteVector import java.math.BigInteger -/** Created by chris on 3/29/16. - * This trait represents all of the default parameters for our elliptic curve +/** Created by chris on 3/29/16. This trait represents all of the default + * parameters for our elliptic curve */ sealed abstract class CryptoParams { diff --git a/crypto/src/main/scala/org/bitcoins/crypto/CryptoRuntime.scala b/crypto/src/main/scala/org/bitcoins/crypto/CryptoRuntime.scala index a1b620802d..a45d145e4a 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/CryptoRuntime.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/CryptoRuntime.scala @@ -4,8 +4,8 @@ import scodec.bits.{BitVector, ByteVector} import scala.util.{Failure, Success, Try} -/** Trait that should be extended by specific runtimes like javascript - * or the JVM to support crypto functions needed for bitcoin-s +/** Trait that should be extended by specific runtimes like javascript or the + * JVM to support crypto functions needed for bitcoin-s */ trait CryptoRuntime { @@ -15,8 +15,10 @@ trait CryptoRuntime { def freshPrivateKey: ECPrivateKey /** Converts a private key -> public key - * @param privateKey the private key we want the corresponding public key for - * @param isCompressed whether the returned public key should be compressed or not + * @param privateKey + * the private key we want the corresponding public key for + * @param isCompressed + * whether the returned public key should be compressed or not */ def toPublicKey(privateKey: ECPrivateKeyBytes): ECPublicKey @@ -148,17 +150,24 @@ trait CryptoRuntime { sha256(dlcAnnouncementTagBytes ++ bytes) } - /** Recover public keys from a signature and the message that was signed. This method will return 2 public keys, and the signature - * can be verified with both, but only one of them matches that private key that was used to generate the signature. + /** Recover public keys from a signature and the message that was signed. This + * method will return 2 public keys, and the signature can be verified with + * both, but only one of them matches that private key that was used to + * generate the signature. * - * @param signature signature - * @param message message that was signed - * @return a (pub1, pub2) tuple where pub1 and pub2 are candidates public keys. If you have the recovery id then use - * pub1 if the recovery id is even and pub2 if it is odd + * @param signature + * signature + * @param message + * message that was signed + * @return + * a (pub1, pub2) tuple where pub1 and pub2 are candidates public keys. If + * you have the recovery id then use pub1 if the recovery id is even and + * pub2 if it is odd */ def recoverPublicKey( signature: ECDigitalSignature, - message: ByteVector): (ECPublicKey, ECPublicKey) + message: ByteVector + ): (ECPublicKey, ECPublicKey) // The tag "BIP0340/aux" private val schnorrAuxTagBytes = { @@ -191,14 +200,16 @@ trait CryptoRuntime { def signWithEntropy( privateKey: ECPrivateKey, bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature + entropy: ByteVector + ): ECDigitalSignature def secKeyVerify(privateKeybytes: ByteVector): Boolean def verify( publicKey: ECPublicKeyApi, data: ByteVector, - signature: ECDigitalSignature): Boolean + signature: ECDigitalSignature + ): Boolean def decompressed(pubKeyBytes: ByteVector): ByteVector = { decodePoint(pubKeyBytes) match { @@ -212,7 +223,8 @@ trait CryptoRuntime { def decompressed[PK <: ECPublicKeyApi]( pubKeyBytes: ByteVector, - fromBytes: ByteVector => PK): PK = { + fromBytes: ByteVector => PK + ): PK = { fromBytes(decompressed(pubKeyBytes)) } @@ -251,7 +263,9 @@ trait CryptoRuntime { sum.bytes } - /** Adds two SecpPoints together and correctly handles the point at infinity (0x00). */ + /** Adds two SecpPoints together and correctly handles the point at infinity + * (0x00). + */ def add(point1: SecpPoint, point2: SecpPoint): SecpPoint = { (point1, point2) match { case (SecpPointInfinity, p) => p @@ -270,21 +284,25 @@ trait CryptoRuntime { } } - /** Adds two public keys together, failing if the sum is 0x00 (the point at infinity). */ + /** Adds two public keys together, failing if the sum is 0x00 (the point at + * infinity). + */ def add(pk1: ECPublicKey, pk2: ECPublicKey): ECPublicKey - /** Adds a Vector of public keys together, failing only if the total sum is 0x00 - * (the point at infinity), but still succeeding if sub-sums are 0x00. + /** Adds a Vector of public keys together, failing only if the total sum is + * 0x00 (the point at infinity), but still succeeding if sub-sums are 0x00. */ def combinePubKeys( pubKeys: Vector[ECPublicKey], - isCompressed: Boolean = true): ECPublicKey = { + isCompressed: Boolean = true + ): ECPublicKey = { val summandPoints = pubKeys.map(_.toPoint) val sumPoint = summandPoints.reduce[SecpPoint](add(_, _)) sumPoint match { case SecpPointInfinity => throw new IllegalArgumentException( - "Sum result was 0x00, an invalid public key.") + "Sum result was 0x00, an invalid public key." + ) case p: SecpPointFinite => if (isCompressed) p.toPublicKey.compressed else p.toPublicKey.decompressed @@ -307,7 +325,8 @@ trait CryptoRuntime { def schnorrSign( dataToSign: ByteVector, privateKey: ECPrivateKey, - auxRand: ByteVector): SchnorrDigitalSignature = { + auxRand: ByteVector + ): SchnorrDigitalSignature = { val nonceKey = SchnorrNonce.kFromBipSchnorr(privateKey, dataToSign, auxRand) @@ -317,12 +336,14 @@ trait CryptoRuntime { def schnorrSignWithNonce( dataToSign: ByteVector, privateKey: ECPrivateKey, - nonceKey: ECPrivateKey): SchnorrDigitalSignature = { + nonceKey: ECPrivateKey + ): SchnorrDigitalSignature = { val rx = nonceKey.schnorrNonce val k = nonceKey.nonceKey.fieldElement val x = privateKey.schnorrKey.fieldElement val e = sha256SchnorrChallenge( - rx.bytes ++ privateKey.schnorrPublicKey.bytes ++ dataToSign).bytes + rx.bytes ++ privateKey.schnorrPublicKey.bytes ++ dataToSign + ).bytes val challenge = x.multiply(FieldElement(e)) val sig = k.add(challenge) @@ -333,14 +354,16 @@ trait CryptoRuntime { def schnorrVerify( data: ByteVector, schnorrPubKey: SchnorrPublicKey, - signature: SchnorrDigitalSignature): Boolean = { + signature: SchnorrDigitalSignature + ): Boolean = { val rx = signature.rx val sT = Try(signature.sig.toPrivateKey) sT match { case Success(s) => val eBytes = sha256SchnorrChallenge( - rx.bytes ++ schnorrPubKey.bytes ++ data).bytes + rx.bytes ++ schnorrPubKey.bytes ++ data + ).bytes val e = FieldElement(eBytes) val negE = e.negate @@ -361,9 +384,11 @@ trait CryptoRuntime { data: ByteVector, nonce: SchnorrNonce, pubKey: SchnorrPublicKey, - compressed: Boolean): ECPublicKey = { + compressed: Boolean + ): ECPublicKey = { val eBytes = sha256SchnorrChallenge( - nonce.bytes ++ pubKey.bytes ++ data).bytes + nonce.bytes ++ pubKey.bytes ++ data + ).bytes val e = FieldElement(eBytes) @@ -381,20 +406,23 @@ trait CryptoRuntime { key: ECPrivateKey, adaptorPoint: ECPublicKey, msg: ByteVector, - auxRand: ByteVector): ECAdaptorSignature = { + auxRand: ByteVector + ): ECAdaptorSignature = { AdaptorUtil.adaptorSign(key, adaptorPoint, msg, auxRand) } def adaptorComplete( key: ECPrivateKey, - adaptorSignature: ECAdaptorSignature): ECDigitalSignature = { + adaptorSignature: ECAdaptorSignature + ): ECDigitalSignature = { AdaptorUtil.adaptorComplete(key, adaptorSignature) } def extractAdaptorSecret( signature: ECDigitalSignature, adaptorSignature: ECAdaptorSignature, - key: ECPublicKey): ECPrivateKey = { + key: ECPublicKey + ): ECPrivateKey = { AdaptorUtil.extractAdaptorSecret(signature, adaptorSignature, key) } @@ -402,7 +430,8 @@ trait CryptoRuntime { adaptorSignature: ECAdaptorSignature, key: ECPublicKey, msg: ByteVector, - adaptorPoint: ECPublicKey): Boolean = + adaptorPoint: ECPublicKey + ): Boolean = AdaptorUtil.adaptorVerify(adaptorSignature, key, msg, adaptorPoint) def decodeSignature(signature: ECDigitalSignature): (BigInt, BigInt) = @@ -414,41 +443,45 @@ trait CryptoRuntime { def isDEREncoded(signature: ECDigitalSignature): Boolean = DERSignatureUtil.isDEREncoded(signature) - /** https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#hashing-data-objects */ + /** https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki#hashing-data-objects + */ def sipHash(item: ByteVector, key: SipHashKey): Long def pbkdf2WithSha512( pass: String, salt: String, iterationCount: Int, - derivedKeyLength: Int): ByteVector = { - pbkdf2WithSha512(ByteVector(pass.getBytes), - ByteVector(salt.getBytes), - iterationCount, - derivedKeyLength) + derivedKeyLength: Int + ): ByteVector = { + pbkdf2WithSha512( + ByteVector(pass.getBytes), + ByteVector(salt.getBytes), + iterationCount, + derivedKeyLength + ) } def pbkdf2WithSha512( pass: ByteVector, salt: ByteVector, iterationCount: Int, - derivedKeyLength: Int): ByteVector + derivedKeyLength: Int + ): ByteVector def randomBytes(n: Int): ByteVector - /** Implements basic sanity tests for checking entropy like - * making sure it isn't all the same bytes, - * it isn't all 0x00...00 - * or it isn't all 0xffff...fff + /** Implements basic sanity tests for checking entropy like making sure it + * isn't all the same bytes, it isn't all 0x00...00 or it isn't all + * 0xffff...fff */ def checkEntropy(bitVector: BitVector): Boolean = { val byteArr = bitVector.toByteArray if (bitVector.length < 128) { - //not enough entropy + // not enough entropy false } else if (byteArr.toSet.size == 1) { - //means all byte were the same - //we need more diversity with entropy + // means all byte were the same + // we need more diversity with entropy false } else { true diff --git a/crypto/src/main/scala/org/bitcoins/crypto/CryptoUtil.scala b/crypto/src/main/scala/org/bitcoins/crypto/CryptoUtil.scala index ec5cc20786..19143511f3 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/CryptoUtil.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/CryptoUtil.scala @@ -2,12 +2,11 @@ package org.bitcoins.crypto import scodec.bits.ByteVector -/** Utility cryptographic functions - * This is a proxy for the underlying implementation of [[CryptoRuntime]] - * such as [[LibSecp256k1CryptoRuntime]]. +/** Utility cryptographic functions This is a proxy for the underlying + * implementation of [[CryptoRuntime]] such as [[LibSecp256k1CryptoRuntime]]. * - * This is necessary so that the core module doesn't need to be refactored - * to add support for multiple platforms, it can keep referencing CryptoUtil + * This is necessary so that the core module doesn't need to be refactored to + * add support for multiple platforms, it can keep referencing CryptoUtil */ trait CryptoUtil extends CryptoRuntime { @@ -85,7 +84,8 @@ trait CryptoUtil extends CryptoRuntime { override def recoverPublicKey( signature: ECDigitalSignature, - message: ByteVector): (ECPublicKey, ECPublicKey) = { + message: ByteVector + ): (ECPublicKey, ECPublicKey) = { cryptoRuntime.recoverPublicKey(signature, message) } @@ -94,22 +94,26 @@ trait CryptoUtil extends CryptoRuntime { override def sign( privateKey: ECPrivateKey, - dataToSign: ByteVector): ECDigitalSignature = { + dataToSign: ByteVector + ): ECDigitalSignature = { val sig = cryptoRuntime.sign(privateKey, dataToSign) assert( verify(privateKey.publicKey, dataToSign, sig), - "Something has gone wrong, a generated signature may have been corrupted") + "Something has gone wrong, a generated signature may have been corrupted" + ) sig } override def signWithEntropy( privateKey: ECPrivateKey, bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature = { + entropy: ByteVector + ): ECDigitalSignature = { val sig = cryptoRuntime.signWithEntropy(privateKey, bytes, entropy) assert( verify(privateKey.publicKey, bytes, sig), - "Something has gone wrong, a generated signature may have been corrupted") + "Something has gone wrong, a generated signature may have been corrupted" + ) sig } @@ -119,19 +123,22 @@ trait CryptoUtil extends CryptoRuntime { override def verify( publicKey: ECPublicKeyApi, data: ByteVector, - signature: ECDigitalSignature): Boolean = + signature: ECDigitalSignature + ): Boolean = cryptoRuntime.verify(publicKey, data, signature) override def decompressed(pubKeyBytes: ByteVector): ByteVector = cryptoRuntime.decompressed(pubKeyBytes) override def decompressed[PK <: ECPublicKeyApi]( - publicKey: PK): publicKey.type = + publicKey: PK + ): publicKey.type = cryptoRuntime.decompressed(publicKey) override def tweakMultiply( publicKey: ECPublicKey, - tweak: FieldElement): ECPublicKey = + tweak: FieldElement + ): ECPublicKey = cryptoRuntime.tweakMultiply(publicKey, tweak) override def add(pk1: ECPrivateKey, pk2: ECPrivateKey): ECPrivateKey = @@ -148,12 +155,14 @@ trait CryptoUtil extends CryptoRuntime { override def combinePubKeys( pubKeys: Vector[ECPublicKey], - isCompressed: Boolean = true): ECPublicKey = + isCompressed: Boolean = true + ): ECPublicKey = cryptoRuntime.combinePubKeys(pubKeys, isCompressed) override def pubKeyTweakAdd( pubkey: ECPublicKey, - privkey: ECPrivateKey): ECPublicKey = + privkey: ECPrivateKey + ): ECPublicKey = cryptoRuntime.pubKeyTweakAdd(pubkey, privkey) override def isValidPubKey(pubKey: ECPublicKeyApi): Boolean = @@ -162,70 +171,82 @@ trait CryptoUtil extends CryptoRuntime { override def schnorrSign( dataToSign: ByteVector, privateKey: ECPrivateKey, - auxRand: ByteVector): SchnorrDigitalSignature = { + auxRand: ByteVector + ): SchnorrDigitalSignature = { val sig = cryptoRuntime.schnorrSign(dataToSign, privateKey, auxRand) assert( schnorrVerify(dataToSign, privateKey.schnorrPublicKey, sig), - "Something has gone wrong, a generated signature may have been corrupted") + "Something has gone wrong, a generated signature may have been corrupted" + ) sig } override def schnorrSignWithNonce( dataToSign: ByteVector, privateKey: ECPrivateKey, - nonceKey: ECPrivateKey): SchnorrDigitalSignature = { + nonceKey: ECPrivateKey + ): SchnorrDigitalSignature = { val sig = cryptoRuntime.schnorrSignWithNonce(dataToSign, privateKey, nonceKey) assert( schnorrVerify(dataToSign, privateKey.schnorrPublicKey, sig), - "Something has gone wrong, a generated signature may have been corrupted") + "Something has gone wrong, a generated signature may have been corrupted" + ) sig } override def schnorrVerify( data: ByteVector, schnorrPubKey: SchnorrPublicKey, - signature: SchnorrDigitalSignature): Boolean = + signature: SchnorrDigitalSignature + ): Boolean = cryptoRuntime.schnorrVerify(data, schnorrPubKey, signature) override def schnorrComputeSigPoint( data: ByteVector, nonce: SchnorrNonce, pubKey: SchnorrPublicKey, - compressed: Boolean): ECPublicKey = + compressed: Boolean + ): ECPublicKey = cryptoRuntime.schnorrComputeSigPoint(data, nonce, pubKey, compressed) override def adaptorSign( key: ECPrivateKey, adaptorPoint: ECPublicKey, msg: ByteVector, - auxRand: ByteVector): ECAdaptorSignature = + auxRand: ByteVector + ): ECAdaptorSignature = cryptoRuntime.adaptorSign(key, adaptorPoint, msg, auxRand) override def adaptorComplete( key: ECPrivateKey, - adaptorSignature: ECAdaptorSignature): ECDigitalSignature = + adaptorSignature: ECAdaptorSignature + ): ECDigitalSignature = cryptoRuntime.adaptorComplete(key, adaptorSignature) override def extractAdaptorSecret( signature: ECDigitalSignature, adaptorSignature: ECAdaptorSignature, - key: ECPublicKey): ECPrivateKey = + key: ECPublicKey + ): ECPrivateKey = cryptoRuntime.extractAdaptorSecret(signature, adaptorSignature, key) override def adaptorVerify( adaptorSignature: ECAdaptorSignature, key: ECPublicKey, msg: ByteVector, - adaptorPoint: ECPublicKey): Boolean = + adaptorPoint: ECPublicKey + ): Boolean = cryptoRuntime.adaptorVerify(adaptorSignature, key, msg, adaptorPoint) override def decodeSignature( - signature: ECDigitalSignature): (BigInt, BigInt) = + signature: ECDigitalSignature + ): (BigInt, BigInt) = cryptoRuntime.decodeSignature(signature) override def isValidSignatureEncoding( - signature: ECDigitalSignature): Boolean = + signature: ECDigitalSignature + ): Boolean = cryptoRuntime.isValidSignatureEncoding(signature) override def isDEREncoded(signature: ECDigitalSignature): Boolean = @@ -243,7 +264,8 @@ trait CryptoUtil extends CryptoRuntime { pass: ByteVector, salt: ByteVector, iterationCount: Int, - derivedKeyLength: Int): ByteVector = + derivedKeyLength: Int + ): ByteVector = cryptoRuntime.pbkdf2WithSha512(pass, salt, iterationCount, derivedKeyLength) } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/DERSignatureUtil.scala b/crypto/src/main/scala/org/bitcoins/crypto/DERSignatureUtil.scala index 78d47855f7..6e36814305 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/DERSignatureUtil.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/DERSignatureUtil.scala @@ -10,38 +10,42 @@ sealed abstract class DERSignatureUtil { /** Checks if this signature is encoded to DER correctly * https://crypto.stackexchange.com/questions/1795/how-can-i-convert-a-der-ecdsa-signature-to-asn-1 - * NOTE: This will fail if this signature contains the hash type appended to the end of it - * @return boolean representing if the signature is a valid + * NOTE: This will fail if this signature contains the hash type appended to + * the end of it + * @return + * boolean representing if the signature is a valid */ def isDEREncoded(signature: ECDigitalSignature): Boolean = isDEREncoded(signature.bytes) /** Checks if the bytes are encoded to DER correctly * https://crypto.stackexchange.com/questions/1795/how-can-i-convert-a-der-ecdsa-signature-to-asn-1 - * This will fail if this signature contains the hash type appended to the end of it - * @return boolean representing if the signature is a valid + * This will fail if this signature contains the hash type appended to the + * end of it + * @return + * boolean representing if the signature is a valid */ def isDEREncoded(bytes: ByteVector): Boolean = { - //signature is trivially valid if the signature is empty + // signature is trivially valid if the signature is empty if (bytes.nonEmpty && bytes.size < 9) false else if (bytes.nonEmpty) { - //first byte must be 0x30 + // first byte must be 0x30 val firstByteIs0x30 = bytes.head == 0x30 - //second byte must indicate the length of the remaining byte array + // second byte must indicate the length of the remaining byte array val signatureSize = bytes(1).toLong - //checks to see if the signature length is the same as the signatureSize val + // checks to see if the signature length is the same as the signatureSize val val signatureLengthIsCorrect = signatureSize == bytes .slice(2, bytes.size) .size - //third byte must be 0x02 + // third byte must be 0x02 val thirdByteIs0x02 = bytes(2) == 0x02 - //this is the size of the r value in the signature + // this is the size of the r value in the signature val rSize = bytes(3) val sOffset = rSize + 4 if (sOffset < 0 || sOffset >= bytes.length) { false } else { - //this 0x02 separates the r and s value in the signature + // this 0x02 separates the r and s value in the signature val second0x02Exists = bytes(sOffset) == 0x02 firstByteIs0x30 && signatureLengthIsCorrect && thirdByteIs0x02 && @@ -55,8 +59,8 @@ sealed abstract class DERSignatureUtil { def decodeSignature(signature: ECDigitalSignature): (BigInt, BigInt) = decodeSignature(signature.bytes) - /** Decodes the given sequence of bytes into it's r and s points - * throws an exception if the given sequence of bytes is not a DER encoded signature + /** Decodes the given sequence of bytes into it's r and s points throws an + * exception if the given sequence of bytes is not a DER encoded signature */ def decodeSignature(bytes: ByteVector): (BigInt, BigInt) = { DERSignatureUtil.parseDERLax(bytes) match { @@ -65,14 +69,18 @@ sealed abstract class DERSignatureUtil { } } - /** This functions implements the strict der encoding rules that were created in BIP66 + /** This functions implements the strict der encoding rules that were created + * in BIP66 * [[https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki]] * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L98]] * - * IMPORTANT: This function assumes signature has a SigHash byte and will fail if not! + * IMPORTANT: This function assumes signature has a SigHash byte and will + * fail if not! * - * @param signature the signature to check if they are strictly der encoded - * @return boolean indicating whether the signature was der encoded or not + * @param signature + * the signature to check if they are strictly der encoded + * @return + * boolean indicating whether the signature was der encoded or not */ def isValidSignatureEncoding(signature: ECDigitalSignature): Boolean = { signature match { @@ -82,14 +90,17 @@ sealed abstract class DERSignatureUtil { } } - /** This functions implements the strict der encoding rules that were created in BIP66 - * https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki + /** This functions implements the strict der encoding rules that were created + * in BIP66 https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki * [[https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L98]] * - * IMPORTANT: This function assumes bytes has a SigHash byte and will fail if not! + * IMPORTANT: This function assumes bytes has a SigHash byte and will fail if + * not! * - * @param bytes the bytes to check if they are strictly der encoded - * @return boolean indicating whether the bytes were der encoded or not + * @param bytes + * the bytes to check if they are strictly der encoded + * @return + * boolean indicating whether the bytes were der encoded or not */ def isValidSignatureEncoding(bytes: ByteVector): Boolean = { // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash] @@ -104,87 +115,89 @@ sealed abstract class DERSignatureUtil { // * sighash: 1-byte value indicating what data is hashed (not part of the DER // signature) - //there is a caveat here that this function is trivially true if the - //empty signature is given to us, aka 0 bytes. + // there is a caveat here that this function is trivially true if the + // empty signature is given to us, aka 0 bytes. if (bytes.size == 0) return true if (bytes.size < 9) return false - //logger.debug("signature is the minimum size for strict der encoding") + // logger.debug("signature is the minimum size for strict der encoding") if (bytes.size > 73) return false - //logger.debug("signature is under the maximum size for strict der encoding") + // logger.debug("signature is under the maximum size for strict der encoding") // A signature is of type 0x30 (compound) if (bytes.head != 0x30) return false - //logger.debug("First byte is 0x30") + // logger.debug("First byte is 0x30") // Make sure the length covers the entire signature. if (bytes(1) != bytes.size - 3) return false - //logger.debug("Signature length covers the entire signature") + // logger.debug("Signature length covers the entire signature") val rSize = bytes(3) - //logger.debug("rSize: " + rSize) + // logger.debug("rSize: " + rSize) // Make sure the length of the S element is still inside the signature. if (5 + rSize >= bytes.size) return false - //logger.debug("Length of S element is contained in the signature") + // logger.debug("Length of S element is contained in the signature") // Extract the length of the S element. val sSize = bytes(5 + rSize) - //logger.debug("sSize: " + sSize) + // logger.debug("sSize: " + sSize) // Verify that the length of the signature matches the sum of the length // of the elements. if ((rSize + sSize + 7) != bytes.size) return false - //logger.debug("Verify that the length of the signature matches the sum of the length of the elements.") + // logger.debug("Verify that the length of the signature matches the sum of the length of the elements.") // Check whether the R element is an integer. if (bytes(2) != 0x02) return false - //logger.debug("R element is an integer") + // logger.debug("R element is an integer") // Zero-length integers are not allowed for R. if (rSize == 0) return false - //logger.debug("r is not a zero length integer") + // logger.debug("r is not a zero length integer") // Negative numbers are not allowed for R. if ((bytes(4) & 0x80) != 0) return false - //logger.debug("r is not a negative number") + // logger.debug("r is not a negative number") // Null bytes at the start of R are not allowed, unless R would // otherwise be interpreted as a negative number. if (rSize > 1 && (bytes(4) == 0x00) && (bytes(5) & 0x80) == 0) return false - //logger.debug("There were not any null bytes at the start of R") + // logger.debug("There were not any null bytes at the start of R") // Check whether the S element is an integer. if (bytes(rSize + 4) != 0x02) return false - //logger.debug("The S element is an integer") + // logger.debug("The S element is an integer") // Zero-length integers are not allowed for S. if (sSize == 0) return false - //logger.debug("S was not a zero length integer") + // logger.debug("S was not a zero length integer") // Negative numbers are not allowed for S. if ((bytes(rSize + 6) & 0x80) != 0) return false - //logger.debug("s was not a negative number") + // logger.debug("s was not a negative number") // Null bytes at the start of S are not allowed, unless S would otherwise be // interpreted as a negative number. if ( sSize > 1 && (bytes(rSize + 6) == 0x00) && (bytes(rSize + 7) & 0x80) == 0 ) return false - //logger.debug("There were not any null bytes at the start of S") - //if we made it to this point without returning false this must be a valid strictly encoded der sig + // logger.debug("There were not any null bytes at the start of S") + // if we made it to this point without returning false this must be a valid strictly encoded der sig true } /** Requires the S value in signatures to be the low version of the S value * https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#low-s-values-in-signatures - * @return if the S value is the low version + * @return + * if the S value is the low version */ def isLowS(signature: ECDigitalSignature): Boolean = isLowS(signature.bytes) /** Requires the S value in signatures to be the low version of the S value * https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#low-s-values-in-signatures - * @return if the S value is the low version + * @return + * if the S value is the low version */ def isLowS(signature: ByteVector): Boolean = { val result = Try { @@ -197,30 +210,36 @@ sealed abstract class DERSignatureUtil { } } - /** Checks if the given digital signature uses a low s value, if it does not it converts it to a low s value and returns it */ + /** Checks if the given digital signature uses a low s value, if it does not + * it converts it to a low s value and returns it + */ def lowS(signature: ECDigitalSignature): ECDigitalSignature = { val sigLowS = if (isLowS(signature)) signature else - ECDigitalSignature(signature.r, - CryptoParams.getN.subtract(signature.s.bigInteger)) + ECDigitalSignature( + signature.r, + CryptoParams.getN.subtract(signature.s.bigInteger) + ) require(DERSignatureUtil.isLowS(sigLowS)) sigLowS } - /** Scala implementation of https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.cpp#L16-L165 + /** Scala implementation of + * https://github.com/bitcoin/bitcoin/blob/master/src/pubkey.cpp#L16-L165 * * Parses correctly as well as poorly encoded DER signatures. * - * "Supported violations include negative integers, excessive padding, garbage - * at the end, and overly long length descriptors." + * "Supported violations include negative integers, excessive padding, + * garbage at the end, and overly long length descriptors." * * The signatures must still follow the following general format: * - * 0x30 | total length | 0x02 | R length | [R] \ 0x02 | S length | [S] + * 0x30 | total length | 0x02 | R length | [R] \ 0x02 | S length | [S] * - * IMPORTANT: Do not use this without further validation when validating blocks - * because BIP 66 requires that new signatures are verified to be strict DER encodings. + * IMPORTANT: Do not use this without further validation when validating + * blocks because BIP 66 requires that new signatures are verified to be + * strict DER encodings. */ def parseDERLax(input: ByteVector): Option[(BigInt, BigInt)] = { val iterator = input.toIterable.iterator.buffered diff --git a/crypto/src/main/scala/org/bitcoins/crypto/DLEQUtil.scala b/crypto/src/main/scala/org/bitcoins/crypto/DLEQUtil.scala index 8c0ead1751..5f5819a15a 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/DLEQUtil.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/DLEQUtil.scala @@ -8,27 +8,19 @@ import scodec.bits.ByteVector * Note that the naming is not entirely consistent between the specification * and this file in hopes of making this code more readable. * - * The naming in this file more closely matches the naming in the secp256k1-zkp implementation: + * The naming in this file more closely matches the naming in the secp256k1-zkp + * implementation: * https://github.com/ElementsProject/secp256k1-zkp/tree/master/src/modules/ecdsa_adaptor * - * Legend: - * x <> fe - * X <> p1/point - * y <> adaptorSecret - * Y <> adaptorPoint/adaptor - * Z <> p2/tweakedPoint - * a <> k - * A_G <> r1 - * A_Y <> r2 - * b <> e - * c <> s - * proof <> (e, s) + * Legend: x <> fe X <> p1/point y <> adaptorSecret Y <> adaptorPoint/adaptor Z + * <> p2/tweakedPoint a <> k A_G <> r1 A_Y <> r2 b <> e c <> s proof <> (e, s) */ object DLEQUtil { def dleqPair( fe: FieldElement, - adaptorPoint: ECPublicKey): (ECPublicKey, ECPublicKey) = { + adaptorPoint: ECPublicKey + ): (ECPublicKey, ECPublicKey) = { val point = fe.getPublicKey val tweakedPoint = adaptorPoint.multiply(fe) @@ -43,16 +35,19 @@ object DLEQUtil { adaptorPoint: ECPublicKey, point: ECPublicKey, tweakedPoint: ECPublicKey, - auxRand: ByteVector): FieldElement = { + auxRand: ByteVector + ): FieldElement = { val hash = CryptoUtil .sha256(point.bytes ++ tweakedPoint.bytes) .bytes - AdaptorUtil.adaptorNonce(hash, - fe.toPrivateKey, - adaptorPoint, - "DLEQ", - auxRand) + AdaptorUtil.adaptorNonce( + hash, + fe.toPrivateKey, + adaptorPoint, + "DLEQ", + auxRand + ) } /** Computes the challenge hash value for dleqProve as specified in @@ -63,22 +58,26 @@ object DLEQUtil { r1: ECPublicKey, r2: ECPublicKey, p1: ECPublicKey, - p2: ECPublicKey): ByteVector = { + p2: ECPublicKey + ): ByteVector = { CryptoUtil .sha256DLEQ( p1.bytes ++ adaptorPoint.bytes ++ - p2.bytes ++ r1.bytes ++ r2.bytes) + p2.bytes ++ r1.bytes ++ r2.bytes + ) .bytes } - /** Proves that the DLOG_G(R') = DLOG_Y(R) (= fe) - * For a full description, see https://cs.nyu.edu/courses/spring07/G22.3220-001/lec3.pdf - * @see https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#proving + /** Proves that the DLOG_G(R') = DLOG_Y(R) (= fe) For a full description, see + * https://cs.nyu.edu/courses/spring07/G22.3220-001/lec3.pdf + * @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#proving */ def dleqProve( fe: FieldElement, adaptorPoint: ECPublicKey, - auxRand: ByteVector): (FieldElement, FieldElement) = { + auxRand: ByteVector + ): (FieldElement, FieldElement) = { require(!fe.isZero, "Input field element cannot be zero.") // (fe*G, fe*Y) @@ -113,14 +112,16 @@ object DLEQUtil { } /** Verifies a proof that the DLOG_G of P1 equals the DLOG_adaptor of P2 - * @see https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#verifying + * @see + * https://github.com/discreetlogcontracts/dlcspecs/blob/d01595b70269d4204b05510d19bba6a4f4fcff23/ECDSA-adaptor.md#verifying */ def dleqVerify( s: FieldElement, e: FieldElement, p1: ECPublicKey, adaptor: ECPublicKey, - p2: ECPublicKey): Boolean = { + p2: ECPublicKey + ): Boolean = { val r1 = p1.multiply(e.negate).add(s.getPublicKey) val r2 = p2.multiply(e.negate).add(adaptor.multiply(s)) val challengeHash = dleqChallengeHash(adaptor, r1, r2, p1, p2) diff --git a/crypto/src/main/scala/org/bitcoins/crypto/ECAdaptorSignature.scala b/crypto/src/main/scala/org/bitcoins/crypto/ECAdaptorSignature.scala index 3d9281f044..dd9b086c81 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/ECAdaptorSignature.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/ECAdaptorSignature.scala @@ -3,8 +3,10 @@ package org.bitcoins.crypto import scodec.bits.ByteVector case class ECAdaptorSignature(bytes: ByteVector) extends NetworkElement { - require(bytes.length == 162, - s"Adaptor signature must be 162 bytes, got $bytes") + require( + bytes.length == 162, + s"Adaptor signature must be 162 bytes, got $bytes" + ) val (adaptedSig: ByteVector, dleqProof: ByteVector) = bytes.splitAt(98) @@ -29,7 +31,8 @@ object ECAdaptorSignature extends Factory[ECAdaptorSignature] { untweakedNonce: ECPublicKey, adaptedS: FieldElement, dleqProofE: FieldElement, - dleqProofS: FieldElement): ECAdaptorSignature = { + dleqProofS: FieldElement + ): ECAdaptorSignature = { fromBytes( tweakedNonce.bytes ++ untweakedNonce.bytes ++ adaptedS.bytes ++ dleqProofE.bytes ++ dleqProofS.bytes diff --git a/crypto/src/main/scala/org/bitcoins/crypto/ECDigitalSignature.scala b/crypto/src/main/scala/org/bitcoins/crypto/ECDigitalSignature.scala index d0f3c1af88..9c8aa0a186 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/ECDigitalSignature.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/ECDigitalSignature.scala @@ -22,7 +22,8 @@ sealed abstract class ECDigitalSignature extends NetworkElement { /** Checks if this signature is encoded to DER correctly * https://crypto.stackexchange.com/questions/1795/how-can-i-convert-a-der-ecdsa-signature-to-asn-1 - * @return boolean representing if the signature is a valid + * @return + * boolean representing if the signature is a valid */ def isDEREncoded: Boolean = CryptoUtil.isDEREncoded(this) @@ -31,9 +32,10 @@ sealed abstract class ECDigitalSignature extends NetworkElement { */ def isStrictEncoded: Boolean = CryptoUtil.isValidSignatureEncoding(this) - /** Decodes the digital signature into it's r and s points - * throws an exception if the given sequence of bytes is not a DER encoded signature - * @return the (r,s) values for the elliptic curve digital signature + /** Decodes the digital signature into it's r and s points throws an exception + * if the given sequence of bytes is not a DER encoded signature + * @return + * the (r,s) values for the elliptic curve digital signature */ lazy val decodeSignature: (BigInt, BigInt) = CryptoUtil.decodeSignature(this) @@ -43,9 +45,8 @@ sealed abstract class ECDigitalSignature extends NetworkElement { decodeSignature._1 } - /** If we need to do serialization with the - * r value, you should use this. It will pad - * the byte vector so we have exactly 32 bytes + /** If we need to do serialization with the r value, you should use this. It + * will pad the byte vector so we have exactly 32 bytes * @return */ def rBytes: ByteVector = { @@ -54,9 +55,8 @@ sealed abstract class ECDigitalSignature extends NetworkElement { padded } - /** If we need to do serialization with the - * s value, you should use this. It will pad - * the byte vector so we have exactly 32 bytes + /** If we need to do serialization with the s value, you should use this. It + * will pad the byte vector so we have exactly 32 bytes * @return */ def s: BigInt = { @@ -69,9 +69,8 @@ sealed abstract class ECDigitalSignature extends NetworkElement { padded } - /** Creates a ByteVector with only - * the 32byte r value and 32 byte s value - * in the vector + /** Creates a ByteVector with only the 32byte r value and 32 byte s value in + * the vector */ def toRawRS: ByteVector = { rBytes ++ sBytes @@ -88,8 +87,10 @@ sealed abstract class ECDigitalSignature extends NetworkElement { } def appendHashType(hashType: HashType): ECDigitalSignature = { - require(this.hashTypeOpt.isEmpty, - "Cannot append HashType to signature which already has HashType") + require( + this.hashTypeOpt.isEmpty, + "Cannot append HashType to signature which already has HashType" + ) val bytesWithHashType = bytes.:+(hashType.byte) ECDigitalSignature.fromBytes(bytesWithHashType) @@ -102,10 +103,9 @@ case object EmptyDigitalSignature extends ECDigitalSignature { override def s: BigInt = r } -/** The point of this case object is to help with fee estimation - * an average [[ECDigitalSignature]] is 72 bytes in size - * Technically this number can vary, 72 bytes is the most - * likely though according to +/** The point of this case object is to help with fee estimation an average + * [[ECDigitalSignature]] is 72 bytes in size Technically this number can vary, + * 72 bytes is the most likely though according to * https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm */ case object DummyECDigitalSignature extends ECDigitalSignature { @@ -114,9 +114,9 @@ case object DummyECDigitalSignature extends ECDigitalSignature { override def s: BigInt = r } -/** The point of this case object is to help with fee estimation - * when using low r signing. Technically this number can vary, - * 71 bytes is the most likely when using low r signing +/** The point of this case object is to help with fee estimation when using low + * r signing. Technically this number can vary, 71 bytes is the most likely + * when using low r signing */ case object LowRDummyECDigitalSignature extends ECDigitalSignature { override val bytes: ByteVector = ByteVector(Array.fill(71)(0.toByte)) @@ -130,7 +130,7 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] { extends ECDigitalSignature override def fromBytes(bytes: ByteVector): ECDigitalSignature = { - //this represents the empty signature + // this represents the empty signature if (bytes.size == 1 && bytes.head == 0x0) EmptyDigitalSignature else if (bytes.size == 0) EmptyDigitalSignature @@ -139,33 +139,39 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] { else if (bytes == LowRDummyECDigitalSignature.bytes) LowRDummyECDigitalSignature else { - //make sure the signature follows BIP62's low-s value - //https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures - //bitcoinj implementation - //https://github.com/bitcoinj/bitcoinj/blob/1e66b9a8e38d9ad425507bf5f34d64c5d3d23bb8/core/src/main/java/org/bitcoinj/core/ECKey.java#L551 + // make sure the signature follows BIP62's low-s value + // https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures + // bitcoinj implementation + // https://github.com/bitcoinj/bitcoinj/blob/1e66b9a8e38d9ad425507bf5f34d64c5d3d23bb8/core/src/main/java/org/bitcoinj/core/ECKey.java#L551 ECDigitalSignatureImpl(bytes) } } /** Reads a (DER encoded) ECDigitalSignature from the front of a ByteVector * This method is also useful if you want to parse a ecdsa digital signature - * but remove the [[HashType]] that the bitcoin protocol appends to the end of a signature + * but remove the [[HashType]] that the bitcoin protocol appends to the end + * of a signature */ def fromFrontOfBytes(bytes: ByteVector): ECDigitalSignature = { val sigWithExtra = fromBytes(bytes) val sig = fromRS(sigWithExtra.r, sigWithExtra.s) - require(bytes.startsWith(sig.bytes), - s"Received weirdly encoded signature at beginning of $bytes") + require( + bytes.startsWith(sig.bytes), + s"Received weirdly encoded signature at beginning of $bytes" + ) sig } - /** Reads a (DER encoded with sighash) ECDigitalSignature from the front of a ByteVector */ + /** Reads a (DER encoded with sighash) ECDigitalSignature from the front of a + * ByteVector + */ def fromFrontOfBytesWithSigHash(bytes: ByteVector): ECDigitalSignature = { val sigWithoutSigHash = fromFrontOfBytes(bytes) ECDigitalSignature( - sigWithoutSigHash.bytes :+ bytes.drop(sigWithoutSigHash.byteSize).head) + sigWithoutSigHash.bytes :+ bytes.drop(sigWithoutSigHash.byteSize).head + ) } def apply(r: BigInt, s: BigInt): ECDigitalSignature = fromRS(r, s) @@ -173,12 +179,15 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] { def apply(r: BigInt, s: BigInt, hashType: HashType): ECDigitalSignature = fromRS(r, s, hashType) - /** Takes in the r and s component of a digital signature and gives back a ECDigitalSignature object - * The ECDigitalSignature object complies with strict der encoding as per BIP62 - * note: That the hash type for the signature CANNOT be added to the digital signature + /** Takes in the r and s component of a digital signature and gives back a + * ECDigitalSignature object The ECDigitalSignature object complies with + * strict der encoding as per BIP62 note: That the hash type for the + * signature CANNOT be added to the digital signature * - * @param r the r component of the digital signature - * @param s the s component of the digital signature + * @param r + * the r component of the digital signature + * @param s + * the s component of the digital signature * @return */ def fromRS(r: BigInt, s: BigInt): ECDigitalSignature = { @@ -186,10 +195,13 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] { val totalSize = 4 + rsSize val bytes: ByteVector = { ByteVector( - Array(0x30.toByte, - totalSize.toByte, - 0x2.toByte, - r.toByteArray.length.toByte)) + Array( + 0x30.toByte, + totalSize.toByte, + 0x2.toByte, + r.toByteArray.length.toByte + ) + ) .++(ByteVector(r.toByteArray)) .++(ByteVector(Array(0x2.toByte, s.toByteArray.length.toByte))) .++(ByteVector(s.toByteArray)) @@ -198,43 +210,44 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] { fromBytes(bytes) } - /** Takes in the r and s component of a digital signature along with a HashType and gives - * back a ECDigitalSignature object - * The ECDigitalSignature object complies with strict der encoding as per BIP62 - * note: That the hash type for the signature CANNOT be added to the digital signature + /** Takes in the r and s component of a digital signature along with a + * HashType and gives back a ECDigitalSignature object The ECDigitalSignature + * object complies with strict der encoding as per BIP62 note: That the hash + * type for the signature CANNOT be added to the digital signature * - * @param r the r component of the digital signature - * @param s the s component of the digital signature - * @param hashType The HashType byte to append + * @param r + * the r component of the digital signature + * @param s + * the s component of the digital signature + * @param hashType + * The HashType byte to append * @return */ def fromRS(r: BigInt, s: BigInt, hashType: HashType): ECDigitalSignature = { fromRS(r, s).appendHashType(hashType) } - /** Reads a 64 byte bytevector and assumes - * the first 32 bytes in the R value, + /** Reads a 64 byte bytevector and assumes the first 32 bytes in the R value, * the second 32 is the value */ def fromRS(byteVector: ByteVector): ECDigitalSignature = { require( byteVector.length == 64, - s"Incorrect size for reading a ECDigital signature from a bytevec, got ${byteVector.length}") + s"Incorrect size for reading a ECDigital signature from a bytevec, got ${byteVector.length}" + ) val r = BigInt(1, byteVector.take(32).toArray) val s = BigInt(1, byteVector.takeRight(32).toArray) fromRS(r, s) } - /** Reads a 64 byte bytevector and assumes - * the first 32 bytes in the R value, + /** Reads a 64 byte bytevector and assumes the first 32 bytes in the R value, * the second 32 is the value */ def fromRS(byteVector: ByteVector, hashType: HashType): ECDigitalSignature = { fromRS(byteVector).appendHashType(hashType) } - /** Reads a 64 byte bytevector and assumes - * the first 32 bytes in the R value, + /** Reads a 64 byte bytevector and assumes the first 32 bytes in the R value, * the second 32 is the value */ def fromRS(hex: String): ECDigitalSignature = { @@ -242,17 +255,15 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] { fromRS(bytes) } - /** Reads a 64 byte bytevector and assumes - * the first 32 bytes in the R value, + /** Reads a 64 byte bytevector and assumes the first 32 bytes in the R value, * the second 32 is the value */ def fromRS(hex: String, hashType: HashType): ECDigitalSignature = { fromRS(hex).appendHashType(hashType) } - /** Minimally encoded zero signature - * This will NOT be 64 bytes in length, it will be much less - * due to the DER encoding + /** Minimally encoded zero signature This will NOT be 64 bytes in length, it + * will be much less due to the DER encoding */ val minimalEncodedZeroSig: ECDigitalSignature = fromRS(0, 0) } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/ECKey.scala b/crypto/src/main/scala/org/bitcoins/crypto/ECKey.scala index e380cc25c2..e3b8a78b03 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/ECKey.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/ECKey.scala @@ -5,10 +5,13 @@ import scodec.bits.ByteVector import java.math.BigInteger import scala.util.Try -/** Represents the raw bytes which are meant to represent an ECKey without deserializing. */ +/** Represents the raw bytes which are meant to represent an ECKey without + * deserializing. + */ sealed abstract class ECKeyBytes extends NetworkElement -/** Represents a serialization sensitive ECPrivateKey (such as is used in WIF). */ +/** Represents a serialization sensitive ECPrivateKey (such as is used in WIF). + */ case class ECPrivateKeyBytes(bytes: ByteVector, isCompressed: Boolean = true) extends ECKeyBytes with MaskedToString { @@ -44,8 +47,9 @@ object ECPrivateKeyBytes extends Factory[ECPrivateKeyBytes] { } } -/** Represents any type which wraps public key bytes which can be used for ECDSA verification. - * Should always be instantiated with class X extends PublicKey[X]. +/** Represents any type which wraps public key bytes which can be used for ECDSA + * verification. Should always be instantiated with class X extends + * PublicKey[X]. */ sealed trait ECPublicKeyApi extends PublicKey { @@ -76,7 +80,9 @@ sealed trait ECPublicKeyApi extends PublicKey { /** Returns true if the underlying bytes being wrapped are decompressed */ def isDecompressed: Boolean = bytes.size == 65 - /** Returns true if the underlying bytes being wrapped are valid according to secp256k1 */ + /** Returns true if the underlying bytes being wrapped are valid according to + * secp256k1 + */ def isFullyValid: Boolean = { CryptoUtil.isValidPubKey(this) } @@ -108,7 +114,9 @@ sealed trait ECPublicKeyApi extends PublicKey { } } -/** Wraps raw ECPublicKey bytes without doing any validation or deserialization (may be invalid). */ +/** Wraps raw ECPublicKey bytes without doing any validation or deserialization + * (may be invalid). + */ case class ECPublicKeyBytes(bytes: ByteVector) extends ECKeyBytes with ECPublicKeyApi { @@ -133,17 +141,16 @@ object ECPublicKeyBytes extends Factory[ECPublicKeyBytes] { } } -/** Created by chris on 2/16/16. - * Represents a fully parsed and validated ECDSA private or public key. +/** Created by chris on 2/16/16. Represents a fully parsed and validated ECDSA + * private or public key. */ sealed abstract class BaseECKey extends NetworkElement -/** Created by chris on 2/16/16. - * A valid deserialized private key. +/** Created by chris on 2/16/16. A valid deserialized private key. * - * Note that there is no notion of compressed vs. decompressed - * as there is in Wallet Import Format (WIF), if dealing with - * external wallets then ECPrivateKeyBytes may be needed. + * Note that there is no notion of compressed vs. decompressed as there is in + * Wallet Import Format (WIF), if dealing with external wallets then + * ECPrivateKeyBytes may be needed. */ case class ECPrivateKey(bytes: ByteVector) extends BaseECKey @@ -152,8 +159,10 @@ case class ECPrivateKey(bytes: ByteVector) require(CryptoUtil.secKeyVerify(bytes), s"Invalid key, hex: ${bytes.toHex}") /** Signs a given sequence of bytes with the signingKey - * @param dataToSign the bytes to be signed - * @return the digital signature + * @param dataToSign + * the bytes to be signed + * @return + * the digital signature */ override def sign(dataToSign: ByteVector): ECDigitalSignature = { CryptoUtil.sign(this, dataToSign) @@ -163,7 +172,8 @@ case class ECPrivateKey(bytes: ByteVector) override def signWithEntropy( bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature = { + entropy: ByteVector + ): ECDigitalSignature = { CryptoUtil.signWithEntropy(this, bytes, entropy) } @@ -174,31 +184,36 @@ case class ECPrivateKey(bytes: ByteVector) def schnorrSign( dataToSign: ByteVector, - auxRand: ByteVector): SchnorrDigitalSignature = { + auxRand: ByteVector + ): SchnorrDigitalSignature = { CryptoUtil.schnorrSign(dataToSign, this, auxRand) } def schnorrSignWithNonce( dataToSign: ByteVector, - nonce: ECPrivateKey): SchnorrDigitalSignature = { + nonce: ECPrivateKey + ): SchnorrDigitalSignature = { CryptoUtil.schnorrSignWithNonce(dataToSign, this, nonce) } override def adaptorSign( adaptorPoint: ECPublicKey, msg: ByteVector, - auxRand: ByteVector): ECAdaptorSignature = { + auxRand: ByteVector + ): ECAdaptorSignature = { CryptoUtil.adaptorSign(this, adaptorPoint, msg, auxRand) } def completeAdaptorSignature( - adaptorSignature: ECAdaptorSignature): ECDigitalSignature = { + adaptorSignature: ECAdaptorSignature + ): ECDigitalSignature = { CryptoUtil.adaptorComplete(this, adaptorSignature) } def completeAdaptorSignature( adaptorSignature: ECAdaptorSignature, - hashTypeByte: Byte): ECDigitalSignature = { + hashTypeByte: Byte + ): ECDigitalSignature = { val completedSig = completeAdaptorSignature(adaptorSignature) ECDigitalSignature(completedSig.bytes ++ ByteVector.fromByte(hashTypeByte)) } @@ -221,7 +236,8 @@ case class ECPrivateKey(bytes: ByteVector) // CryptoParams.curve.getN private val N: BigInteger = new BigInteger( - "115792089237316195423570985008687907852837564279074904382605163141518161494337") + "115792089237316195423570985008687907852837564279074904382605163141518161494337" + ) def negate: ECPrivateKey = { val negPrivKeyNum = N.subtract(new BigInteger(1, bytes.toArray)) @@ -265,20 +281,27 @@ object ECPrivateKey extends Factory[ECPrivateKey] { } else throw new IllegalArgumentException( "Private keys must be 32 in size, got: " + - CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size) + CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size + ) } def fromFieldElement(fieldElement: FieldElement): ECPrivateKey = { fieldElement.toPrivateKey } - /** Generates a fresh [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]] that has not been used before. */ + /** Generates a fresh [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]] that + * has not been used before. + */ def apply(): ECPrivateKey = ECPrivateKey.freshPrivateKey - /** Generates a fresh [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]] that has not been used before. */ + /** Generates a fresh [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]] that + * has not been used before. + */ def freshPrivateKey: ECPrivateKey = CryptoUtil.freshPrivateKey - /** Generates [[num]] private keys that are ordered by [[ECPrivateKey.schnorrNonce]] */ + /** Generates [[num]] private keys that are ordered by + * [[ECPrivateKey.schnorrNonce]] + */ def generateNonceOrderedPrivKeys(num: Int): Vector[ECPrivateKey] = { val privKeys = 0.until(num).map(_ => ECPrivateKey.freshPrivateKey).toVector val sortByNonce = privKeys @@ -289,24 +312,27 @@ object ECPrivateKey extends Factory[ECPrivateKey] { } } -/** Created by chris on 2/16/16. - * A valid deserialized ECDSA public key. +/** Created by chris on 2/16/16. A valid deserialized ECDSA public key. * - * This class wraps some underlying _bytes but after checking that these _bytes are valid, - * all serializations (compressed and decompressed) of this public key are (lazily) computed - * where the decompressed version is used internally for computation and the compressed version - * is provided by the NetworkElement::bytes member. + * This class wraps some underlying _bytes but after checking that these _bytes + * are valid, all serializations (compressed and decompressed) of this public + * key are (lazily) computed where the decompressed version is used internally + * for computation and the compressed version is provided by the + * NetworkElement::bytes member. * - * Note that 0x00 is not a valid ECPublicKey but is a valid SecpPoint meaning that if you are - * doing computations on public key (points) that may have intermediate 0x00 values, then you - * should convert using toPoint, do computation, and then convert back toPublicKey in the end. + * Note that 0x00 is not a valid ECPublicKey but is a valid SecpPoint meaning + * that if you are doing computations on public key (points) that may have + * intermediate 0x00 values, then you should convert using toPoint, do + * computation, and then convert back toPublicKey in the end. */ case class ECPublicKey(bytes: ByteVector) extends BaseECKey with ECPublicKeyApi { require(isFullyValid, s"Invalid public key: ${bytes}: $decompressedBytesT") - /** Converts this public key into the raw underlying point on secp256k1 for computation. */ + /** Converts this public key into the raw underlying point on secp256k1 for + * computation. + */ def toPoint: SecpPointFinite = SecpPoint.fromPublicKey(this) override private[crypto] def fromBytes(bytes: ByteVector): this.type = { @@ -315,13 +341,15 @@ case class ECPublicKey(bytes: ByteVector) def schnorrVerify( data: ByteVector, - signature: SchnorrDigitalSignature): Boolean = { + signature: SchnorrDigitalSignature + ): Boolean = { schnorrPublicKey.verify(data, signature) } def schnorrComputePoint( data: ByteVector, - nonce: SchnorrNonce): ECPublicKey = { + nonce: SchnorrNonce + ): ECPublicKey = { schnorrPublicKey.computeSigPoint(data, nonce) } @@ -332,13 +360,15 @@ case class ECPublicKey(bytes: ByteVector) def adaptorVerify( msg: ByteVector, adaptorPoint: ECPublicKey, - adaptorSignature: ECAdaptorSignature): Boolean = { + adaptorSignature: ECAdaptorSignature + ): Boolean = { CryptoUtil.adaptorVerify(adaptorSignature, this, msg, adaptorPoint) } def extractAdaptorSecret( adaptorSignature: ECAdaptorSignature, - signature: ECDigitalSignature): ECPrivateKey = { + signature: ECDigitalSignature + ): ECPrivateKey = { CryptoUtil.extractAdaptorSecret(signature, adaptorSignature, this) } @@ -363,8 +393,8 @@ case class ECPublicKey(bytes: ByteVector) } /** Returns this same ECPublicKey wrapping the underlying compressed _bytes. - * This function doesn't really have any use, don't use it probably. - * Same for decompressed. + * This function doesn't really have any use, don't use it probably. Same for + * decompressed. */ override lazy val compressed: this.type = { if (isCompressed || bytes == ByteVector.fromByte(0x00)) { @@ -386,7 +416,9 @@ case class ECPublicKey(bytes: ByteVector) decompressedBytes.toHex } - /** Converts this ECPublicKey to raw ECPublicKeyBytes using the specified serialization. */ + /** Converts this ECPublicKey to raw ECPublicKeyBytes using the specified + * serialization. + */ def toPublicKeyBytes(isCompressed: Boolean = true): ECPublicKeyBytes = { val bs = if (isCompressed) compressedBytes else decompressedBytes ECPublicKeyBytes(bs) @@ -399,8 +431,9 @@ case class ECPublicKey(bytes: ByteVector) } } - /** Adds this ECPublicKey to another as points and returns the resulting ECPublicKey. - * If you are adding more than two points together use CryptoUtil.combinePubKeys instead. + /** Adds this ECPublicKey to another as points and returns the resulting + * ECPublicKey. If you are adding more than two points together use + * CryptoUtil.combinePubKeys instead. */ def add(otherKey: ECPublicKey): ECPublicKey = CryptoUtil.add(this, otherKey) @@ -430,6 +463,8 @@ object ECPublicKey extends Factory[ECPublicKey] { val dummy: ECPublicKey = FieldElement.one.getPublicKey - /** Generates a fresh [[org.bitcoins.crypto.ECPublicKey ECPublicKey]] that has not been used before. */ + /** Generates a fresh [[org.bitcoins.crypto.ECPublicKey ECPublicKey]] that has + * not been used before. + */ def freshPublicKey: ECPublicKey = ECPrivateKey.freshPrivateKey.publicKey } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/Factory.scala b/crypto/src/main/scala/org/bitcoins/crypto/Factory.scala index 998a005abc..1e93f3795b 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/Factory.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/Factory.scala @@ -4,23 +4,23 @@ import scodec.bits.ByteVector import scala.util.Try -/** Created by chris on 2/26/16. - * Trait to implement ubiquitous factory functions across our codebase +/** Created by chris on 2/26/16. Trait to implement ubiquitous factory functions + * across our codebase */ abstract class Factory[+T] { /** Creates a T out of a hex string. */ def fromHex(hex: String): T = fromBytes(CryptoBytesUtil.decodeHex(hex)) - /** Deserializes the given hex string to a T - * If the hex is not correct, [[None]] is returned + /** Deserializes the given hex string to a T If the hex is not correct, + * [[None]] is returned */ def fromHexOpt(hex: String): Option[T] = { fromHexT(hex).toOption } - /** Deserializes the given hex string - * if the hex is not correct, we give you a [[Failure]] + /** Deserializes the given hex string if the hex is not correct, we give you a + * [[Failure]] */ def fromHexT(hex: String): Try[T] = { Try(fromHex(hex)) @@ -32,15 +32,15 @@ abstract class Factory[+T] { /** Creates a T out of a sequence of bytes. */ def fromBytes(bytes: ByteVector): T - /** Deserializes the given [[ByteVector]] to a T - * If the [[ByteVector]] is not correct, [[None]] is returned + /** Deserializes the given [[ByteVector]] to a T If the [[ByteVector]] is not + * correct, [[None]] is returned */ def fromBytesOpt(bytes: ByteVector): Option[T] = { fromBytesT(bytes).toOption } - /** Deserializes the given [[ByteVector]] string - * if the [[ByteVector]] is not correct, we give you a [[Failure]] + /** Deserializes the given [[ByteVector]] string if the [[ByteVector]] is not + * correct, we give you a [[Failure]] */ def fromBytesT(bytes: ByteVector): Try[T] = { Try(fromBytes(bytes)) diff --git a/crypto/src/main/scala/org/bitcoins/crypto/FieldElement.scala b/crypto/src/main/scala/org/bitcoins/crypto/FieldElement.scala index 0991fabbd0..642b390664 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/FieldElement.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/FieldElement.scala @@ -4,7 +4,8 @@ import scodec.bits.ByteVector import scala.util.Try -/** Represents integers modulo the secp256k1 field size: pow(2,256) - 0x1000003D1. +/** Represents integers modulo the secp256k1 field size: pow(2,256) - + * 0x1000003D1. * * Supports arithmetic for these elements including +, -, *, and inverses. * Supports 32 byte serialization as is needed for ECPrivateKeys. @@ -15,7 +16,8 @@ case class FieldElement(bytes: ByteVector) require( privKeyT.isSuccess || isZero, - s"$bytes is not a valid field element: ${privKeyT.failed.get.getMessage}") + s"$bytes is not a valid field element: ${privKeyT.failed.get.getMessage}" + ) def toPrivateKey: ECPrivateKey = if (!isZero) { diff --git a/crypto/src/main/scala/org/bitcoins/crypto/FiniteField.scala b/crypto/src/main/scala/org/bitcoins/crypto/FiniteField.scala index cadbec02d3..863eb858b2 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/FiniteField.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/FiniteField.scala @@ -6,13 +6,16 @@ import java.math.BigInteger abstract class FiniteFieldMember[F <: FiniteFieldMember[F]]( fieldOrder: BigInteger, - byteSize: Int) - extends NetworkElement { - require(bytes.length == byteSize, - s"Finite field member must have $byteSize bytes, got $bytes") + byteSize: Int +) extends NetworkElement { + require( + bytes.length == byteSize, + s"Finite field member must have $byteSize bytes, got $bytes" + ) require( toBigInteger.compareTo(fieldOrder) < 0, - s"$bytes is not a valid field member (was not less than $fieldOrder).") + s"$bytes is not a valid field member (was not less than $fieldOrder)." + ) def isZero: Boolean = bytes.toArray.forall(_ == 0.toByte) @@ -53,8 +56,8 @@ abstract class FiniteFieldMember[F <: FiniteFieldMember[F]]( abstract class FiniteFieldObject[F <: FiniteFieldMember[F]]( fieldOrder: BigInteger, - byteSize: Int) - extends Factory[F] { + byteSize: Int +) extends Factory[F] { def fieldMemberConstructor(bytes: ByteVector): F @@ -67,7 +70,8 @@ abstract class FiniteFieldObject[F <: FiniteFieldMember[F]]( fieldMemberConstructor(bytes.tail) } else { throw new IllegalArgumentException( - s"Field element cannot have more than 32 bytes, got $bytes") + s"Field element cannot have more than 32 bytes, got $bytes" + ) } } @@ -112,8 +116,9 @@ abstract class FiniteFieldObject[F <: FiniteFieldMember[F]]( apply(neg) } - /** Computes the inverse (mod fieldOrder) of the input using the Euclidean Algorithm (log time) - * Cribbed from [[https://www.geeksforgeeks.org/multiplicative-inverse-under-modulo-m/]] + /** Computes the inverse (mod fieldOrder) of the input using the Euclidean + * Algorithm (log time) Cribbed from + * [[https://www.geeksforgeeks.org/multiplicative-inverse-under-modulo-m/]] */ def computeInverse(fe: F): F = { val inv = fe.toBigInteger.modInverse(fieldOrder) diff --git a/crypto/src/main/scala/org/bitcoins/crypto/HashDigest.scala b/crypto/src/main/scala/org/bitcoins/crypto/HashDigest.scala index 9ca3edb016..aa20b17e1b 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/HashDigest.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/HashDigest.scala @@ -7,9 +7,9 @@ sealed trait HashDigest extends Any with NetworkElement { /** The message digest represented in bytes */ override def bytes: ByteVector - /** Flips the endianness of the byte sequence. - * Since bitcoin unfortunately has inconsistent endianness between the protocol - * level and the presentation level. This is useful for switching between the two. + /** Flips the endianness of the byte sequence. Since bitcoin unfortunately has + * inconsistent endianness between the protocol level and the presentation + * level. This is useful for switching between the two. * @return */ def flip: HashDigest @@ -68,9 +68,11 @@ object Sha256Digest extends Factory[Sha256Digest] { } override def fromBytes(bytes: ByteVector): Sha256Digest = { - require(bytes.length == 32, - // $COVERAGE-OFF$ - "Sha256Digest must be 32 bytes in size, got: " + bytes.length) + require( + bytes.length == 32, + // $COVERAGE-OFF$ + "Sha256Digest must be 32 bytes in size, got: " + bytes.length + ) Sha256DigestImpl(bytes) } @@ -96,9 +98,11 @@ object Sha256DigestBE extends Factory[Sha256DigestBE] { } override def fromBytes(bytes: ByteVector): Sha256DigestBE = { - require(bytes.length == 32, - // $COVERAGE-OFF$ - "Sha256Digest must be 32 bytes in size, got: " + bytes.length) + require( + bytes.length == 32, + // $COVERAGE-OFF$ + "Sha256Digest must be 32 bytes in size, got: " + bytes.length + ) Sha256DigestBEImpl(bytes) } @@ -108,8 +112,10 @@ object Sha256DigestBE extends Factory[Sha256DigestBE] { /** Represents the result of SHA256(SHA256()) */ case class DoubleSha256Digest(bytes: ByteVector) extends HashDigest { - require(bytes.length == 32, - "DoubleSha256Digest must always be 32 bytes, got: " + bytes.length) + require( + bytes.length == 32, + "DoubleSha256Digest must always be 32 bytes, got: " + bytes.length + ) lazy val flip: DoubleSha256DigestBE = DoubleSha256DigestBE(bytes.reverse) @@ -133,8 +139,10 @@ object DoubleSha256Digest extends Factory[DoubleSha256Digest] { /** The big endian version of [[DoubleSha256Digest DoubleSha256Digest]] */ case class DoubleSha256DigestBE(bytes: ByteVector) extends HashDigest { - require(bytes.length == 32, - "DoubleSha256Digest must always be 32 bytes, got: " + bytes.length) + require( + bytes.length == 32, + "DoubleSha256Digest must always be 32 bytes, got: " + bytes.length + ) def flip: DoubleSha256Digest = DoubleSha256Digest.fromBytes(bytes.reverse) @@ -169,9 +177,11 @@ object RipeMd160Digest extends Factory[RipeMd160Digest] { } override def fromBytes(bytes: ByteVector): RipeMd160Digest = { - require(bytes.length == 20, - // $COVERAGE-OFF$ - "RIPEMD160Digest must always be 20 bytes, got: " + bytes.length) + require( + bytes.length == 20, + // $COVERAGE-OFF$ + "RIPEMD160Digest must always be 20 bytes, got: " + bytes.length + ) RipeMd160DigestImpl(bytes) } } @@ -192,9 +202,11 @@ object RipeMd160DigestBE extends Factory[RipeMd160DigestBE] { } override def fromBytes(bytes: ByteVector): RipeMd160DigestBE = { - require(bytes.length == 20, - // $COVERAGE-OFF$ - "RIPEMD160Digest must always be 20 bytes, got: " + bytes.length) + require( + bytes.length == 20, + // $COVERAGE-OFF$ + "RIPEMD160Digest must always be 20 bytes, got: " + bytes.length + ) RipeMd160DigestBEImpl(bytes) } } @@ -217,9 +229,11 @@ object Sha256Hash160Digest extends Factory[Sha256Hash160Digest] { } override def fromBytes(bytes: ByteVector): Sha256Hash160Digest = { - require(bytes.length == 20, - // $COVERAGE-OFF$ - "Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length) + require( + bytes.length == 20, + // $COVERAGE-OFF$ + "Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length + ) Sha256Hash160DigestImpl(bytes) } } @@ -240,9 +254,11 @@ object Sha256Hash160DigestBE extends Factory[Sha256Hash160DigestBE] { } override def fromBytes(bytes: ByteVector): Sha256Hash160DigestBE = { - require(bytes.length == 20, - // $COVERAGE-OFF$ - "Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length) + require( + bytes.length == 20, + // $COVERAGE-OFF$ + "Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length + ) Sha256Hash160DigestBEImpl(bytes) } } @@ -263,9 +279,11 @@ object Sha3_256Digest extends Factory[Sha3_256Digest] { } override def fromBytes(bytes: ByteVector): Sha3_256Digest = { - require(bytes.length == 32, - // $COVERAGE-OFF$ - "Sha3-256Digest must be 32 bytes in size, got: " + bytes.length) + require( + bytes.length == 32, + // $COVERAGE-OFF$ + "Sha3-256Digest must be 32 bytes in size, got: " + bytes.length + ) Sha3_256DigestImpl(bytes) } @@ -291,9 +309,11 @@ object Sha3_256DigestBE extends Factory[Sha3_256DigestBE] { } override def fromBytes(bytes: ByteVector): Sha3_256DigestBE = { - require(bytes.length == 32, - // $COVERAGE-OFF$ - "Sha3-256Digest must be 32 bytes in size, got: " + bytes.length) + require( + bytes.length == 32, + // $COVERAGE-OFF$ + "Sha3-256Digest must be 32 bytes in size, got: " + bytes.length + ) Sha3_256DigestBEImpl(bytes) } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/HashType.scala b/crypto/src/main/scala/org/bitcoins/crypto/HashType.scala index e862baf373..248bda0d23 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/HashType.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/HashType.scala @@ -107,14 +107,16 @@ object HashType extends Factory[HashType] { false } - lazy val hashTypes = Seq(sigHashAll, - sigHashNone, - sigHashSingle, - sigHashAnyoneCanPay, - sigHashNoneAnyoneCanPay, - sigHashAllAnyoneCanPay, - sigHashSingleAnyoneCanPay, - sigHashDefault) + lazy val hashTypes = Seq( + sigHashAll, + sigHashNone, + sigHashSingle, + sigHashAnyoneCanPay, + sigHashNoneAnyoneCanPay, + sigHashAllAnyoneCanPay, + sigHashSingleAnyoneCanPay, + sigHashDefault + ) lazy val hashTypeBytes: Vector[Byte] = Vector( sigHashDefaultByte, @@ -141,21 +143,22 @@ object HashType extends Factory[HashType] { /** The default [[SIGHASH_ALL]] value */ val sigHashAll = SIGHASH_ALL(sigHashAllByte) - /** The default num for [[SIGHASH_ANYONECANPAY]] - * We need this for serialization of [[HashType]] - * flags inside of [[org.bitcoins.core.crypto.TransactionSignatureSerializer]] + /** The default num for [[SIGHASH_ANYONECANPAY]] We need this for + * serialization of [[HashType]] flags inside of + * [[org.bitcoins.core.crypto.TransactionSignatureSerializer]] * * Have to be careful using this value, since native scala numbers are signed * We need this because this serializes to 0x00000080 instead of 0xffffff80 - * If we try to use Int(sigHashAnyoneCanPayByte) we will get the latter serialization - * because all native scala numbers are signed + * If we try to use Int(sigHashAnyoneCanPayByte) we will get the latter + * serialization because all native scala numbers are signed */ val sigHashAnyoneCanPayNum = 0x80 val sigHashAnyoneCanPayByte = 0x80.toByte val sigHashAnyoneCanPay: SIGHASH_ANYONECANPAY = SIGHASH_ANYONECANPAY( - sigHashAnyoneCanPayNum) + sigHashAnyoneCanPayNum + ) /** The default byte for [[SIGHASH_NONE]] */ val sigHashNoneByte: Byte = 2.toByte @@ -173,7 +176,8 @@ object HashType extends Factory[HashType] { val sigHashAllAnyoneCanPayNum = sigHashAllByte.toInt | sigHashAnyoneCanPayNum val sigHashAllAnyoneCanPay = SIGHASH_ALL_ANYONECANPAY( - sigHashAllAnyoneCanPayNum) + sigHashAllAnyoneCanPayNum + ) val sigHashNoneAnyoneCanPayByte = (HashType.sigHashNoneByte | HashType.sigHashAnyoneCanPayByte).toByte @@ -182,7 +186,8 @@ object HashType extends Factory[HashType] { sigHashNoneByte.toInt | sigHashAnyoneCanPayNum val sigHashNoneAnyoneCanPay = SIGHASH_NONE_ANYONECANPAY( - sigHashNoneAnyoneCanPayNum) + sigHashNoneAnyoneCanPayNum + ) val sigHashSingleAnyoneCanPayByte = (HashType.sigHashSingleByte | HashType.sigHashAnyoneCanPayByte).toByte @@ -191,10 +196,11 @@ object HashType extends Factory[HashType] { sigHashSingleByte.toInt | sigHashAnyoneCanPayNum val sigHashSingleAnyoneCanPay = SIGHASH_SINGLE_ANYONECANPAY( - sigHashSingleAnyoneCanPayNum) + sigHashSingleAnyoneCanPayNum + ) - /** Checks if the given digital signature has a valid hash type - * Mimics this functionality inside of Bitcoin Core + /** Checks if the given digital signature has a valid hash type Mimics this + * functionality inside of Bitcoin Core * https://github.com/bitcoin/bitcoin/blob/b83264d9c7a8ddb79f64bd9540caddc8632ef31f/src/script/interpreter.cpp#L186 */ def isDefinedHashtypeSignature(sig: ECDigitalSignature): Boolean = { @@ -206,15 +212,16 @@ case object SIGHASH_DEFAULT extends HashType { override val num: Int = HashType.sigHashDefaultByte } -/** defaultValue is the underlying value of the HashType. The last byte of a signature determines the HashType. - * https://en.bitcoin.it/wiki/OP_CHECKSIG +/** defaultValue is the underlying value of the HashType. The last byte of a + * signature determines the HashType. https://en.bitcoin.it/wiki/OP_CHECKSIG */ case class SIGHASH_ALL(override val num: Int) extends HashType { require( HashType.isSigHashAll(num), "SIGHASH_ALL acts as a 'catch-all' for undefined hashtypes, and has a default " + "value of one. Your input was: " + num + ", which is of hashType: " + HashType( - num) + num + ) ) } @@ -223,32 +230,43 @@ object SIGHASH_ALL { } case class SIGHASH_NONE(override val num: Int) extends HashType { - require(HashType.isSigHashNone(num), - "The given number is not a SIGHASH_NONE number: " + num) + require( + HashType.isSigHashNone(num), + "The given number is not a SIGHASH_NONE number: " + num + ) } case class SIGHASH_SINGLE(override val num: Int) extends HashType { - require(HashType.isSigHashSingle(num), - "The given number is not a SIGHASH_SINGLE number: " + num) + require( + HashType.isSigHashSingle(num), + "The given number is not a SIGHASH_SINGLE number: " + num + ) } case class SIGHASH_ANYONECANPAY(override val num: Int) extends HashType { - require(HashType.isSigHashAnyoneCanPay(num), - "The given number was not a SIGHASH_ANYONECANPAY number: " + num) + require( + HashType.isSigHashAnyoneCanPay(num), + "The given number was not a SIGHASH_ANYONECANPAY number: " + num + ) } case class SIGHASH_ALL_ANYONECANPAY(override val num: Int) extends HashType { - require(HashType.isSigHashAllAnyoneCanPay(num), - "The given number was not a SIGHASH_ALL_ANYONECANPAY number: " + num) + require( + HashType.isSigHashAllAnyoneCanPay(num), + "The given number was not a SIGHASH_ALL_ANYONECANPAY number: " + num + ) } case class SIGHASH_NONE_ANYONECANPAY(override val num: Int) extends HashType { - require(HashType.isSigHashNoneAnyoneCanPay(num), - "The given number was not a SIGHASH_NONE_ANYONECANPAY number: " + num) + require( + HashType.isSigHashNoneAnyoneCanPay(num), + "The given number was not a SIGHASH_NONE_ANYONECANPAY number: " + num + ) } case class SIGHASH_SINGLE_ANYONECANPAY(override val num: Int) extends HashType { require( HashType.isSigHashSingleAnyoneCanPay(num), - "The given number was not a SIGHASH_SINGLE_ANYONECANPAY number: " + num) + "The given number was not a SIGHASH_SINGLE_ANYONECANPAY number: " + num + ) } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/MaskedToString.scala b/crypto/src/main/scala/org/bitcoins/crypto/MaskedToString.scala index 6e493672c5..743827453c 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/MaskedToString.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/MaskedToString.scala @@ -1,7 +1,7 @@ package org.bitcoins.crypto -/** Meant to provide a simple trait that - * masks the default to string for sensitive classes +/** Meant to provide a simple trait that masks the default to string for + * sensitive classes */ trait MaskedToString { @@ -9,9 +9,8 @@ trait MaskedToString { s"Masked(${getClass.getSimpleName})" } - /** Returns the real value of a sensitive string - * This should be considered unsafe in the sense - * that this information is sensitive and could cause + /** Returns the real value of a sensitive string This should be considered + * unsafe in the sense that this information is sensitive and could cause * loss of funds if used anywhere things are persisted like logs */ def toStringSensitive: String diff --git a/crypto/src/main/scala/org/bitcoins/crypto/NetworkElement.scala b/crypto/src/main/scala/org/bitcoins/crypto/NetworkElement.scala index 5c5c6d587e..0c7f2f29f4 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/NetworkElement.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/NetworkElement.scala @@ -2,9 +2,8 @@ package org.bitcoins.crypto import scodec.bits.ByteVector -/** Created by chris on 1/14/16. - * This represents a element that can be serialized to - * be sent over the network +/** Created by chris on 1/14/16. This represents a element that can be + * serialized to be sent over the network */ trait NetworkElement extends Any { diff --git a/crypto/src/main/scala/org/bitcoins/crypto/SchnorrDigitalSignature.scala b/crypto/src/main/scala/org/bitcoins/crypto/SchnorrDigitalSignature.scala index 4ccb513e43..0f22d8a835 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/SchnorrDigitalSignature.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/SchnorrDigitalSignature.scala @@ -9,16 +9,22 @@ case class SchnorrDigitalSignature(rx: SchnorrNonce, sig: FieldElement) object SchnorrDigitalSignature extends Factory[SchnorrDigitalSignature] { - //If the sig is 65 bytes long, return sig[64] ≠ 0x00[20] and + // If the sig is 65 bytes long, return sig[64] ≠ 0x00[20] and // Verify(q, hashTapSighash(0x00 || SigMsg(sig[64], 0)), sig[0:64]). override def fromBytes(bytes: ByteVector): SchnorrDigitalSignature = { - require(bytes.length == 64, - s"SchnorrDigitalSignature must be exactly 64 bytes, got $bytes") - SchnorrDigitalSignature(SchnorrNonce(bytes.take(32)), - FieldElement(bytes.drop(32))) + require( + bytes.length == 64, + s"SchnorrDigitalSignature must be exactly 64 bytes, got $bytes" + ) + SchnorrDigitalSignature( + SchnorrNonce(bytes.take(32)), + FieldElement(bytes.drop(32)) + ) } lazy val dummy: SchnorrDigitalSignature = - SchnorrDigitalSignature(FieldElement.one.getPublicKey.schnorrNonce, - FieldElement.one) + SchnorrDigitalSignature( + FieldElement.one.getPublicKey.schnorrNonce, + FieldElement.one + ) } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/SchnorrNonce.scala b/crypto/src/main/scala/org/bitcoins/crypto/SchnorrNonce.scala index f8f121bab9..914520b76a 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/SchnorrNonce.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/SchnorrNonce.scala @@ -25,7 +25,8 @@ object SchnorrNonce extends Factory[SchnorrNonce] { def kFromBipSchnorr( privKey: ECPrivateKey, message: ByteVector, - auxRand: ByteVector): ECPrivateKey = { + auxRand: ByteVector + ): ECPrivateKey = { val privKeyForUse = privKey.schnorrKey val randHash = @@ -33,19 +34,20 @@ object SchnorrNonce extends Factory[SchnorrNonce] { val maskedKey = randHash.xor(privKeyForUse.bytes) val nonceHash = CryptoUtil.sha256SchnorrNonce( - maskedKey ++ privKey.schnorrPublicKey.bytes ++ message) + maskedKey ++ privKey.schnorrPublicKey.bytes ++ message + ) ECPrivateKey(nonceHash.bytes).nonceKey } - /** Computes the bip-schnorr nonce for a given message and private key. - * This is intended to ensure that no two messages are signed with the - * same nonce. + /** Computes the bip-schnorr nonce for a given message and private key. This + * is intended to ensure that no two messages are signed with the same nonce. */ def fromBipSchnorr( privKey: ECPrivateKey, message: ByteVector, - auxRand: ByteVector): SchnorrNonce = { + auxRand: ByteVector + ): SchnorrNonce = { val k = kFromBipSchnorr(privKey, message, auxRand) k.publicKey.schnorrNonce } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/SchnorrPublicKey.scala b/crypto/src/main/scala/org/bitcoins/crypto/SchnorrPublicKey.scala index 3f05f7a78c..256dd8a7af 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/SchnorrPublicKey.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/SchnorrPublicKey.scala @@ -6,10 +6,14 @@ import scala.annotation.tailrec import scala.util.Try case class SchnorrPublicKey(bytes: ByteVector) extends PublicKey { - require(bytes.length == 32, - s"Schnorr public keys must be 32 bytes, got $bytes") - require(Try(publicKey).isSuccess, - s"Schnorr public key must be a valid x coordinate, got $bytes") + require( + bytes.length == 32, + s"Schnorr public keys must be 32 bytes, got $bytes" + ) + require( + Try(publicKey).isSuccess, + s"Schnorr public key must be a valid x coordinate, got $bytes" + ) def verify(data: ByteVector, signature: SchnorrDigitalSignature): Boolean = { CryptoUtil.schnorrVerify(data, this, signature) @@ -29,7 +33,8 @@ case class SchnorrPublicKey(bytes: ByteVector) extends PublicKey { def computeSigPoint( bytesToHash: Vector[ByteVector], - nonces: Vector[SchnorrNonce]): ECPublicKey = { + nonces: Vector[SchnorrNonce] + ): ECPublicKey = { // TODO: when combine function is ported from secp, use that instead for nonces val bytesAndNonces = bytesToHash.zip(nonces) @@ -38,7 +43,8 @@ case class SchnorrPublicKey(bytes: ByteVector) extends PublicKey { .sha256SchnorrChallenge( nonce.bytes ++ this.bytes ++ CryptoUtil .sha256DLCAttestation(bytes) - .bytes) + .bytes + ) .bytes val e = ECPrivateKey(eBytes) (e, nonce.publicKey) @@ -56,7 +62,8 @@ case class SchnorrPublicKey(bytes: ByteVector) extends PublicKey { def computeSigPoint( data: ByteVector, nonce: SchnorrNonce, - compressed: Boolean): ECPublicKey = { + compressed: Boolean + ): ECPublicKey = { CryptoUtil.schnorrComputeSigPoint(data, nonce, this, compressed) } @@ -77,8 +84,10 @@ object SchnorrPublicKey extends Factory[SchnorrPublicKey] { @tailrec def fromBytes(bytes: ByteVector): SchnorrPublicKey = { - require(bytes.length <= 33, - s"XOnlyPublicKey must be less than 33 bytes, got $bytes") + require( + bytes.length <= 33, + s"XOnlyPublicKey must be less than 33 bytes, got $bytes" + ) if (bytes.length == 32) new SchnorrPublicKey(bytes) else if (bytes.length < 32) { @@ -90,7 +99,8 @@ object SchnorrPublicKey extends Factory[SchnorrPublicKey] { } else { throw new IllegalArgumentException( "XOnlyPublicKey cannot be greater than 33 bytes in size, got: " + - CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size) + CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size + ) } } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/SecpPoint.scala b/crypto/src/main/scala/org/bitcoins/crypto/SecpPoint.scala index 171cbf6bd9..38c1574152 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/SecpPoint.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/SecpPoint.scala @@ -25,8 +25,7 @@ sealed trait SecpPoint extends NetworkElement { } /** The point at infinity, this is the secp256k1 group identity element meaning - * p + 0x00 = 0x00 + p = p for any point p and - * p + (-p) = 0x00. + * p + 0x00 = 0x00 + p = p for any point p and p + (-p) = 0x00. * * Note that this does not correspond to a valid ECPublicKey just like * FieldElement.zero does not correspond to a valid private key (and in fact @@ -52,8 +51,10 @@ case class SecpPointFinite(x: CurveCoordinate, y: CurveCoordinate) def schnorrNonce: SchnorrNonce = { val pub = toPublicKey - require(pub.isCompressed, - s"SchnorrNonce can only be created from compressed public keys") + require( + pub.isCompressed, + s"SchnorrNonce can only be created from compressed public keys" + ) pub.schnorrNonce } } @@ -69,8 +70,10 @@ object SecpPoint { SecpPointFinite(CurveCoordinate.fromBytes(x), CurveCoordinate.fromBytes(y)) def apply(x: Array[Byte], y: Array[Byte]): SecpPointFinite = - SecpPointFinite(CurveCoordinate.fromByteArray(x), - CurveCoordinate.fromByteArray(y)) + SecpPointFinite( + CurveCoordinate.fromByteArray(x), + CurveCoordinate.fromByteArray(y) + ) def apply(x: BigInteger, y: BigInteger): SecpPointFinite = SecpPointFinite(CurveCoordinate(x), CurveCoordinate(y)) diff --git a/crypto/src/main/scala/org/bitcoins/crypto/Sign.scala b/crypto/src/main/scala/org/bitcoins/crypto/Sign.scala index d708416b3e..ec1ebe69e1 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/Sign.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/Sign.scala @@ -5,36 +5,43 @@ import scodec.bits.ByteVector import scala.annotation.tailrec import scala.concurrent.{ExecutionContext, Future} -/** This is meant to be an abstraction for a [[org.bitcoins.crypto.ECPrivateKey]], sometimes we will not - * have direct access to a private key in memory -- for instance if that key is on a hardware device -- so we need to create an - * abstraction of the signing process. Fundamentally a private key takes in a scodec.bits.ByteVector and returns a [[ECDigitalSignature]] - * That is what this abstraction is meant to represent. If you have a [[ECPrivateKey]] in your application, you can get it's - * [[Sign]] type by doing this: +/** This is meant to be an abstraction for a + * [[org.bitcoins.crypto.ECPrivateKey]], sometimes we will not have direct + * access to a private key in memory -- for instance if that key is on a + * hardware device -- so we need to create an abstraction of the signing + * process. Fundamentally a private key takes in a scodec.bits.ByteVector and + * returns a [[ECDigitalSignature]] That is what this abstraction is meant to + * represent. If you have a [[ECPrivateKey]] in your application, you can get + * it's [[Sign]] type by doing this: * - * val key = ECPrivateKey() - * val sign: scodec.bits.ByteVector => Future[ECDigitalSignature] = key.signFunction + * val key = ECPrivateKey() val sign: scodec.bits.ByteVector => + * Future[ECDigitalSignature] = key.signFunction * - * If you have a hardware wallet, you will need to implement the protocol to send a message to the hardware device. The - * type signature of the function you implement must be scodec.bits.ByteVector => Future[ECDigitalSignature] + * If you have a hardware wallet, you will need to implement the protocol to + * send a message to the hardware device. The type signature of the function + * you implement must be scodec.bits.ByteVector => Future[ECDigitalSignature] */ trait AsyncSign { def asyncSign(bytes: ByteVector): Future[ECDigitalSignature] /** Note that using this function to generate digital signatures with specific - * properties (by trying a bunch of entropy values) can reduce privacy as it will - * fingerprint your wallet. Additionally it could lead to a loss of entropy in - * the resulting nonce should the property you are interested in cause a constraint - * on the input space. + * properties (by trying a bunch of entropy values) can reduce privacy as it + * will fingerprint your wallet. Additionally it could lead to a loss of + * entropy in the resulting nonce should the property you are interested in + * cause a constraint on the input space. * - * In short, ALL USES OF THIS FUNCTION THAT SIGN THE SAME DATA WITH DIFFERENT ENTROPY - * HAVE THE POTENTIAL TO CAUSE REDUCTIONS IN SECURITY AND PRIVACY, BEWARE! + * In short, ALL USES OF THIS FUNCTION THAT SIGN THE SAME DATA WITH DIFFERENT + * ENTROPY HAVE THE POTENTIAL TO CAUSE REDUCTIONS IN SECURITY AND PRIVACY, + * BEWARE! */ def asyncSignWithEntropy( bytes: ByteVector, - entropy: ByteVector): Future[ECDigitalSignature] + entropy: ByteVector + ): Future[ECDigitalSignature] private def asyncSignLowR(bytes: ByteVector, startAt: Long)(implicit - ec: ExecutionContext): Future[ECDigitalSignature] = { + ec: ExecutionContext + ): Future[ECDigitalSignature] = { val sigF = if (startAt == 0) { // On first try, use normal signing asyncSign(bytes) } else { // Subsequently, use additional entropy @@ -51,8 +58,9 @@ trait AsyncSign { } } - def asyncSignLowR(bytes: ByteVector)(implicit - ec: ExecutionContext): Future[ECDigitalSignature] = { + def asyncSignLowR( + bytes: ByteVector + )(implicit ec: ExecutionContext): Future[ECDigitalSignature] = { asyncSignLowR(bytes, startAt = 0) } @@ -65,9 +73,10 @@ object AsyncSign { asyncSignFunction: ByteVector => Future[ECDigitalSignature], asyncSignWithEntropyFunction: ( ByteVector, - ByteVector) => Future[ECDigitalSignature], - override val publicKey: ECPublicKey) - extends AsyncSign { + ByteVector + ) => Future[ECDigitalSignature], + override val publicKey: ECPublicKey + ) extends AsyncSign { override def asyncSign(bytes: ByteVector): Future[ECDigitalSignature] = { asyncSignFunction(bytes) @@ -75,7 +84,8 @@ object AsyncSign { override def asyncSignWithEntropy( bytes: ByteVector, - entropy: ByteVector): Future[ECDigitalSignature] = { + entropy: ByteVector + ): Future[ECDigitalSignature] = { asyncSignWithEntropyFunction(bytes, entropy) } } @@ -84,23 +94,28 @@ object AsyncSign { asyncSign: ByteVector => Future[ECDigitalSignature], asyncSignWithEntropy: ( ByteVector, - ByteVector) => Future[ECDigitalSignature], - pubKey: ECPublicKey): AsyncSign = { + ByteVector + ) => Future[ECDigitalSignature], + pubKey: ECPublicKey + ): AsyncSign = { AsyncSignImpl(asyncSign, asyncSignWithEntropy, pubKey) } def constant(sig: ECDigitalSignature, pubKey: ECPublicKey): AsyncSign = { - AsyncSignImpl(_ => Future.successful(sig), - (_, _) => Future.successful(sig), - pubKey) + AsyncSignImpl( + _ => Future.successful(sig), + (_, _) => Future.successful(sig), + pubKey + ) } /** This dummySign function is useful for the case where we do not have the - * signFunction available on the same jvm as the place where we are creating the - * sign. I can't think of a good way to serialize the signFunction, so it needs to be - * optional for now. Maybe we rethink the idea of the signFunction in the future. - * the public key is still useful here though because it can be used to match against - * a specific private key on another server + * signFunction available on the same jvm as the place where we are creating + * the sign. I can't think of a good way to serialize the signFunction, so it + * needs to be optional for now. Maybe we rethink the idea of the + * signFunction in the future. the public key is still useful here though + * because it can be used to match against a specific private key on another + * server */ def dummySign(publicKey: ECPublicKey): AsyncSign = { constant(EmptyDigitalSignature, publicKey) @@ -112,11 +127,13 @@ trait AsyncAdaptorSign extends AsyncSign { def asyncAdaptorSign( adaptorPoint: ECPublicKey, msg: ByteVector, - auxRand: ByteVector): Future[ECAdaptorSignature] + auxRand: ByteVector + ): Future[ECAdaptorSignature] def asyncAdaptorSign( adaptorPoint: ECPublicKey, - msg: ByteVector): Future[ECAdaptorSignature] = { + msg: ByteVector + ): Future[ECAdaptorSignature] = { val auxRand = ECPrivateKey.freshPrivateKey.bytes asyncAdaptorSign(adaptorPoint, msg, auxRand) } @@ -130,21 +147,24 @@ trait Sign extends AsyncSign { } /** Note that using this function to generate digital signatures with specific - * properties (by trying a bunch of entropy values) can reduce privacy as it will - * fingerprint your wallet. Additionally it could lead to a loss of entropy in - * the resulting nonce should the property you are interested in cause a constraint - * on the input space. + * properties (by trying a bunch of entropy values) can reduce privacy as it + * will fingerprint your wallet. Additionally it could lead to a loss of + * entropy in the resulting nonce should the property you are interested in + * cause a constraint on the input space. * - * In short, ALL USES OF THIS FUNCTION THAT SIGN THE SAME DATA WITH DIFFERENT ENTROPY - * HAVE THE POTENTIAL TO CAUSE REDUCTIONS IN SECURITY AND PRIVACY, BEWARE! + * In short, ALL USES OF THIS FUNCTION THAT SIGN THE SAME DATA WITH DIFFERENT + * ENTROPY HAVE THE POTENTIAL TO CAUSE REDUCTIONS IN SECURITY AND PRIVACY, + * BEWARE! */ def signWithEntropy( bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature + entropy: ByteVector + ): ECDigitalSignature override def asyncSignWithEntropy( bytes: ByteVector, - entropy: ByteVector): Future[ECDigitalSignature] = { + entropy: ByteVector + ): Future[ECDigitalSignature] = { Future.successful(signWithEntropy(bytes, entropy)) } @@ -173,8 +193,9 @@ trait Sign extends AsyncSign { signLowR(bytes, startAt = 0) } - override def asyncSignLowR(bytes: ByteVector)(implicit - ec: ExecutionContext): Future[ECDigitalSignature] = { + override def asyncSignLowR( + bytes: ByteVector + )(implicit ec: ExecutionContext): Future[ECDigitalSignature] = { Future.successful(signLowR(bytes)) } } @@ -184,8 +205,8 @@ object Sign { private case class SignImpl( signFunction: ByteVector => ECDigitalSignature, signWithEntropyFunction: (ByteVector, ByteVector) => ECDigitalSignature, - override val publicKey: ECPublicKey) - extends Sign { + override val publicKey: ECPublicKey + ) extends Sign { override def sign(bytes: ByteVector): ECDigitalSignature = { signFunction(bytes) @@ -193,7 +214,8 @@ object Sign { override def signWithEntropy( bytes: ByteVector, - entropy: ByteVector): ECDigitalSignature = { + entropy: ByteVector + ): ECDigitalSignature = { signWithEntropyFunction(bytes, entropy) } } @@ -201,7 +223,8 @@ object Sign { def apply( sign: ByteVector => ECDigitalSignature, signWithEntropy: (ByteVector, ByteVector) => ECDigitalSignature, - pubKey: ECPublicKey): Sign = { + pubKey: ECPublicKey + ): Sign = { SignImpl(sign, signWithEntropy, pubKey) } @@ -219,11 +242,13 @@ trait AdaptorSign extends Sign with AsyncAdaptorSign { def adaptorSign( adaptorPoint: ECPublicKey, msg: ByteVector, - auxRand: ByteVector): ECAdaptorSignature + auxRand: ByteVector + ): ECAdaptorSignature def adaptorSign( adaptorPoint: ECPublicKey, - msg: ByteVector): ECAdaptorSignature = { + msg: ByteVector + ): ECAdaptorSignature = { val auxRand = ECPrivateKey.freshPrivateKey.bytes adaptorSign(adaptorPoint, msg, auxRand) } @@ -231,7 +256,8 @@ trait AdaptorSign extends Sign with AsyncAdaptorSign { override def asyncAdaptorSign( adaptorPoint: ECPublicKey, msg: ByteVector, - auxRand: ByteVector): Future[ECAdaptorSignature] = { + auxRand: ByteVector + ): Future[ECAdaptorSignature] = { Future.successful(adaptorSign(adaptorPoint, msg, auxRand)) } } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/SipHashKey.scala b/crypto/src/main/scala/org/bitcoins/crypto/SipHashKey.scala index afb0d812bc..8a35ee90bd 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/SipHashKey.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/SipHashKey.scala @@ -3,6 +3,8 @@ package org.bitcoins.crypto import scodec.bits.ByteVector case class SipHashKey(bytes: ByteVector) extends NetworkElement { - require(bytes.size == 16, - "Can only use a key length of 16 bytes, got: " + bytes.size) + require( + bytes.size == 16, + "Can only use a key length of 16 bytes, got: " + bytes.size + ) } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/StringFactory.scala b/crypto/src/main/scala/org/bitcoins/crypto/StringFactory.scala index bc49aa07f1..856ff57e2c 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/StringFactory.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/StringFactory.scala @@ -2,7 +2,9 @@ package org.bitcoins.crypto import scala.util.Try -/** A common factory trait that can be re-used to deserialize a string to a type t */ +/** A common factory trait that can be re-used to deserialize a string to a type + * t + */ trait StringFactory[+T] { /** Tries to parse a string to type t, throws an exception if fails */ @@ -13,7 +15,9 @@ trait StringFactory[+T] { fromStringT(string).toOption } - /** Tries to parse string to type t, returns [[scala.util.Failure]] if the fails */ + /** Tries to parse string to type t, returns [[scala.util.Failure]] if the + * fails + */ def fromStringT(string: String): Try[T] = { Try(fromString(string)) } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/XOnlyPubKey.scala b/crypto/src/main/scala/org/bitcoins/crypto/XOnlyPubKey.scala index cb8a4a5fef..8079427802 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/XOnlyPubKey.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/XOnlyPubKey.scala @@ -5,12 +5,18 @@ import scodec.bits.ByteVector import scala.annotation.tailrec import scala.util.Try -/** Represents the x-coordinate of an ECPublicKey, with undetermined y-coordinate parity */ +/** Represents the x-coordinate of an ECPublicKey, with undetermined + * y-coordinate parity + */ case class XOnlyPubKey(bytes: ByteVector) extends PublicKey { - require(bytes.length == 32, - s"x-only public keys must be 32 bytes, got $bytes") - require(Try(publicKey(EvenParity)).isSuccess, - s"x-only public key must be a valid x coordinate, got $bytes") + require( + bytes.length == 32, + s"x-only public keys must be 32 bytes, got $bytes" + ) + require( + Try(publicKey(EvenParity)).isSuccess, + s"x-only public key must be a valid x coordinate, got $bytes" + ) def publicKey(parity: KeyParity): ECPublicKey = { val pubKeyBytes = parity.bytes ++ bytes @@ -26,17 +32,24 @@ case class XOnlyPubKey(bytes: ByteVector) extends PublicKey { def coord: CurveCoordinate = CurveCoordinate(bytes) - /** @see https://github.com/bitcoin/bitcoin/blob/3340d46cd363e568ce842b2a9930e30902d150ca/src/pubkey.cpp#L227 - * @see https://github.com/bitcoin-core/secp256k1/blob/9a5a87e0f1276e0284446af1172056ea4693737f/src/modules/extrakeys/main_impl.h#L151 - * @param pubKey the internal tapscript pubkey - * @param merkleRootOpt the merkle root of the tapscript tree, if empty means we have no scripts in the tapscript tree - * @param parity the expected parity of the public key reproduced + /** @see + * https://github.com/bitcoin/bitcoin/blob/3340d46cd363e568ce842b2a9930e30902d150ca/src/pubkey.cpp#L227 + * @see + * https://github.com/bitcoin-core/secp256k1/blob/9a5a87e0f1276e0284446af1172056ea4693737f/src/modules/extrakeys/main_impl.h#L151 + * @param pubKey + * the internal tapscript pubkey + * @param merkleRootOpt + * the merkle root of the tapscript tree, if empty means we have no scripts + * in the tapscript tree + * @param parity + * the expected parity of the public key reproduced * @return */ def checkTapTweak( internal: XOnlyPubKey, merkleRootOpt: Option[Sha256Digest], - parity: Boolean): Boolean = { + parity: Boolean + ): Boolean = { // Q = point_add(lift_x(pubkey), point_mul(G, t)) val tweaked = internal.computeTapTweakHash(merkleRootOpt) val fe = FieldElement.fromBytes(tweaked.bytes) @@ -45,9 +58,11 @@ case class XOnlyPubKey(bytes: ByteVector) extends PublicKey { this == add.toXOnly && add.parity.isOdd == parity } - /** @see https://github.com/bitcoin/bitcoin/blob/5174a139c92c1238f9700d06e362dc628d81a0a9/src/pubkey.cpp#L216 - * @param merkleRootOpt if merkle root is empty we have no scripts. - * The actual tweak does not matter, but follow BIP341 here to + /** @see + * https://github.com/bitcoin/bitcoin/blob/5174a139c92c1238f9700d06e362dc628d81a0a9/src/pubkey.cpp#L216 + * @param merkleRootOpt + * if merkle root is empty we have no scripts. The actual tweak does not + * matter, but follow BIP341 here to * * @return */ @@ -62,12 +77,15 @@ case class XOnlyPubKey(bytes: ByteVector) extends PublicKey { } } - /** @see https://github.com/bitcoin/bitcoin/blob/bdb33ec51986570ea17406c83bad2c955ae23186/src/pubkey.cpp#L249 - * @param merkleRootOpt if the merkle root is empty we have no scripts. + /** @see + * https://github.com/bitcoin/bitcoin/blob/bdb33ec51986570ea17406c83bad2c955ae23186/src/pubkey.cpp#L249 + * @param merkleRootOpt + * if the merkle root is empty we have no scripts. * @return */ def createTapTweak( - merkleRootOpt: Option[Sha256Digest]): (KeyParity, XOnlyPubKey) = { + merkleRootOpt: Option[Sha256Digest] + ): (KeyParity, XOnlyPubKey) = { val taggedHash = computeTapTweakHash(merkleRootOpt) val result = CryptoParams.getG .multiply(FieldElement(taggedHash.bytes)) @@ -84,8 +102,10 @@ object XOnlyPubKey extends Factory[XOnlyPubKey] { @tailrec def fromBytes(bytes: ByteVector): XOnlyPubKey = { - require(bytes.length <= 33, - s"XOnlyPublicKey must be less than 33 bytes, got $bytes") + require( + bytes.length <= 33, + s"XOnlyPublicKey must be less than 33 bytes, got $bytes" + ) if (bytes.length == 32) new XOnlyPubKey(bytes) @@ -98,7 +118,8 @@ object XOnlyPubKey extends Factory[XOnlyPubKey] { } else { throw new IllegalArgumentException( "XOnlyPublicKey cannot be greater than 33 bytes in size, got: " + - CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size) + CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size + ) } } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/musig/KeySet.scala b/crypto/src/main/scala/org/bitcoins/crypto/musig/KeySet.scala index 06d28be853..4da229d1d7 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/musig/KeySet.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/musig/KeySet.scala @@ -8,8 +8,8 @@ import org.bitcoins.crypto.{ } import scodec.bits.ByteVector -/** Represents an ordered set of MuSig signers and their tweaks. - * This is the data required to (non-interactively) compute the aggPubKey. +/** Represents an ordered set of MuSig signers and their tweaks. This is the + * data required to (non-interactively) compute the aggPubKey. */ trait KeySet { def keys: Vector[SchnorrPublicKey] @@ -46,9 +46,8 @@ trait KeySet { } } - private lazy val computeAggPubKeyAndTweakContext: ( - ECPublicKey, - MuSigTweakContext) = { + private lazy val computeAggPubKeyAndTweakContext + : (ECPublicKey, MuSigTweakContext) = { val untweakedAggPubKey = keys .map { key => val coef = keyAggCoef(key) @@ -69,8 +68,8 @@ trait KeySet { lazy val tweakContext: MuSigTweakContext = computeAggPubKeyAndTweakContext._2 - /** The first key different from the keys.head, - * optimized MuSig2 allows this key to have coefficient 1 + /** The first key different from the keys.head, optimized MuSig2 allows this + * key to have coefficient 1 */ lazy val secondKeyOpt: Option[SchnorrPublicKey] = { keys.find(_ != keys.head) @@ -90,7 +89,8 @@ object KeySet { def apply( keys: Vector[SchnorrPublicKey], - tweaks: Vector[MuSigTweak]): LexicographicKeySet = { + tweaks: Vector[MuSigTweak] + ): LexicographicKeySet = { val sortedKeys = keys.sorted(NetworkElement.lexicographicalOrdering) LexicographicKeySet(sortedKeys, tweaks) } @@ -99,18 +99,20 @@ object KeySet { /** The default way of ordering a KeySet is lexicographically */ case class LexicographicKeySet( override val keys: Vector[SchnorrPublicKey], - override val tweaks: Vector[MuSigTweak] = Vector.empty) - extends KeySet { + override val tweaks: Vector[MuSigTweak] = Vector.empty +) extends KeySet { keys.init.zip(keys.tail).foreach { case (key1, key2) => - require(key1.hex.compareTo(key2.hex) <= 0, - "Keys must be sorted lexicographically") + require( + key1.hex.compareTo(key2.hex) <= 0, + "Keys must be sorted lexicographically" + ) } } -/** This represents an arbitrary KeySet, for use in tests. - * If you have a non-lexicographical order, extend KeySet. +/** This represents an arbitrary KeySet, for use in tests. If you have a + * non-lexicographical order, extend KeySet. */ case class UnsortedKeySet( override val keys: Vector[SchnorrPublicKey], - override val tweaks: Vector[MuSigTweak] = Vector.empty) - extends KeySet + override val tweaks: Vector[MuSigTweak] = Vector.empty +) extends KeySet diff --git a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigNoncePriv.scala b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigNoncePriv.scala index f324aefb11..8cd191a834 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigNoncePriv.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigNoncePriv.scala @@ -6,8 +6,10 @@ import scodec.bits.ByteVector /** Wraps the ephemeral private keys making up a MuSig2 nonce */ case class MuSigNoncePriv(privNonces: Vector[ECPrivateKey]) extends NetworkElement { - require(privNonces.length == MuSigUtil.nonceNum, - s"Exactly ${MuSigUtil.nonceNum} keys are expected, found $privNonces") + require( + privNonces.length == MuSigUtil.nonceNum, + s"Exactly ${MuSigUtil.nonceNum} keys are expected, found $privNonces" + ) def toPublicNonces: MuSigNoncePub = { MuSigNoncePub(privNonces.map(_.publicKey.toPoint)) @@ -29,11 +31,13 @@ case class MuSigNoncePriv(privNonces: Vector[ECPrivateKey]) /** Collapses this into a single ephemeral private key */ def sumToKey(b: FieldElement): FieldElement = { - MuSigUtil.nonceSum[FieldElement](toFieldElements, - b, - _.add(_), - _.multiply(_), - FieldElement.zero) + MuSigUtil.nonceSum[FieldElement]( + toFieldElements, + b, + _.add(_), + _.multiply(_), + FieldElement.zero + ) } } @@ -49,26 +53,33 @@ object MuSigNoncePriv extends Factory[MuSigNoncePriv] { MuSigNoncePriv(privs) } - /** Generates a MuSigNoncePriv given 32 bytes of entropy from preRand, - * and possibly some other sources, as specified in the BIP. + /** Generates a MuSigNoncePriv given 32 bytes of entropy from preRand, and + * possibly some other sources, as specified in the BIP. */ def genInternal( preRand: ByteVector, privKeyOpt: Option[ECPrivateKey] = None, aggPubKeyOpt: Option[SchnorrPublicKey] = None, msgOpt: Option[ByteVector] = None, - extraInOpt: Option[ByteVector] = None): MuSigNoncePriv = { - require(preRand.length == 32, - s"32 bytes of entropy must be provided, found $preRand") - require(msgOpt.forall(msg => msg.length == 32), - s"The message to be signed must be 32 bytes, found $msgOpt") + extraInOpt: Option[ByteVector] = None + ): MuSigNoncePriv = { + require( + preRand.length == 32, + s"32 bytes of entropy must be provided, found $preRand" + ) + require( + msgOpt.forall(msg => msg.length == 32), + s"The message to be signed must be 32 bytes, found $msgOpt" + ) require( extraInOpt.forall(_.length <= 4294967295L), - "extraIn too long, its length must be represented by at most four bytes") + "extraIn too long, its length must be represented by at most four bytes" + ) def serializeWithLen( bytesOpt: Option[ByteVector], - lengthSize: Int = 1): ByteVector = { + lengthSize: Int = 1 + ): ByteVector = { bytesOpt match { case Some(bytes) => ByteVector.fromLong(bytes.length, lengthSize) ++ bytes @@ -104,7 +115,8 @@ object MuSigNoncePriv extends Factory[MuSigNoncePriv] { privKeyOpt: Option[ECPrivateKey] = None, aggPubKeyOpt: Option[SchnorrPublicKey] = None, msgOpt: Option[ByteVector] = None, - extraInOpt: Option[ByteVector] = None): MuSigNoncePriv = { + extraInOpt: Option[ByteVector] = None + ): MuSigNoncePriv = { val preRand = CryptoUtil.randomBytes(32) genInternal(preRand, privKeyOpt, aggPubKeyOpt, msgOpt, extraInOpt) diff --git a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigNoncePub.scala b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigNoncePub.scala index fd49cda4c2..5c0484b6f7 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigNoncePub.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigNoncePub.scala @@ -5,8 +5,10 @@ import scodec.bits.ByteVector /** Wraps the ephemeral points making up a MuSig2 nonce */ case class MuSigNoncePub(pubNonces: Vector[SecpPoint]) extends NetworkElement { - require(pubNonces.length == MuSigUtil.nonceNum, - s"Exactly ${MuSigUtil.nonceNum} keys are expected, found $pubNonces") + require( + pubNonces.length == MuSigUtil.nonceNum, + s"Exactly ${MuSigUtil.nonceNum} keys are expected, found $pubNonces" + ) def apply(i: Int): SecpPoint = { pubNonces(i) @@ -25,11 +27,13 @@ case class MuSigNoncePub(pubNonces: Vector[SecpPoint]) extends NetworkElement { /** Collapses this into a single ephemeral public key */ def sumToKey(b: FieldElement): ECPublicKey = { - MuSigUtil.nonceSum[SecpPoint](pubNonces, - b, - _.add(_), - _.multiply(_), - SecpPointInfinity) match { + MuSigUtil.nonceSum[SecpPoint]( + pubNonces, + b, + _.add(_), + _.multiply(_), + SecpPointInfinity + ) match { case SecpPointInfinity => CryptoParams.getG case p: SecpPointFinite => p.toPublicKey } diff --git a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigTweakContext.scala b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigTweakContext.scala index 54b65776d8..b9a65dc28f 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigTweakContext.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigTweakContext.scala @@ -2,17 +2,19 @@ package org.bitcoins.crypto.musig import org.bitcoins.crypto.{ECPublicKey, FieldElement, OddParity} -/** Represents the total tweak sum and net parity multiplier - * after applying all tweaks +/** Represents the total tweak sum and net parity multiplier after applying all + * tweaks */ case class MuSigTweakContext( parityAcc: ParityMultiplier, - tweakAcc: FieldElement) { + tweakAcc: FieldElement +) { /** Adds tweak to tweakAcc and aggPubKey changing parityAcc if necessary */ def applyTweak( tweak: MuSigTweak, - aggPubKey: ECPublicKey): (ECPublicKey, MuSigTweakContext) = { + aggPubKey: ECPublicKey + ): (ECPublicKey, MuSigTweakContext) = { val parityMult = if (tweak.isXOnlyT && aggPubKey.parity == OddParity) Neg else Pos diff --git a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigTweakData.scala b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigTweakData.scala index bd31a98128..997c8a2911 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigTweakData.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigTweakData.scala @@ -2,13 +2,13 @@ package org.bitcoins.crypto.musig import org.bitcoins.crypto.{EvenParity, FieldElement, KeyParity, OddParity} -/** The data required to apply the net tweak during - * MuSig signature aggregation +/** The data required to apply the net tweak during MuSig signature aggregation */ case class MuSigTweakData( context: MuSigTweakContext, aggPubKeyParity: KeyParity, - e: FieldElement) { + e: FieldElement +) { def additiveTweak: FieldElement = { val g = aggPubKeyParity match { diff --git a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigUtil.scala b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigUtil.scala index 447a4488f2..08c730c441 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigUtil.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/musig/MuSigUtil.scala @@ -4,7 +4,9 @@ import org.bitcoins.crypto._ import scodec.bits.ByteVector // TODO test against secp256k1-zkp someday -/** Contains constants, hash functions, and signing/verification functionality for MuSig */ +/** Contains constants, hash functions, and signing/verification functionality + * for MuSig + */ object MuSigUtil { val nonceNum: Int = 2 @@ -35,7 +37,8 @@ object MuSigUtil { b: FieldElement, add: (T, T) => T, multiply: (T, FieldElement) => T, - identity: T): T = { + identity: T + ): T = { nonces .foldLeft((FieldElement.one, identity)) { case ((pow, sumSoFar), nonce) => val prod = multiply(nonce, pow) @@ -45,13 +48,15 @@ object MuSigUtil { ._2 } - /** Generates a MuSig partial signature, accompanied by the aggregate R value */ + /** Generates a MuSig partial signature, accompanied by the aggregate R value + */ def sign( noncePriv: MuSigNoncePriv, aggNoncePub: MuSigNoncePub, privKey: ECPrivateKey, message: ByteVector, - keySet: KeySet): (ECPublicKey, FieldElement) = { + keySet: KeySet + ): (ECPublicKey, FieldElement) = { val pubKey = privKey.publicKey val coef = keySet.keyAggCoef(pubKey.schnorrPublicKey) val SigningSession(b, aggNonce, e) = @@ -75,14 +80,18 @@ object MuSigUtil { val s = adjustedPrivKey.multiply(e).multiply(coef).add(privNonceSum) - require(partialSigVerify(s, - noncePriv.toPublicNonces, - pubKey.schnorrPublicKey, - keySet, - b, - aggNonce, - e), - "Failed verification when generating signature.") + require( + partialSigVerify( + s, + noncePriv.toPublicNonces, + pubKey.schnorrPublicKey, + keySet, + b, + aggNonce, + e + ), + "Failed verification when generating signature." + ) (aggNonce, s) } @@ -92,16 +101,21 @@ object MuSigUtil { pubNonces: Vector[MuSigNoncePub], keySet: KeySet, message: ByteVector, - signerIndex: Int): Boolean = { - require(signerIndex >= 0 && signerIndex < keySet.length, - s"Invalid signer index $signerIndex for ${keySet.length} signers") + signerIndex: Int + ): Boolean = { + require( + signerIndex >= 0 && signerIndex < keySet.length, + s"Invalid signer index $signerIndex for ${keySet.length} signers" + ) - partialSigVerify(partialSig, - pubNonces(signerIndex), - MuSigNoncePub.aggregate(pubNonces), - keySet(signerIndex), - keySet, - message) + partialSigVerify( + partialSig, + pubNonces(signerIndex), + MuSigNoncePub.aggregate(pubNonces), + keySet(signerIndex), + keySet, + message + ) } def partialSigVerify( @@ -110,7 +124,8 @@ object MuSigUtil { aggNoncePub: MuSigNoncePub, pubKey: SchnorrPublicKey, keySet: KeySet, - message: ByteVector): Boolean = { + message: ByteVector + ): Boolean = { val SigningSession(b, aggNonce, e) = SigningSession(aggNoncePub, keySet, message) @@ -124,7 +139,8 @@ object MuSigUtil { keySet: KeySet, b: FieldElement, aggNonce: ECPublicKey, - e: FieldElement): Boolean = { + e: FieldElement + ): Boolean = { val nonceSum = noncePub.sumToKey(b) val nonceSumAdjusted = aggNonce.parity match { case EvenParity => nonceSum @@ -137,15 +153,18 @@ object MuSigUtil { val aggKey = pubKey.toXOnly.publicKey(aggKeyParity) val a = keySet.keyAggCoef(pubKey) partialSig.getPublicKey == nonceSumAdjusted.add( - aggKey.multiply(e.multiply(a))) + aggKey.multiply(e.multiply(a)) + ) } - /** Aggregates MuSig partial signatures into a BIP340 SchnorrDigitalSignature */ + /** Aggregates MuSig partial signatures into a BIP340 SchnorrDigitalSignature + */ def signAgg( sVals: Vector[FieldElement], aggNoncePub: MuSigNoncePub, keySet: KeySet, - message: ByteVector): SchnorrDigitalSignature = { + message: ByteVector + ): SchnorrDigitalSignature = { val SigningSession(_, aggNonce, e) = SigningSession(aggNoncePub, keySet, message) val tweakData = @@ -154,11 +173,13 @@ object MuSigUtil { signAgg(sVals, aggNonce, Some(tweakData)) } - /** Aggregates MuSig partial signatures into a BIP340 SchnorrDigitalSignature */ + /** Aggregates MuSig partial signatures into a BIP340 SchnorrDigitalSignature + */ def signAgg( sVals: Vector[FieldElement], aggPubNonce: ECPublicKey, - tweakDataOpt: Option[MuSigTweakData] = None): SchnorrDigitalSignature = { + tweakDataOpt: Option[MuSigTweakData] = None + ): SchnorrDigitalSignature = { val sSum = sVals.reduce(_.add(_)) val s = tweakDataOpt match { case Some(tweakData) => sSum.add(tweakData.additiveTweak) diff --git a/crypto/src/main/scala/org/bitcoins/crypto/musig/ParityMultiplier.scala b/crypto/src/main/scala/org/bitcoins/crypto/musig/ParityMultiplier.scala index d4e1814cf2..80c4bbbd81 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/musig/ParityMultiplier.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/musig/ParityMultiplier.scala @@ -8,13 +8,13 @@ import org.bitcoins.crypto.{ OddParity } -/** Represents either FieldElement.one or FieldElement.orderMinusOne. - * Using this ADT rather than those actual FieldElements saves computation - * including some unnecessary point multiplications. +/** Represents either FieldElement.one or FieldElement.orderMinusOne. Using this + * ADT rather than those actual FieldElements saves computation including some + * unnecessary point multiplications. * - * In general there is a correspondence between Pos <-> EvenParity and Neg <-> OddParity, - * this is because in general x-only keys are assumed to be even and need to be negated - * if they are meant to be used as odd keys. + * In general there is a correspondence between Pos <-> EvenParity and Neg <-> + * OddParity, this is because in general x-only keys are assumed to be even and + * need to be negated if they are meant to be used as odd keys. */ sealed trait ParityMultiplier { @@ -32,7 +32,9 @@ sealed trait ParityMultiplier { } } - /** Combines two ParityMultiplier into a single one representing their net modification */ + /** Combines two ParityMultiplier into a single one representing their net + * modification + */ def multiply(other: ParityMultiplier): ParityMultiplier = { (this, other) match { case (Pos, Pos) | (Neg, Neg) => Pos diff --git a/crypto/src/main/scala/org/bitcoins/crypto/musig/SigningSession.scala b/crypto/src/main/scala/org/bitcoins/crypto/musig/SigningSession.scala index 1dfe760b89..71be19db71 100644 --- a/crypto/src/main/scala/org/bitcoins/crypto/musig/SigningSession.scala +++ b/crypto/src/main/scala/org/bitcoins/crypto/musig/SigningSession.scala @@ -12,14 +12,16 @@ import scodec.bits.ByteVector case class SigningSession( b: FieldElement, aggNonce: ECPublicKey, - e: FieldElement) + e: FieldElement +) object SigningSession { def computeB( aggNoncePub: MuSigNoncePub, keySet: KeySet, - message: ByteVector): FieldElement = { + message: ByteVector + ): FieldElement = { val aggPubKey = keySet.aggPubKey.schnorrPublicKey val bHash = @@ -31,10 +33,12 @@ object SigningSession { def computeE( aggPubKey: SchnorrPublicKey, aggNonce: ECPublicKey, - message: ByteVector): FieldElement = { + message: ByteVector + ): FieldElement = { val eBytes = CryptoUtil .sha256SchnorrChallenge( - aggNonce.schnorrNonce.bytes ++ aggPubKey.bytes ++ message) + aggNonce.schnorrNonce.bytes ++ aggPubKey.bytes ++ message + ) .bytes FieldElement(new java.math.BigInteger(1, eBytes.toArray)) @@ -43,7 +47,8 @@ object SigningSession { def getSessionValues( aggNoncePub: MuSigNoncePub, keySet: KeySet, - message: ByteVector): SigningSession = { + message: ByteVector + ): SigningSession = { val aggPubKey = keySet.aggPubKey.schnorrPublicKey val b = computeB(aggNoncePub, keySet, message) val aggNonce = aggNoncePub.sumToKey(b) @@ -55,7 +60,8 @@ object SigningSession { def apply( aggNoncePub: MuSigNoncePub, keySet: KeySet, - message: ByteVector): SigningSession = { + message: ByteVector + ): SigningSession = { getSessionValues(aggNoncePub, keySet, message) } } diff --git a/db-commons-test/src/test/scala/org/bitcoins/db/DBConfigTest.scala b/db-commons-test/src/test/scala/org/bitcoins/db/DBConfigTest.scala index e65f19a26f..bba1a00fb5 100644 --- a/db-commons-test/src/test/scala/org/bitcoins/db/DBConfigTest.scala +++ b/db-commons-test/src/test/scala/org/bitcoins/db/DBConfigTest.scala @@ -17,11 +17,14 @@ class DBConfigTest extends BitcoinSAsyncTest { it should "use sqlite as default database and set its connection pool size to 1" in { withTempDir { dataDir => val bytes = Files.readAllBytes( - new File("db-commons/src/main/resources/reference.conf").toPath) - Files.write(dataDir.resolve("bitcoin-s.conf"), - bytes, - StandardOpenOption.CREATE_NEW, - StandardOpenOption.WRITE) + new File("db-commons/src/main/resources/reference.conf").toPath + ) + Files.write( + dataDir.resolve("bitcoin-s.conf"), + bytes, + StandardOpenOption.CREATE_NEW, + StandardOpenOption.WRITE + ) val chainConfig = ChainAppConfig(dataDir, Vector.empty) val nodeConfig = NodeAppConfig(dataDir, Vector.empty) @@ -55,7 +58,8 @@ class DBConfigTest extends BitcoinSAsyncTest { assert(slickChainConfig.config.hasPath("db.numThreads")) assert(slickChainConfig.config.getInt("db.numThreads") == 1) assert( - slickChainConfig.config.getString("db.connectionPool") == "disabled") + slickChainConfig.config.getString("db.connectionPool") == "disabled" + ) assert(slickChainConfig.config.getInt("db.queueSize") == 5000) val nodeConfig = NodeAppConfig(dataDir, Vector.empty) @@ -64,7 +68,8 @@ class DBConfigTest extends BitcoinSAsyncTest { assert(slickNodeConfig.config.hasPath("db.numThreads")) assert(slickNodeConfig.config.getInt("db.numThreads") == 1) assert( - slickNodeConfig.config.getString("db.connectionPool") == "disabled") + slickNodeConfig.config.getString("db.connectionPool") == "disabled" + ) assert(slickNodeConfig.config.getInt("db.queueSize") == 5000) val walletConfig = WalletAppConfig(dataDir, Vector.empty) @@ -73,15 +78,18 @@ class DBConfigTest extends BitcoinSAsyncTest { assert(slickWalletConfig.config.hasPath("db.numThreads")) assert(slickWalletConfig.config.getInt("db.numThreads") == 1) assert( - slickWalletConfig.config.getString("db.connectionPool") == "disabled") + slickWalletConfig.config.getString("db.connectionPool") == "disabled" + ) assert(slickWalletConfig.config.getInt("db.queueSize") == 5000) } } it must "override a configuration with a hardcoded value" in { val memoryDb = - BitcoinSTestAppConfig.configWithEmbeddedDb(Some(ProjectType.Chain), - () => None) + BitcoinSTestAppConfig.configWithEmbeddedDb( + Some(ProjectType.Chain), + () => None + ) val mainnetConf = ConfigFactory.parseString("bitcoin-s.network = mainnet") val chainConfig: ChainAppConfig = { BitcoinSTestAppConfig.getNeutrinoTestConfig(mainnetConf).chainConf diff --git a/db-commons-test/src/test/scala/org/bitcoins/db/DbManagementTest.scala b/db-commons-test/src/test/scala/org/bitcoins/db/DbManagementTest.scala index a53e2fb0e7..28287f01b0 100644 --- a/db-commons-test/src/test/scala/org/bitcoins/db/DbManagementTest.scala +++ b/db-commons-test/src/test/scala/org/bitcoins/db/DbManagementTest.scala @@ -23,7 +23,8 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { } def createChainDbManagement( - chainAppConfig: ChainAppConfig): ChainDbManagement = + chainAppConfig: ChainAppConfig + ): ChainDbManagement = new ChainDbManagement with JdbcProfileComponent[ChainAppConfig] { override val ec: ExecutionContext = system.dispatcher @@ -38,7 +39,8 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { } def createWalletDbManagement( - walletAppConfig: WalletAppConfig): WalletDbManagement = + walletAppConfig: WalletAppConfig + ): WalletDbManagement = new WalletDbManagement with JdbcProfileComponent[WalletAppConfig] { override val ec: ExecutionContext = system.dispatcher @@ -53,8 +55,10 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { } it must "run migrations for chain db" in { - val chainAppConfig = ChainAppConfig(BitcoinSTestAppConfig.tmpDir(), - Vector(dbConfig(ProjectType.Chain))) + val chainAppConfig = ChainAppConfig( + BitcoinSTestAppConfig.tmpDir(), + Vector(dbConfig(ProjectType.Chain)) + ) val chainDbManagement = createChainDbManagement(chainAppConfig) val result = chainDbManagement.migrate() chainAppConfig.driver match { @@ -68,7 +72,7 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { val expected = 6 assert(result.migrationsExecuted == expected) val flywayInfo = chainDbManagement.info() - //+1 for << Flyway Schema Creation >> + // +1 for << Flyway Schema Creation >> assert(flywayInfo.applied().length == expected + 1) assert(flywayInfo.pending().length == 0) } @@ -77,8 +81,10 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { it must "run migrations for dlc db" in { val dlcAppConfig = - DLCAppConfig(BitcoinSTestAppConfig.tmpDir(), - Vector(dbConfig(ProjectType.DLC))) + DLCAppConfig( + BitcoinSTestAppConfig.tmpDir(), + Vector(dbConfig(ProjectType.DLC)) + ) val dlcDbManagement = createDLCDbManagement(dlcAppConfig) val result = dlcDbManagement.migrate() dlcAppConfig.driver match { @@ -93,15 +99,17 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { assert(result.migrationsExecuted == expected) val flywayInfo = dlcAppConfig.info() - //+1 for << Flyway Schema Creation >> + // +1 for << Flyway Schema Creation >> assert(flywayInfo.applied().length == expected + 1) assert(flywayInfo.pending().length == 0) } } it must "run migrations for wallet db" in { - val walletAppConfig = WalletAppConfig(BitcoinSTestAppConfig.tmpDir(), - Vector(dbConfig(ProjectType.Wallet))) + val walletAppConfig = WalletAppConfig( + BitcoinSTestAppConfig.tmpDir(), + Vector(dbConfig(ProjectType.Wallet)) + ) val walletDbManagement = createWalletDbManagement(walletAppConfig) val result = walletDbManagement.migrate() walletAppConfig.driver match { @@ -116,7 +124,7 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { assert(result.migrationsExecuted == expected) val flywayInfo = walletDbManagement.info() - //+1 for << Flyway Schema Creation >> + // +1 for << Flyway Schema Creation >> assert(flywayInfo.applied().length == expected + 1) assert(flywayInfo.pending().length == 0) } @@ -125,8 +133,10 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { it must "run migrations for node db" in { val nodeAppConfig = - NodeAppConfig(BitcoinSTestAppConfig.tmpDir(), - Vector(dbConfig(ProjectType.Node))) + NodeAppConfig( + BitcoinSTestAppConfig.tmpDir(), + Vector(dbConfig(ProjectType.Node)) + ) val nodeDbManagement = createNodeDbManagement(nodeAppConfig) val result = nodeDbManagement.migrate() nodeAppConfig.driver match { @@ -142,7 +152,7 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { assert(result.migrationsExecuted == expected) val flywayInfo = nodeDbManagement.info() - //+1 for << Flyway Schema Creation >> + // +1 for << Flyway Schema Creation >> assert(flywayInfo.applied().length == expected + 1) assert(flywayInfo.pending().length == 0) } @@ -150,8 +160,10 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { it must "run migrations for oracle db" in { val oracleAppConfig = - DLCOracleAppConfig(BitcoinSTestAppConfig.tmpDir(), - Vector(dbConfig(ProjectType.Oracle))) + DLCOracleAppConfig( + BitcoinSTestAppConfig.tmpDir(), + Vector(dbConfig(ProjectType.Oracle)) + ) val result = oracleAppConfig.migrate() oracleAppConfig.driver match { case SQLite => @@ -166,7 +178,7 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg { assert(result.migrationsExecuted == expected) val flywayInfo = oracleAppConfig.info() - //+1 for << Flyway Schema Creation >> + // +1 for << Flyway Schema Creation >> assert(flywayInfo.applied().length == expected + 1) assert(flywayInfo.pending().length == 0) } diff --git a/db-commons/src/main/scala/org/bitcoins/db/CRUD.scala b/db-commons/src/main/scala/org/bitcoins/db/CRUD.scala index 1d0f4d2363..6e9c659df5 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/CRUD.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/CRUD.scala @@ -7,18 +7,17 @@ import slick.lifted.AbstractTable import java.sql.SQLException import scala.concurrent.{ExecutionContext, Future} -/** Created by chris on 9/8/16. - * This is an abstract actor that can be used to implement any sort of - * actor that accesses a Postgres database. It creates - * read, update, upsert, and delete methods for your actor to call. - * You are responsible for the create function. You also need to specify - * the table and the database you are connecting to. +/** Created by chris on 9/8/16. This is an abstract actor that can be used to + * implement any sort of actor that accesses a Postgres database. It creates + * read, update, upsert, and delete methods for your actor to call. You are + * responsible for the create function. You also need to specify the table and + * the database you are connecting to. */ abstract class CRUD[T, PrimaryKeyType](implicit override val ec: ExecutionContext, - override val appConfig: DbAppConfig) - extends CRUDAction[T, PrimaryKeyType] + override val appConfig: DbAppConfig +) extends CRUDAction[T, PrimaryKeyType] with JdbcProfileComponent[DbAppConfig] { val schemaName: Option[String] = appConfig.schemaName @@ -27,31 +26,41 @@ abstract class CRUD[T, PrimaryKeyType](implicit import scala.language.implicitConversions - /** We need to cast from TableQuery's of internal types (e.g. AddressDAO#AddressTable) to external - * versions of them (e.g. AddressDAO().table). You'll notice that although the latter is a subtype - * of the first, this requires a cast since TableQuery is not covariant in its type parameter. + /** We need to cast from TableQuery's of internal types (e.g. + * AddressDAO#AddressTable) to external versions of them (e.g. + * AddressDAO().table). You'll notice that although the latter is a subtype + * of the first, this requires a cast since TableQuery is not covariant in + * its type parameter. * - * However, since Query is covariant in its first type parameter, I believe the cast from - * TableQuery[T1] to TableQuery[T2] will always be safe so long as T1 is a subtype of T2 - * AND T1#TableElementType is equal to T2#TableElementType. + * However, since Query is covariant in its first type parameter, I believe + * the cast from TableQuery[T1] to TableQuery[T2] will always be safe so long + * as T1 is a subtype of T2 AND T1#TableElementType is equal to + * T2#TableElementType. * - * The above conditions are always the case when this is called within DAOs as it is only - * ever used for things of the form TableQuery[XDAO().table] -> TableQuery[XDAO#XTable]. + * The above conditions are always the case when this is called within DAOs + * as it is only ever used for things of the form TableQuery[XDAO().table] -> + * TableQuery[XDAO#XTable]. */ implicit protected def tableQuerySafeSubtypeCast[ - SpecificT <: AbstractTable[_], + SpecificT <: AbstractTable[ + _ + ], SomeT <: SpecificT]( - tableQuery: TableQuery[SomeT]): TableQuery[SpecificT] = { + tableQuery: TableQuery[SomeT] + ): TableQuery[SpecificT] = { tableQuery.asInstanceOf[TableQuery[SpecificT]] } - /** Binding to the actual database itself, this is what is used to run querys */ + /** Binding to the actual database itself, this is what is used to run querys + */ def safeDatabase: SafeDatabase = SafeDatabase(this) /** create a record in the database * - * @param t - the record to be inserted - * @return the inserted record + * @param t + * \- the record to be inserted + * @return + * the inserted record */ def create(t: T): Future[T] = { logger.trace(s"Writing $t to DB with config: $appConfig") @@ -62,8 +71,10 @@ abstract class CRUD[T, PrimaryKeyType](implicit /** read a record from the database * - * @param id - the id of the record to be read - * @return Option[T] - the record if found, else none + * @param id + * \- the id of the record to be read + * @return + * Option[T] - the record if found, else none */ def read(id: PrimaryKeyType): Future[Option[T]] = { val query = findByPrimaryKey(id) @@ -84,8 +95,10 @@ abstract class CRUD[T, PrimaryKeyType](implicit /** delete the corresponding record in the database * - * @param t - the record to be deleted - * @return int - the number of rows affected by the deletion + * @param t + * \- the record to be deleted + * @return + * int - the number of rows affected by the deletion */ def delete(t: T): Future[Int] = { logger.debug("Deleting record: " + t) @@ -107,8 +120,10 @@ abstract class CRUD[T, PrimaryKeyType](implicit /** insert the record if it does not exist, update it if it does * - * @param t - the record to inserted / updated - * @return t - the record that has been inserted / updated + * @param t + * \- the record to inserted / updated + * @return + * t - the record that has been inserted / updated */ def upsert(t: T): Future[T] = { upsertAll(Vector(t)).flatMap { ts => @@ -120,7 +135,9 @@ abstract class CRUD[T, PrimaryKeyType](implicit } } - /** Upserts all of the given ts in the database, then returns the upserted values */ + /** Upserts all of the given ts in the database, then returns the upserted + * values + */ def upsertAll(ts: Vector[T]): Future[Vector[T]] = { safeDatabase.run(upsertAllAction(ts)) } @@ -142,27 +159,27 @@ case class SafeDatabase(jdbcProfile: JdbcProfileComponent[DbAppConfig]) jdbcActionExtensionMethods } - /** SQLite does not enable foreign keys by default. This query is - * used to enable it. It must be included in all connections to - * the database. + /** SQLite does not enable foreign keys by default. This query is used to + * enable it. It must be included in all connections to the database. */ private val foreignKeysPragma = sqlu"PRAGMA foreign_keys = TRUE;" private val sqlite = jdbcProfile.appConfig.driver == DatabaseDriver.SQLite /** Logs the given action and error, if we are not on mainnet */ private def logAndThrowError( - action: DBIOAction[_, NoStream, _]): PartialFunction[ - Throwable, - Nothing] = { case err: SQLException => + action: DBIOAction[_, NoStream, _] + ): PartialFunction[Throwable, Nothing] = { case err: SQLException => logger.error( - s"Error when executing query ${action.getDumpInfo.getNamePlusMainInfo}") + s"Error when executing query ${action.getDumpInfo.getNamePlusMainInfo}" + ) logger.error(s"$err") throw err } /** Runs the given DB action */ - def run[R](action: DBIOAction[R, NoStream, _])(implicit - ec: ExecutionContext): Future[R] = { + def run[R]( + action: DBIOAction[R, NoStream, _] + )(implicit ec: ExecutionContext): Future[R] = { val result = scala.concurrent.blocking { if (sqlite) database.run[R](foreignKeysPragma >> action.transactionally) else database.run[R](action.transactionally) @@ -172,11 +189,12 @@ case class SafeDatabase(jdbcProfile: JdbcProfileComponent[DbAppConfig]) } } - /** Runs the given DB sequence-returning DB action - * and converts the result to a vector + /** Runs the given DB sequence-returning DB action and converts the result to + * a vector */ - def runVec[R](action: DBIOAction[Seq[R], NoStream, _])(implicit - ec: ExecutionContext): Future[Vector[R]] = { + def runVec[R]( + action: DBIOAction[Seq[R], NoStream, _] + )(implicit ec: ExecutionContext): Future[Vector[R]] = { val result = scala.concurrent.blocking { if (sqlite) database.run[Seq[R]](foreignKeysPragma >> action.transactionally) diff --git a/db-commons/src/main/scala/org/bitcoins/db/CRUDAction.scala b/db-commons/src/main/scala/org/bitcoins/db/CRUDAction.scala index 1413813de1..8b31458683 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/CRUDAction.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/CRUDAction.scala @@ -4,15 +4,16 @@ import scala.concurrent.ExecutionContext abstract class CRUDAction[T, PrimaryKeyType](implicit val ec: ExecutionContext, - override val appConfig: DbAppConfig) - extends JdbcProfileComponent[DbAppConfig] { + override val appConfig: DbAppConfig +) extends JdbcProfileComponent[DbAppConfig] { import profile.api._ /** The table inside our database we are inserting into */ val table: profile.api.TableQuery[_ <: profile.api.Table[T]] def createAllAction( - ts: Vector[T]): DBIOAction[Vector[T], NoStream, Effect.Write] + ts: Vector[T] + ): DBIOAction[Vector[T], NoStream, Effect.Write] def createAction(t: T): DBIOAction[T, NoStream, Effect.Write] = { createAllAction(Vector(t)) @@ -23,27 +24,29 @@ abstract class CRUDAction[T, PrimaryKeyType](implicit updateAllAction(Vector(t)).map { ts => ts.headOption match { case Some(updated) => updated - case None => throw UpdateFailedException("Update failed for: " + t) + case None => throw UpdateFailedException("Update failed for: " + t) } } } /** return all rows that have a certain primary key * - * @param id primary key of the row to return - * @return Query object corresponding to the selected rows + * @param id + * primary key of the row to return + * @return + * Query object corresponding to the selected rows */ protected def findByPrimaryKey(id: PrimaryKeyType): Query[Table[T], T, Seq] = findByPrimaryKeys(Vector(id)) /** Finds the rows that correlate to the given primary keys */ protected def findByPrimaryKeys( - ids: Vector[PrimaryKeyType]): Query[Table[T], T, Seq] + ids: Vector[PrimaryKeyType] + ): Query[Table[T], T, Seq] - def findByPrimaryKeysAction(ids: Vector[PrimaryKeyType]): DBIOAction[ - Vector[T], - NoStream, - Effect.Read] = { + def findByPrimaryKeysAction( + ids: Vector[PrimaryKeyType] + ): DBIOAction[Vector[T], NoStream, Effect.Read] = { if (ids.isEmpty) { DBIO.successful(Vector.empty) } else { @@ -53,7 +56,8 @@ abstract class CRUDAction[T, PrimaryKeyType](implicit } def findByPrimaryKeyAction( - id: PrimaryKeyType): DBIOAction[Option[T], NoStream, Effect.Read] = { + id: PrimaryKeyType + ): DBIOAction[Option[T], NoStream, Effect.Read] = { findByPrimaryKey(id).result.map(_.headOption) } @@ -61,20 +65,18 @@ abstract class CRUDAction[T, PrimaryKeyType](implicit protected def findAll(ts: Vector[T]): Query[Table[T], T, Seq] - def findAllAction(): DBIOAction[ - Vector[T], - profile.api.NoStream, - profile.api.Effect.Read] = { + def findAllAction() + : DBIOAction[Vector[T], profile.api.NoStream, profile.api.Effect.Read] = { table.result.map(_.toVector) } - /** Updates all of the given ts. - * Returns all ts that actually existed in the database and got updated - * This method discards things that did not exist in the database, - * thus could not be updated + /** Updates all of the given ts. Returns all ts that actually existed in the + * database and got updated This method discards things that did not exist in + * the database, thus could not be updated */ def updateAllAction( - ts: Vector[T]): DBIOAction[Vector[T], NoStream, Effect.Write] = { + ts: Vector[T] + ): DBIOAction[Vector[T], NoStream, Effect.Write] = { val updateActions: Vector[DBIOAction[Option[T], NoStream, Effect.Write]] = { ts.map { t => find(t).update(t).flatMap { rowsUpdated => @@ -83,8 +85,11 @@ abstract class CRUDAction[T, PrimaryKeyType](implicit } else if (rowsUpdated == 1) { DBIO.successful(Some(t)) } else { - DBIO.failed(new RuntimeException( - s"Updated more rows that we intended to update, updated=$rowsUpdated")) + DBIO.failed( + new RuntimeException( + s"Updated more rows that we intended to update, updated=$rowsUpdated" + ) + ) } } @@ -94,24 +99,24 @@ abstract class CRUDAction[T, PrimaryKeyType](implicit DBIO.sequence(updateActions) } - //discard all rows that did not exist, - //thus cannot be updated + // discard all rows that did not exist, + // thus cannot be updated sequencedA.map(_.flatten) } def upsertAction( - t: T): DBIOAction[T, NoStream, Effect.Write with Effect.Read] = { + t: T + ): DBIOAction[T, NoStream, Effect.Write with Effect.Read] = { upsertAllAction(Vector(t)).map(_.head) } - /** Upsert all of the given ts. - * Returns all ts that were inserted or updated - * @see https://scala-slick.org/doc/3.3.3/queries.html#upserting + /** Upsert all of the given ts. Returns all ts that were inserted or updated + * @see + * https://scala-slick.org/doc/3.3.3/queries.html#upserting */ - def upsertAllAction(ts: Vector[T]): DBIOAction[ - Vector[T], - NoStream, - Effect.Write with Effect.Read] = { + def upsertAllAction( + ts: Vector[T] + ): DBIOAction[Vector[T], NoStream, Effect.Write with Effect.Read] = { val upsertActions = { ts.map { t => table.insertOrUpdate(t).flatMap(_ => find(t).result.map(_.headOption)) @@ -126,16 +131,15 @@ abstract class CRUDAction[T, PrimaryKeyType](implicit } def deleteAllAction( - ts: Vector[T]): DBIOAction[Int, NoStream, Effect.Write] = { + ts: Vector[T] + ): DBIOAction[Int, NoStream, Effect.Write] = { val query = findAll(ts) query.delete } /** WARNING: Deletes all rows in table, use with care */ - def deleteAllAction(): DBIOAction[ - Int, - NoStream, - Effect.Write with Effect.Transactional] = { + def deleteAllAction() + : DBIOAction[Int, NoStream, Effect.Write with Effect.Transactional] = { table.delete } diff --git a/db-commons/src/main/scala/org/bitcoins/db/CRUDAutoInc.scala b/db-commons/src/main/scala/org/bitcoins/db/CRUDAutoInc.scala index cac1e20a58..4787366557 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/CRUDAutoInc.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/CRUDAutoInc.scala @@ -6,18 +6,17 @@ import scala.concurrent.{ExecutionContext, Future} abstract class CRUDAutoInc[T <: DbRowAutoInc[T]](implicit ec: ExecutionContext, - override val appConfig: DbAppConfig) - extends CRUD[T, Long]()(ec, appConfig) + override val appConfig: DbAppConfig +) extends CRUD[T, Long]()(ec, appConfig) with TableAutoIncComponent[T] { import profile.api._ /** The table inside our database we are inserting into */ override val table: profile.api.TableQuery[_ <: TableAutoInc[T]] - override def createAllAction(ts: Vector[T]): profile.api.DBIOAction[ - Vector[T], - profile.api.NoStream, - Effect.Write] = { + override def createAllAction( + ts: Vector[T] + ): profile.api.DBIOAction[Vector[T], profile.api.NoStream, Effect.Write] = { val idQuery = table.map(_.id) val idAutoInc = table.returning(idQuery) val query = { @@ -33,11 +32,13 @@ abstract class CRUDAutoInc[T <: DbRowAutoInc[T]](implicit } override protected def findByPrimaryKey( - id: Long): Query[TableAutoInc[T], T, Seq] = + id: Long + ): Query[TableAutoInc[T], T, Seq] = table.filter(_.id === id) override def findByPrimaryKeys( - ids: Vector[Long]): Query[TableAutoInc[T], T, Seq] = { + ids: Vector[Long] + ): Query[TableAutoInc[T], T, Seq] = { table.filter { t => t.id.inSet(ids) } @@ -49,9 +50,9 @@ abstract class CRUDAutoInc[T <: DbRowAutoInc[T]](implicit } } -/** Defines a table that has an auto incremented fields that is named id. - * This is useful for things we want to store that don't have an - * inherent id such as a hash. +/** Defines a table that has an auto incremented fields that is named id. This + * is useful for things we want to store that don't have an inherent id such as + * a hash. * @param tag * @param tableName * @tparam T @@ -62,8 +63,8 @@ trait TableAutoIncComponent[T <: DbRowAutoInc[T]] { self: CRUDAutoInc[T] => abstract class TableAutoInc[T]( tag: profile.api.Tag, schemaName: Option[String], - tableName: String) - extends profile.api.Table[T](tag, schemaName, tableName) { + tableName: String + ) extends profile.api.Table[T](tag, schemaName, tableName) { def id: Rep[Long] = column[Long]("id", O.PrimaryKey, O.AutoInc) } } diff --git a/db-commons/src/main/scala/org/bitcoins/db/DatadirUtil.scala b/db-commons/src/main/scala/org/bitcoins/db/DatadirUtil.scala index c3f639a1e5..5bcba1e11f 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/DatadirUtil.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/DatadirUtil.scala @@ -11,7 +11,8 @@ object DatadirUtil { def zipDatadir(source: Path, target: Path): Try[Path] = Try { if (Files.exists(target)) { throw new IOException( - s"Cannot zip datadir. Target file already exists: $target") + s"Cannot zip datadir. Target file already exists: $target" + ) } val temp = Files.createTempDirectory(source, "backup") try { @@ -36,10 +37,11 @@ object DatadirUtil { ) ) - SQLiteUtil.backupDirectory(source = source, - target = temp, - fileNameFilter = - Vector(".*chaindb.sqlite$".r, tempRE)) + SQLiteUtil.backupDirectory( + source = source, + target = temp, + fileNameFilter = Vector(".*chaindb.sqlite$".r, tempRE) + ) FileUtil.zipDirectory( source = temp, diff --git a/db-commons/src/main/scala/org/bitcoins/db/DbAppConfig.scala b/db-commons/src/main/scala/org/bitcoins/db/DbAppConfig.scala index df5800ae52..7726f5fe71 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/DbAppConfig.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/DbAppConfig.scala @@ -115,9 +115,10 @@ abstract class DbAppConfig extends AppConfig { val usedConf = overrideConf.withFallback(config) Try { - val c = DatabaseConfig.forConfig[JdbcProfile](path = - s"bitcoin-s.$moduleName", - config = usedConf) + val c = DatabaseConfig.forConfig[JdbcProfile]( + path = s"bitcoin-s.$moduleName", + config = usedConf + ) logger.trace(s"Resolved DB config: ${ConfigOps(c.config).asReadableJson}") c @@ -137,13 +138,13 @@ abstract class DbAppConfig extends AppConfig { hikariLoggingOpt match { case Some(bool) => bool case None => - //default hikari logging off + // default hikari logging off false } } - /** Gets how often we should log hikari connection pool stats - * if None, this means [[isHikariLoggingEnabled]] is not enabled + /** Gets how often we should log hikari connection pool stats if None, this + * means [[isHikariLoggingEnabled]] is not enabled */ lazy val hikariLoggingInterval: Option[Duration] = { if (isHikariLoggingEnabled) { @@ -152,7 +153,7 @@ abstract class DbAppConfig extends AppConfig { val interval = intervalOpt match { case Some(interval) => interval case None => - //default to 1 minute if nothing is set + // default to 1 minute if nothing is set new FiniteDuration(1, TimeUnit.MINUTES) } Some(interval) diff --git a/db-commons/src/main/scala/org/bitcoins/db/DbCommonsColumnMappers.scala b/db-commons/src/main/scala/org/bitcoins/db/DbCommonsColumnMappers.scala index 876a587353..f1200a7aa0 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/DbCommonsColumnMappers.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/DbCommonsColumnMappers.scala @@ -81,8 +81,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { } - implicit val doubleSha256DigestBEMapper: BaseColumnType[ - DoubleSha256DigestBE] = + implicit val doubleSha256DigestBEMapper + : BaseColumnType[DoubleSha256DigestBE] = MappedColumnType.base[DoubleSha256DigestBE, String]( _.hex, DoubleSha256DigestBE.fromHex @@ -91,7 +91,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { implicit val doubleSha256DigestMapper: BaseColumnType[DoubleSha256Digest] = MappedColumnType.base[DoubleSha256Digest, String]( _.hex, - DoubleSha256Digest.fromHex) + DoubleSha256Digest.fromHex + ) implicit val bigIntMapper: BaseColumnType[BigInt] = MappedColumnType @@ -129,11 +130,14 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { implicit val ecDigitalSignatureMapper: BaseColumnType[ECDigitalSignature] = MappedColumnType.base[ECDigitalSignature, String]( _.hex, - ECDigitalSignature.fromHex) + ECDigitalSignature.fromHex + ) implicit val signingVersionMapper: BaseColumnType[SigningVersion] = - MappedColumnType.base[SigningVersion, String](_.toString, - SigningVersion.fromString) + MappedColumnType.base[SigningVersion, String]( + _.toString, + SigningVersion.fromString + ) implicit val schnorrPublicKeyMapper: BaseColumnType[SchnorrPublicKey] = MappedColumnType @@ -155,7 +159,9 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { tcomap = UInt8(_) ) - /** Responsible for mapping a [[org.bitcoins.core.number.UInt32 UInt32]] to a long in Slick, and vice versa */ + /** Responsible for mapping a [[org.bitcoins.core.number.UInt32 UInt32]] to a + * long in Slick, and vice versa + */ implicit val uInt32Mapper: BaseColumnType[UInt32] = MappedColumnType.base[UInt32, Long]( tmap = _.toLong, @@ -166,7 +172,10 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { MappedColumnType.base[Int32, Long](tmap = _.toLong, tcomap = Int32(_)) } - /** Responsible for mapping a [[org.bitcoins.core.protocol.transaction.TransactionOutput TransactionOutput]] to hex in Slick, and vice versa */ + /** Responsible for mapping a + * [[org.bitcoins.core.protocol.transaction.TransactionOutput TransactionOutput]] + * to hex in Slick, and vice versa + */ implicit val transactionOutputMapper: BaseColumnType[TransactionOutput] = { MappedColumnType.base[TransactionOutput, String]( _.hex, @@ -192,8 +201,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { padded.toHex } - implicit val transactionOutPointMapper: BaseColumnType[ - TransactionOutPoint] = { + implicit val transactionOutPointMapper + : BaseColumnType[TransactionOutPoint] = { MappedColumnType .base[TransactionOutPoint, String](_.hex, TransactionOutPoint(_)) } @@ -206,7 +215,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { MappedColumnType .base[ScriptWitness, String]( _.hex, - hex => RawScriptWitnessParser.read(ByteVector.fromValidHex(hex))) + hex => RawScriptWitnessParser.read(ByteVector.fromValidHex(hex)) + ) } implicit val byteVectorMapper: BaseColumnType[ByteVector] = { @@ -239,7 +249,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { .base[HDPurpose, Int]( _.constant, purpose => - HDPurposes.fromConstant(purpose).getOrElse(HDPurpose(purpose))) + HDPurposes.fromConstant(purpose).getOrElse(HDPurpose(purpose)) + ) implicit val bitcoinAddressMapper: BaseColumnType[BitcoinAddress] = MappedColumnType @@ -288,14 +299,17 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { implicit val addressTagTypeMapper: BaseColumnType[AddressTagType] = { MappedColumnType - .base[AddressTagType, String](_.typeName, - InternalAddressTagType.fromString) + .base[AddressTagType, String]( + _.typeName, + InternalAddressTagType.fromString + ) } implicit val hdAccountMapper: BaseColumnType[HDAccount] = { MappedColumnType.base[HDAccount, String]( _.toString, - str => HDAccount.fromPath(BIP32Path.fromString(str)).get) + str => HDAccount.fromPath(BIP32Path.fromString(str)).get + ) } implicit val contractInfoMapper: BaseColumnType[ContractInfo] = { @@ -308,8 +322,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { .base[ContractInfoV0TLV, String](_.hex, ContractInfoV0TLV.fromHex) } - implicit val contractDescriptorTLVMapper: BaseColumnType[ - ContractDescriptorTLV] = { + implicit val contractDescriptorTLVMapper + : BaseColumnType[ContractDescriptorTLV] = { MappedColumnType .base[ContractDescriptorTLV, String](_.hex, ContractDescriptorTLV.fromHex) } @@ -319,8 +333,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { .base[OracleParamsV0TLV, String](_.hex, OracleParamsV0TLV.fromHex) } - implicit val negotiationFieldsTLVMapper: BaseColumnType[ - NegotiationFieldsTLV] = { + implicit val negotiationFieldsTLVMapper + : BaseColumnType[NegotiationFieldsTLV] = { MappedColumnType .base[NegotiationFieldsTLV, String](_.hex, NegotiationFieldsTLV.fromHex) } @@ -353,8 +367,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { ) } - implicit val dlcOutcomeTypeVecMapper: BaseColumnType[ - Vector[DLCOutcomeType]] = { + implicit val dlcOutcomeTypeVecMapper + : BaseColumnType[Vector[DLCOutcomeType]] = { val enumStr = "Enum:" val unsignedNumStr = "Unsigned:" @@ -390,8 +404,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { ) } - implicit val singleOracleInfoVecMapper: BaseColumnType[ - Vector[SingleOracleInfo]] = + implicit val singleOracleInfoVecMapper + : BaseColumnType[Vector[SingleOracleInfo]] = MappedColumnType.base[Vector[SingleOracleInfo], String]( _.map(_.announcement.hex).mkString("|"), str => { @@ -406,7 +420,8 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { implicit val blockStampWithFutureMapper: BaseColumnType[BlockTimeStamp] = { MappedColumnType.base[BlockTimeStamp, Long]( _.toUInt32.toLong, - long => BlockTimeStamp(UInt32(long))) + long => BlockTimeStamp(UInt32(long)) + ) } implicit val partialSigMapper: BaseColumnType[PartialSignature] = { @@ -420,15 +435,17 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { _.foldLeft("")(_ ++ _.hex), hex => if (hex.isEmpty) Vector.empty - else InputPSBTMap(hex ++ "00").partialSignatures) + else InputPSBTMap(hex ++ "00").partialSignatures + ) } - implicit val satoshisPerVirtualByteMapper: BaseColumnType[ - SatoshisPerVirtualByte] = { + implicit val satoshisPerVirtualByteMapper + : BaseColumnType[SatoshisPerVirtualByte] = { MappedColumnType .base[SatoshisPerVirtualByte, String]( _.currencyUnit.hex, - hex => SatoshisPerVirtualByte(Satoshis.fromHex(hex))) + hex => SatoshisPerVirtualByte(Satoshis.fromHex(hex)) + ) } implicit val networkMapper: BaseColumnType[BitcoinNetwork] = { @@ -436,15 +453,16 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { .base[BitcoinNetwork, String](_.name, BitcoinNetworks.fromString) } - implicit val schnorrDigitalSignatureMapper: BaseColumnType[ - SchnorrDigitalSignature] = { + implicit val schnorrDigitalSignatureMapper + : BaseColumnType[SchnorrDigitalSignature] = { MappedColumnType.base[SchnorrDigitalSignature, String]( _.hex, - SchnorrDigitalSignature.fromHex) + SchnorrDigitalSignature.fromHex + ) } - implicit val schnorrDigitalSignatureVecMapper: BaseColumnType[ - Vector[SchnorrDigitalSignature]] = { + implicit val schnorrDigitalSignatureVecMapper + : BaseColumnType[Vector[SchnorrDigitalSignature]] = { MappedColumnType.base[Vector[SchnorrDigitalSignature], String]( _.foldLeft("")(_ ++ _.hex), _.toArray @@ -455,22 +473,25 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { ) } - implicit val walletStateDescriptorTypeMapper: BaseColumnType[ - WalletStateDescriptorType] = + implicit val walletStateDescriptorTypeMapper + : BaseColumnType[WalletStateDescriptorType] = MappedColumnType.base[WalletStateDescriptorType, String]( _.toString, - WalletStateDescriptorType.fromString) + WalletStateDescriptorType.fromString + ) - implicit val walletStateDescriptorMapper: BaseColumnType[ - WalletStateDescriptor] = + implicit val walletStateDescriptorMapper + : BaseColumnType[WalletStateDescriptor] = MappedColumnType.base[WalletStateDescriptor, String]( _.toString, - WalletStateDescriptor.fromString) + WalletStateDescriptor.fromString + ) implicit val ecAdaptorSignatureMapper: BaseColumnType[ECAdaptorSignature] = { MappedColumnType.base[ECAdaptorSignature, String]( _.hex, - ECAdaptorSignature.fromHex) + ECAdaptorSignature.fromHex + ) } implicit val dlcStateMapper: BaseColumnType[DLCState] = { @@ -481,13 +502,15 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { implicit val eventDescriptorTLVMapper: BaseColumnType[EventDescriptorTLV] = { MappedColumnType.base[EventDescriptorTLV, String]( _.hex, - EventDescriptorTLV.fromHex) + EventDescriptorTLV.fromHex + ) } implicit val oracleAnnouncementTLV: BaseColumnType[OracleAnnouncementTLV] = { MappedColumnType.base[OracleAnnouncementTLV, String]( _.hex, - OracleAnnouncementTLV.fromHex) + OracleAnnouncementTLV.fromHex + ) } implicit val lnInvoiceMapper: BaseColumnType[LnInvoice] = { @@ -503,15 +526,18 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { } implicit val extKeyPubVersion: BaseColumnType[ExtKeyPubVersion] = { - MappedColumnType.base[ExtKeyPubVersion, String](_.hex, - ExtKeyPubVersion.fromHex) + MappedColumnType.base[ExtKeyPubVersion, String]( + _.hex, + ExtKeyPubVersion.fromHex + ) } - implicit val dlcSerializationVersion: BaseColumnType[ - DLCSerializationVersion] = { + implicit val dlcSerializationVersion + : BaseColumnType[DLCSerializationVersion] = { MappedColumnType.base[DLCSerializationVersion, String]( _.toString, - DLCSerializationVersion.fromString) + DLCSerializationVersion.fromString + ) } implicit val dlcOfferTLVMapper: BaseColumnType[DLCOfferTLV] = { @@ -534,21 +560,25 @@ class DbCommonsColumnMappers(val profile: JdbcProfile) { MappedColumnType.base[PaymentSecret, String](_.hex, PaymentSecret.fromHex) implicit val ShortChannelIdMapper: BaseColumnType[ShortChannelId] = - MappedColumnType.base[ShortChannelId, Long](_.u64.toLong, - l => ShortChannelId(UInt64(l))) + MappedColumnType.base[ShortChannelId, Long]( + _.u64.toLong, + l => ShortChannelId(UInt64(l)) + ) implicit val MilliSatoshisMapper: BaseColumnType[MilliSatoshis] = MappedColumnType.base[MilliSatoshis, Long](_.toLong, MilliSatoshis.apply(_)) - implicit val nodeStateDescriptorTypeMapper: BaseColumnType[ - NodeStateDescriptorType] = + implicit val nodeStateDescriptorTypeMapper + : BaseColumnType[NodeStateDescriptorType] = MappedColumnType.base[NodeStateDescriptorType, String]( _.toString, - NodeStateDescriptorType.fromString) + NodeStateDescriptorType.fromString + ) implicit val nodeStateDescriptorMapper: BaseColumnType[NodeStateDescriptor] = MappedColumnType.base[NodeStateDescriptor, String]( _.toString, - NodeStateDescriptor.fromString) + NodeStateDescriptor.fromString + ) } diff --git a/db-commons/src/main/scala/org/bitcoins/db/DbManagement.scala b/db-commons/src/main/scala/org/bitcoins/db/DbManagement.scala index a91cc292dc..9fb198e55e 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/DbManagement.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/DbManagement.scala @@ -16,7 +16,7 @@ trait DbManagement extends BitcoinSLogger { import scala.language.implicitConversions protected lazy val flyway: Flyway = { - //create the database if it doesn't exist yet in sqlite3 + // create the database if it doesn't exist yet in sqlite3 appConfig.driver match { case SQLite => SQLiteUtil.createDbFileIfDNE(appConfig.dbPath, appConfig.dbName) @@ -55,20 +55,26 @@ trait DbManagement extends BitcoinSLogger { /** Internally, slick defines the schema member as * - * def schema: SchemaDescription = buildTableSchemaDescription(q.shaped.value.asInstanceOf[Table[_]]) + * def schema: SchemaDescription = + * buildTableSchemaDescription(q.shaped.value.asInstanceOf[Table[_]]) * - * we need to cast between TableQuery's of specific table types to the more generic TableQuery[Table[_]] - * to get methods in this trait working as they require schema (which essentially does this cast anyway) + * we need to cast between TableQuery's of specific table types to the more + * generic TableQuery[Table[_]] to get methods in this trait working as they + * require schema (which essentially does this cast anyway) * - * This cast is needed because TableQuery is not covariant in its type parameter. However, since Query - * is covariant in its first type parameter, I believe the cast from TableQuery[T1] to TableQuery[T2] will - * always be safe so long as T1 is a subtype of T2 AND T1#TableElementType is equal to T2#TableElementType. + * This cast is needed because TableQuery is not covariant in its type + * parameter. However, since Query is covariant in its first type parameter, + * I believe the cast from TableQuery[T1] to TableQuery[T2] will always be + * safe so long as T1 is a subtype of T2 AND T1#TableElementType is equal to + * T2#TableElementType. * - * The above conditions are always the case when this is called in the current code base and will - * stay that way so long as no one tries anything too fancy. + * The above conditions are always the case when this is called in the + * current code base and will stay that way so long as no one tries anything + * too fancy. */ implicit protected def tableQueryToWithSchema( - tableQuery: TableQuery[_]): TableQuery[Table[_]] = { + tableQuery: TableQuery[_] + ): TableQuery[Table[_]] = { tableQuery.asInstanceOf[TableQuery[Table[_]]] } @@ -89,7 +95,8 @@ trait DbManagement extends BitcoinSLogger { /** The query needed to create the given table */ private def createTableQuery( table: TableQuery[_ <: Table[_]], - createIfNotExists: Boolean) = { + createIfNotExists: Boolean + ) = { if (createIfNotExists) { table.schema.createIfNotExists } else { @@ -100,8 +107,8 @@ trait DbManagement extends BitcoinSLogger { /** Creates the given table */ def createTable( table: TableQuery[_ <: Table[_]], - createIfNotExists: Boolean = true)(implicit - ec: ExecutionContext): Future[Unit] = { + createIfNotExists: Boolean = true + )(implicit ec: ExecutionContext): Future[Unit] = { val tableName = table.baseTableRow.tableName logger.debug(s"Creating table $tableName with DB config: $appConfig") @@ -117,8 +124,9 @@ trait DbManagement extends BitcoinSLogger { result } - def dropTable(tableName: String)(implicit - ec: ExecutionContext): Future[Int] = { + def dropTable( + tableName: String + )(implicit ec: ExecutionContext): Future[Int] = { val fullTableName = appConfig.schemaName.map(_ + ".").getOrElse("") + tableName val sql = sqlu"""DROP TABLE IF EXISTS #$fullTableName""" @@ -129,8 +137,9 @@ trait DbManagement extends BitcoinSLogger { result } - def createSchema(createIfNotExists: Boolean = true)(implicit - ec: ExecutionContext): Future[Unit] = + def createSchema( + createIfNotExists: Boolean = true + )(implicit ec: ExecutionContext): Future[Unit] = appConfig.schemaName match { case None => Future.unit @@ -144,7 +153,8 @@ trait DbManagement extends BitcoinSLogger { } /** Returns flyway information about the state of migrations - * @see https://flywaydb.org/documentation/command/info + * @see + * https://flywaydb.org/documentation/command/info */ def info(): MigrationInfoService = { flyway.info() @@ -163,7 +173,8 @@ trait DbManagement extends BitcoinSLogger { /** Executes migrations related to this database * - * @see [[https://flywaydb.org/documentation/api/#programmatic-configuration-java]] + * @see + * [[https://flywaydb.org/documentation/api/#programmatic-configuration-java]] */ def migrate(): MigrateResult = { try { @@ -172,9 +183,10 @@ trait DbManagement extends BitcoinSLogger { case err: FlywayException => logger.warn( s"Failed to apply first round of migrations, attempting baseline and re-apply", - err) - //maybe we have an existing database, so attempt to baseline the existing - //database and then apply migrations again + err + ) + // maybe we have an existing database, so attempt to baseline the existing + // database and then apply migrations again flyway.baseline() flyway.migrate() } @@ -182,10 +194,11 @@ trait DbManagement extends BitcoinSLogger { /** Runs flyway clean * - * WARNING: - * THIS DELETES ALL DATA IN THE DATABASE, YOU PROBABLY DON'T WANT THIS UNLESS YOU ARE USING TESTS + * WARNING: THIS DELETES ALL DATA IN THE DATABASE, YOU PROBABLY DON'T WANT + * THIS UNLESS YOU ARE USING TESTS * - * @see https://flywaydb.org/documentation/command/clean + * @see + * https://flywaydb.org/documentation/command/clean */ def clean(): CleanResult = { flyway.clean() diff --git a/db-commons/src/main/scala/org/bitcoins/db/HikariLogging.scala b/db-commons/src/main/scala/org/bitcoins/db/HikariLogging.scala index 6803f80b3a..0132456fd6 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/HikariLogging.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/HikariLogging.scala @@ -48,9 +48,10 @@ case class HikariLogging( } } - /** From the docs: - * How long each connection is used before being returned to the pool. This is the "out of pool" or "in-use" time. - * @see https://github.com/brettwooldridge/HikariCP/wiki/Dropwizard-Metrics + /** From the docs: How long each connection is used before being returned to + * the pool. This is the "out of pool" or "in-use" time. + * @see + * https://github.com/brettwooldridge/HikariCP/wiki/Dropwizard-Metrics */ private case class HikariPoolUsageUpdate( `75thPercentile`: Double, @@ -81,37 +82,41 @@ case class HikariLogging( } } - //this is needed to get the 'AsyncExecutor' bean below to register properly - //dbConfig.database.ioExecutionContext + // this is needed to get the 'AsyncExecutor' bean below to register properly + // dbConfig.database.ioExecutionContext private lazy val poolName = hikariDataSource.getPoolName private lazy val mBeanServer = ManagementFactory.getPlatformMBeanServer lazy val aeBeanName = new ObjectName( - s"slick:type=AsyncExecutor,name=$poolName") + s"slick:type=AsyncExecutor,name=$poolName" + ) lazy val poolBeanName = new ObjectName( - s"com.zaxxer.hikari:type=Pool ($poolName)") + s"com.zaxxer.hikari:type=Pool ($poolName)" + ) lazy val poolConfigBeanName = new ObjectName( s"com.zaxxer.hikari:type=PoolConfig ($poolName)" ) - /** MBean uses random string incantations for - * accessing attributes :-( + /** MBean uses random string incantations for accessing attributes :-( * - * @see [[https://github.com/brettwooldridge/HikariCP/wiki/MBean-(JMX)-Monitoring-and-Management#programmatic-access HikariCP docs]] + * @see + * [[https://github.com/brettwooldridge/HikariCP/wiki/MBean-(JMX)-Monitoring-and-Management#programmatic-access HikariCP docs]] */ private lazy val objectName = new ObjectName( s"com.zaxxer.hikari:type=Pool ($poolName)" ) - /** @see https://github.com/brettwooldridge/HikariCP/wiki/MBean-(JMX)-Monitoring-and-Management + /** @see + * https://github.com/brettwooldridge/HikariCP/wiki/MBean-(JMX)-Monitoring-and-Management */ private lazy val hikariMxBean = JMX.newMXBeanProxy(mBeanServer, objectName, classOf[HikariPoolMXBean]) - /** @see http://slick.lightbend.com/doc/3.3.0/config.html#monitoring + /** @see + * http://slick.lightbend.com/doc/3.3.0/config.html#monitoring */ private lazy val slickMxBean = JMX.newMXBeanProxy(mBeanServer, aeBeanName, classOf[AsyncExecutorMXBean]) @@ -183,7 +188,8 @@ case class HikariLogging( logHikariStats, interval.toMillis, interval.toMillis, - TimeUnit.MILLISECONDS) + TimeUnit.MILLISECONDS + ) cancelOpt = Some(future) started = true this @@ -212,12 +218,15 @@ object HikariLogging extends BitcoinSLogger { private[db] val scheduler = Executors.newScheduledThreadPool(1) /** Returns a started hikari logger if configuration is correct, else None - * @param jdbcProfileComponent the database component we are logging for - * @param interval how often the hikari logs should be output + * @param jdbcProfileComponent + * the database component we are logging for + * @param interval + * how often the hikari logs should be output */ def fromJdbcProfileComponent[T <: DbAppConfig]( jdbcProfileComponent: JdbcProfileComponent[T], - interval: Duration): Option[HikariLogging] = { + interval: Duration + ): Option[HikariLogging] = { val dataSource = jdbcProfileComponent.database.source val moduleName = jdbcProfileComponent.appConfig.moduleName dataSource match { diff --git a/db-commons/src/main/scala/org/bitcoins/db/JdbcProfileComponent.scala b/db-commons/src/main/scala/org/bitcoins/db/JdbcProfileComponent.scala index 7894a37fca..2fab39405b 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/JdbcProfileComponent.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/JdbcProfileComponent.scala @@ -10,8 +10,8 @@ trait JdbcProfileComponent[+ConfigType <: DbAppConfig] extends BitcoinSLogger { def appConfig: ConfigType - /** The configuration details for connecting/using the database for our projects - * that require database connections + /** The configuration details for connecting/using the database for our + * projects that require database connections */ lazy val dbConfig: DatabaseConfig[JdbcProfile] = { appConfig.slickDbConfig @@ -29,16 +29,17 @@ trait JdbcProfileComponent[+ConfigType <: DbAppConfig] extends BitcoinSLogger { private[this] var hikariLoggerOpt: Option[HikariLogging] = None /** Starts the background logger for hikari - * @param interval - how often hikari logs database connection pool information + * @param interval + * \- how often hikari logs database connection pool information */ protected def startHikariLogger(interval: Duration): HikariLogging = { hikariLoggerOpt match { case Some(hikarkiLogger) => hikarkiLogger case None => - //this is needed to get the 'AsyncExecutor' bean below to register properly - //dbConfig.database.ioExecutionContext + // this is needed to get the 'AsyncExecutor' bean below to register properly + // dbConfig.database.ioExecutionContext val _ = database.ioExecutionContext - //start a new one + // start a new one HikariLogging.fromJdbcProfileComponent(this, interval) match { case Some(hikariLogger) => hikariLoggerOpt = Some(hikariLogger) diff --git a/db-commons/src/main/scala/org/bitcoins/db/PostgresUtil.scala b/db-commons/src/main/scala/org/bitcoins/db/PostgresUtil.scala index 2b15aac5ae..588a4ff209 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/PostgresUtil.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/PostgresUtil.scala @@ -11,8 +11,10 @@ object PostgresUtil { moduleName } else { val schemaName = s"${moduleName}_$walletName" - require(schemaName.length <= schemaNameMaxLen, - s"Schema name length must be up to 63 characters: `$schemaName`") + require( + schemaName.length <= schemaNameMaxLen, + s"Schema name length must be up to 63 characters: `$schemaName`" + ) schemaName } } diff --git a/db-commons/src/main/scala/org/bitcoins/db/SQLiteTableInfo.scala b/db-commons/src/main/scala/org/bitcoins/db/SQLiteTableInfo.scala index 3585b26355..ad014765f2 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/SQLiteTableInfo.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/SQLiteTableInfo.scala @@ -1,6 +1,8 @@ package org.bitcoins.db -/** @param name The name of the table - * @param sql The SQL executed to create the table +/** @param name + * The name of the table + * @param sql + * The SQL executed to create the table */ case class SQLiteTableInfo(name: String, sql: String) diff --git a/db-commons/src/main/scala/org/bitcoins/db/SQLiteUtil.scala b/db-commons/src/main/scala/org/bitcoins/db/SQLiteUtil.scala index 4c40c384b7..00fbb06668 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/SQLiteUtil.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/SQLiteUtil.scala @@ -16,26 +16,30 @@ object SQLiteUtil extends BitcoinSLogger { source: Path, target: Path, fileNameFilter: Vector[Regex] = Vector.empty, - dbExtension: String = ".sqlite"): Unit = { + dbExtension: String = ".sqlite" + ): Unit = { Files.list(source).toArray.map(_.asInstanceOf[Path]).foreach { file => if ( - fileNameFilter.exists(reg => - file.toAbsolutePath.toString.matches(reg.regex)) + fileNameFilter + .exists(reg => file.toAbsolutePath.toString.matches(reg.regex)) ) { logger.info(s"Skipping ${file.toAbsolutePath} for backup") } else { if (Files.isDirectory(file)) { - backupDirectory(file, - target.resolve(file.getFileName), - fileNameFilter, - dbExtension) + backupDirectory( + file, + target.resolve(file.getFileName), + fileNameFilter, + dbExtension + ) } else if ( Files.isRegularFile(file, LinkOption.NOFOLLOW_LINKS) && file.toString .endsWith(dbExtension) ) { val backupFile = target.resolve(file.getFileName) logger.info( - s"Backing up file=${file.toAbsolutePath} to ${backupFile.toAbsolutePath}") + s"Backing up file=${file.toAbsolutePath} to ${backupFile.toAbsolutePath}" + ) Files.createDirectories(target) backup(pathToJdbcUrl(file), backupFile) logger.info(s"Done backing up file=${file.toAbsolutePath}") @@ -50,13 +54,15 @@ object SQLiteUtil extends BitcoinSLogger { val existsAndWritable = Files.exists(backupFilePath) && Files.isWritable(backupFilePath) val doesntExistAndPArentIsWritable = !Files.exists( - backupFilePath) && Files.isWritable(backupFilePath.getParent) + backupFilePath + ) && Files.isWritable(backupFilePath.getParent) if (existsAndWritable || doesntExistAndPArentIsWritable) { val _ = conn.createStatement().executeUpdate(s"BACKUP TO $backupFilePath") } else { throw new IOException( - s"Backup destination is not writable: $backupFilePath") + s"Backup destination is not writable: $backupFilePath" + ) } } finally conn.close() } diff --git a/db-commons/src/main/scala/org/bitcoins/db/SlickUtil.scala b/db-commons/src/main/scala/org/bitcoins/db/SlickUtil.scala index 4d10e5d982..e0c9c79c6e 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/SlickUtil.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/SlickUtil.scala @@ -12,7 +12,8 @@ trait SlickUtilAction[T, PrimaryKeyType] { _: CRUDAction[T, PrimaryKeyType] => import profile.api._ def createAllAction( - ts: Vector[T]): DBIOAction[Vector[T], NoStream, Effect.Write] = { + ts: Vector[T] + ): DBIOAction[Vector[T], NoStream, Effect.Write] = { val fixedSqlAction = table ++= ts fixedSqlAction.map(_ => ts) @@ -27,7 +28,8 @@ trait SlickUtil[T, PrimaryKeyType] extends SlickUtilAction[T, PrimaryKeyType] { /** Creates rows in a database that are not auto incremented */ def createAllNoAutoInc(ts: Vector[T], database: SafeDatabase)(implicit - ec: ExecutionContext): Future[Vector[T]] = { + ec: ExecutionContext + ): Future[Vector[T]] = { val actions = (table ++= ts).andThen(DBIO.successful(ts)) val result = database.run(actions) result diff --git a/db-commons/src/main/scala/org/bitcoins/db/models/MasterXPubDAO.scala b/db-commons/src/main/scala/org/bitcoins/db/models/MasterXPubDAO.scala index b786ff7376..31af3ede01 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/models/MasterXPubDAO.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/models/MasterXPubDAO.scala @@ -24,11 +24,13 @@ case class ExtPublicKeyDTO( } -/** The primary key type is the public key associated with the extended public key [[ExtPublicKey.key]] */ +/** The primary key type is the public key associated with the extended public + * key [[ExtPublicKey.key]] + */ case class MasterXPubDAO()(implicit ec: ExecutionContext, - appConfig: DbAppConfig) - extends CRUD[ExtPublicKeyDTO, ECPublicKey] + appConfig: DbAppConfig +) extends CRUD[ExtPublicKeyDTO, ECPublicKey] with SlickUtil[ExtPublicKeyDTO, ECPublicKey] { import profile.api._ private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -38,16 +40,19 @@ case class MasterXPubDAO()(implicit def create( extPublicKey: ExtPublicKey, - name: Option[String] = None): Future[ExtPublicKeyDTO] = { + name: Option[String] = None + ): Future[ExtPublicKeyDTO] = { val dto = createDTO(extPublicKey, name) create(dto) } override def createAllAction( - ts: Vector[ExtPublicKeyDTO]): profile.api.DBIOAction[ - Vector[ExtPublicKeyDTO], - profile.api.NoStream, - Effect.Write] = { + ts: Vector[ExtPublicKeyDTO] + ): profile.api.DBIOAction[Vector[ + ExtPublicKeyDTO + ], + profile.api.NoStream, + Effect.Write] = { val fixedSqlAction = table ++= ts fixedSqlAction.map(_ => ts) @@ -61,48 +66,60 @@ case class MasterXPubDAO()(implicit table += t case count @ _ => DBIO.failed( - new SQLException(s"Only 1 master xpub should be stored, got=$count")) + new SQLException(s"Only 1 master xpub should be stored, got=$count") + ) } database.run(action).map(_ => t) } override def createAll( - extKeys: Vector[ExtPublicKeyDTO]): Future[Vector[ExtPublicKeyDTO]] = { + extKeys: Vector[ExtPublicKeyDTO] + ): Future[Vector[ExtPublicKeyDTO]] = { if (extKeys.size != 1) Future.failed( new SQLException( - s"Only 1 master xpub should be stored, got=${extKeys.size}")) + s"Only 1 master xpub should be stored, got=${extKeys.size}" + ) + ) else create(extKeys.head).map(Vector(_)) } override protected def findByPrimaryKeys( - pubkeys: Vector[ECPublicKey]): profile.api.Query[ - profile.api.Table[ExtPublicKeyDTO], - ExtPublicKeyDTO, - Seq] = { + pubkeys: Vector[ECPublicKey] + ): profile.api.Query[profile.api.Table[ + ExtPublicKeyDTO + ], + ExtPublicKeyDTO, + Seq] = { table.filter(_.key.inSet(pubkeys)) } override protected def findAll( - ts: Vector[ExtPublicKeyDTO]): profile.api.Query[ - profile.api.Table[ExtPublicKeyDTO], - ExtPublicKeyDTO, - Seq] = { + ts: Vector[ExtPublicKeyDTO] + ): profile.api.Query[profile.api.Table[ + ExtPublicKeyDTO + ], + ExtPublicKeyDTO, + Seq] = { findByPrimaryKeys(ts.map(_.publicKey)) } /** Validates the stored public key against the given xpub - * @throws RuntimeException if the keys are different + * @throws RuntimeException + * if the keys are different */ def validate(xpub: ExtPublicKey): Future[Unit] = { findAll().map { xpubs => - require(xpubs.length == 1, - s"Only 1 master xpub should be stored, got=${xpubs.length}") + require( + xpubs.length == 1, + s"Only 1 master xpub should be stored, got=${xpubs.length}" + ) if (xpub != xpubs.head.toExtPublicKey) { sys.error( - s"Keymanager xpub and stored xpub are different, stored=${xpubs.head.toExtPublicKey}, keymanager=${xpub}") + s"Keymanager xpub and stored xpub are different, stored=${xpubs.head.toExtPublicKey}, keymanager=${xpub}" + ) } } } @@ -113,8 +130,10 @@ case class MasterXPubDAO()(implicit def findXPub(): Future[ExtPublicKeyDTO] = { findAll().map { xpubs => - require(xpubs.length == 1, - s"Only 1 master xpub should be stored, got=${xpubs.length}") + require( + xpubs.length == 1, + s"Only 1 master xpub should be stored, got=${xpubs.length}" + ) xpubs.head } } @@ -127,7 +146,8 @@ case class MasterXPubDAO()(implicit table.map(_.name).update(Option(name)) case count @ _ => DBIO.failed( - new SQLException(s"Only 1 master xpub should be stored, got=$count")) + new SQLException(s"Only 1 master xpub should be stored, got=$count") + ) } database.run(action).map(_ => ()) @@ -153,13 +173,15 @@ case class MasterXPubDAO()(implicit def * = { (version, depth, fingerprint, childNum, chaincode, key, name).<>( ExtPublicKeyDTO.tupled, - ExtPublicKeyDTO.unapply) + ExtPublicKeyDTO.unapply + ) } } private def createDTO( epk: ExtPublicKey, - name: Option[String]): ExtPublicKeyDTO = + name: Option[String] + ): ExtPublicKeyDTO = ExtPublicKeyDTO( version = epk.version, depth = epk.depth, diff --git a/db-commons/src/main/scala/org/bitcoins/db/util/DBMasterXPubApi.scala b/db-commons/src/main/scala/org/bitcoins/db/util/DBMasterXPubApi.scala index 97e50d824d..d57b48685f 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/util/DBMasterXPubApi.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/util/DBMasterXPubApi.scala @@ -8,7 +8,9 @@ import org.bitcoins.keymanager.WalletStorage import java.nio.file.Path import scala.concurrent.{ExecutionContext, Future} -/** A trait for checking invariants on file based seeds against a database stored master xpub */ +/** A trait for checking invariants on file based seeds against a database + * stored master xpub + */ trait DBMasterXPubApi extends MasterXPubApi { dbAppConfig: DbAppConfig => def seedPath: Path diff --git a/db-commons/src/main/scala/org/bitcoins/db/util/MasterXPubUtil.scala b/db-commons/src/main/scala/org/bitcoins/db/util/MasterXPubUtil.scala index b47239e2f7..ffda7b1bab 100644 --- a/db-commons/src/main/scala/org/bitcoins/db/util/MasterXPubUtil.scala +++ b/db-commons/src/main/scala/org/bitcoins/db/util/MasterXPubUtil.scala @@ -8,10 +8,12 @@ import scala.concurrent.{ExecutionContext, Future} object MasterXPubUtil { /** Checks our database xpub is the same as our key manager xpub - * @throws RuntimeExceptions if the xpubs do not match + * @throws RuntimeExceptions + * if the xpubs do not match */ def checkMasterXPub(xpub: ExtPublicKey, masterXPubDAO: MasterXPubDAO)(implicit - ec: ExecutionContext): Future[Boolean] = { + ec: ExecutionContext + ): Future[Boolean] = { val validateF = masterXPubDAO.validate(xpub) validateF.map(_ => true) } diff --git a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCConnectionHandlerTest.scala b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCConnectionHandlerTest.scala index c468f5ba61..45d976308d 100644 --- a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCConnectionHandlerTest.scala +++ b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCConnectionHandlerTest.scala @@ -10,7 +10,7 @@ class DLCConnectionHandlerTest extends BitcoinSAsyncTest { it must "DLC Accept message that is not aligned with a tcp frame" in { forAllAsync(LnMessageGen.dlcAcceptMessage) { accept => - //split the msg at a random index to simulate a tcp frame not being aligned + // split the msg at a random index to simulate a tcp frame not being aligned val randomIndex = scala.util.Random.nextInt().abs % accept.bytes.size val (firstHalf, secondHalf) = accept.bytes.splitAt(randomIndex) val (firstHalfParseHeaders, remainingBytes) = @@ -19,7 +19,8 @@ class DLCConnectionHandlerTest extends BitcoinSAsyncTest { val (secondHalfParsedHeaders, _) = DLCConnectionHandler.parseIndividualMessages( - remainingBytes ++ secondHalf) + remainingBytes ++ secondHalf + ) val parsedLnMessage = secondHalfParsedHeaders.head val parsedLnAcceptMessage = parsedLnMessage.asInstanceOf[LnMessage[DLCAcceptTLV]] diff --git a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCNegotiationTest.scala b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCNegotiationTest.scala index a708cfdfa1..abc6681f84 100644 --- a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCNegotiationTest.scala +++ b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCNegotiationTest.scala @@ -31,10 +31,8 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest { Future.unit } - private val handleWriteErrorFn: ( - BigSizeUInt, - ByteVector, - Throwable) => Future[Unit] = { + private val handleWriteErrorFn + : (BigSizeUInt, ByteVector, Throwable) => Future[Unit] = { case (_: BigSizeUInt, _: ByteVector, _: Throwable) => Future.unit } @@ -52,17 +50,21 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest { val handlerP = Promise[ActorRef]() for { - _ <- DLCServer.bind(dlcWalletApi = walletA, - bindAddress = bindAddress, - targets = Vector(), - torParams = None, - handleWrite = handleWriteFn, - handleWriteError = handleWriteErrorFn) - _ <- DLCClient.connect(Peer(connectAddress, socks5ProxyParams = None), - walletB, - Some(handlerP), - handleWrite = handleWriteFn, - handleWriteError = handleWriteErrorFn) + _ <- DLCServer.bind( + dlcWalletApi = walletA, + bindAddress = bindAddress, + targets = Vector(), + torParams = None, + handleWrite = handleWriteFn, + handleWriteError = handleWriteErrorFn + ) + _ <- DLCClient.connect( + Peer(connectAddress, socks5ProxyParams = None), + walletB, + Some(handlerP), + handleWrite = handleWriteFn, + handleWriteError = handleWriteErrorFn + ) handler <- handlerP.future @@ -72,14 +74,16 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest { _ = assert(preDLCsA.isEmpty) _ = assert(preDLCsB.isEmpty) - offer <- walletB.createDLCOffer(sampleContractInfo, - half, - Some(SatoshisPerVirtualByte.one), - UInt32.zero, - UInt32.one, - None, - None, - None) + offer <- walletB.createDLCOffer( + sampleContractInfo, + half, + Some(SatoshisPerVirtualByte.one), + UInt32.zero, + UInt32.one, + None, + None, + None + ) accept <- walletA.acceptDLCOffer(offer, None, None, None) // Send accept message to begin p2p @@ -115,12 +119,14 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest { val errorP = Promise[ByteVector]() for { - _ <- DLCServer.bind(walletA, - bindAddress, - Vector(), - None, - handleWrite = handleWriteFn, - handleWriteError = handleWriteErrorFn) + _ <- DLCServer.bind( + walletA, + bindAddress, + Vector(), + None, + handleWrite = handleWriteFn, + handleWriteError = handleWriteErrorFn + ) _ <- DLCClient.connect( Peer(connectAddress, socks5ProxyParams = None), walletB, @@ -142,14 +148,16 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest { _ = assert(preA.isEmpty) _ = assert(preB.isEmpty) - offer <- walletB.createDLCOffer(sampleContractInfo, - half, - Some(SatoshisPerVirtualByte.one), - UInt32.zero, - UInt32.one, - None, - None, - None) + offer <- walletB.createDLCOffer( + sampleContractInfo, + half, + Some(SatoshisPerVirtualByte.one), + UInt32.zero, + UInt32.one, + None, + None, + None + ) tlv = SendOfferTLV(peer = "peer", message = "msg", offer = offer.toTLV) _ = assert(!okP.isCompleted) diff --git a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCNodeTest.scala b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCNodeTest.scala index 9cf76dd1fe..7ff40dec4b 100644 --- a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCNodeTest.scala +++ b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCNodeTest.scala @@ -43,7 +43,8 @@ class DLCNodeTest extends BitcoinSDLCNodeTest { okP.success("ok") Future.unit } - }) + } + ) configA.addCallbacks(established) val initiatedP = Promise[String]() @@ -68,10 +69,13 @@ class DLCNodeTest extends BitcoinSDLCNodeTest { ok <- okP.future _ = assert(ok == "ok") _ = assert(!errorP.isCompleted) - invalidAddr = InetSocketAddress.createUnresolved(addrB.getHostString, - NetworkUtil.randomPort()) + invalidAddr = InetSocketAddress.createUnresolved( + addrB.getHostString, + NetworkUtil.randomPort() + ) _ <- recoverToSucceededIf[Exception]( - nodeA.checkPeerConnection(invalidAddr)) + nodeA.checkPeerConnection(invalidAddr) + ) error <- errorP.future } yield { assert(error == "err") @@ -92,14 +96,16 @@ class DLCNodeTest extends BitcoinSDLCNodeTest { _ = assert(preDLCsA.isEmpty) _ = assert(preDLCsB.isEmpty) - offer <- walletA.createDLCOffer(sampleContractInfo, - half, - Some(SatoshisPerVirtualByte.one), - UInt32.zero, - UInt32.one, - None, - None, - None) + offer <- walletA.createDLCOffer( + sampleContractInfo, + half, + Some(SatoshisPerVirtualByte.one), + UInt32.zero, + UInt32.one, + None, + None, + None + ) _ <- nodeB.acceptDLCOffer(addrA, offer.toMessage, None, None) diff --git a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCServerTest.scala b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCServerTest.scala index abc8368ddd..7145603ef7 100644 --- a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCServerTest.scala +++ b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCServerTest.scala @@ -29,10 +29,8 @@ class DLCServerTest extends BitcoinSActorFixtureWithDLCWallet { Future.unit } - private val handleWriteErrorFn: ( - BigSizeUInt, - ByteVector, - Throwable) => Future[Unit] = { + private val handleWriteErrorFn + : (BigSizeUInt, ByteVector, Throwable) => Future[Unit] = { case (_: BigSizeUInt, _: ByteVector, _: Throwable) => Future.unit } @@ -60,7 +58,8 @@ class DLCServerTest extends BitcoinSActorFixtureWithDLCWallet { }, handleWriteFn, handleWriteErrorFn - )) + ) + ) val resultF: Future[Future[Assertion]] = for { _ <- boundAddressPromise.future @@ -79,7 +78,8 @@ class DLCServerTest extends BitcoinSActorFixtureWithDLCWallet { }, handleWriteFn, handleWriteErrorFn - )) + ) + ) client ! DLCClient.Connect(Peer(connectAddress, socks5ProxyParams = None)) for { @@ -87,13 +87,16 @@ class DLCServerTest extends BitcoinSActorFixtureWithDLCWallet { _ <- AsyncUtil.retryUntilSatisfied(serverConnectionHandlerOpt.isDefined) _ <- AsyncUtil.retryUntilSatisfied(clientConnectionHandlerOpt.isDefined) pingTLV = - PingTLV(UInt16.one, - ByteVector.fromValidHex("00112233445566778899aabbccddeeff")) + PingTLV( + UInt16.one, + ByteVector.fromValidHex("00112233445566778899aabbccddeeff") + ) clientConnectionHandler = clientConnectionHandlerOpt.get _ = clientProbe.send(clientConnectionHandler, pingTLV) _ = serverProbe.expectMsg(DLCDataHandler.Received(LnMessage(pingTLV))) pongTLV = PongTLV.forIgnored( - ByteVector.fromValidHex("00112233445566778899aabbccddeeff")) + ByteVector.fromValidHex("00112233445566778899aabbccddeeff") + ) serverConnectionHandler = serverConnectionHandlerOpt.get _ = serverProbe.send(serverConnectionHandler, pongTLV) _ = clientProbe.expectMsg(DLCDataHandler.Received(LnMessage(pongTLV))) @@ -103,8 +106,10 @@ class DLCServerTest extends BitcoinSActorFixtureWithDLCWallet { PongTLV.forIgnored(ignored) _ = clientProbe.send(clientConnectionHandler, bigTLV) _ = serverProbe.expectMsg(DLCDataHandler.Received(LnMessage(bigTLV))) - _ = clientProbe.send(clientConnectionHandler, - DLCConnectionHandler.CloseConnection) + _ = clientProbe.send( + clientConnectionHandler, + DLCConnectionHandler.CloseConnection + ) _ = clientProbe.send(clientConnectionHandler, pingTLV) _ = serverProbe.expectNoMessage() _ = serverProbe.send(serverConnectionHandler, pongTLV) diff --git a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCServerTorTest.scala b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCServerTorTest.scala index b440490ebd..a21644472d 100644 --- a/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCServerTorTest.scala +++ b/dlc-node-test/src/test/scala/org/bitcoins/dlc/node/DLCServerTorTest.scala @@ -43,10 +43,8 @@ class DLCServerTorTest Future.unit } - private val handleWriteErrorFn: ( - BigSizeUInt, - ByteVector, - Throwable) => Future[Unit] = { + private val handleWriteErrorFn + : (BigSizeUInt, ByteVector, Throwable) => Future[Unit] = { case (_: BigSizeUInt, _: ByteVector, _: Throwable) => Future.unit } @@ -83,7 +81,8 @@ class DLCServerTorTest }, handleWriteFn, handleWriteErrorFn - )) + ) + ) val resultF: Future[Future[Assertion]] = for { _ <- boundAddressPromise.future @@ -103,32 +102,41 @@ class DLCServerTorTest }, handleWriteFn, handleWriteErrorFn - )) + ) + ) client ! DLCClient.Connect( - Peer(connectAddress, - socks5ProxyParams = Some( - Socks5ProxyParams( - address = torProxyAddress, - credentialsOpt = None, - randomizeCredentials = true - )))) + Peer( + connectAddress, + socks5ProxyParams = Some( + Socks5ProxyParams( + address = torProxyAddress, + credentialsOpt = None, + randomizeCredentials = true + ) + ) + ) + ) for { _ <- connectedAddressPromise.future _ <- AsyncUtil.retryUntilSatisfied( - serverConnectionHandlerOpt.isDefined) + serverConnectionHandlerOpt.isDefined + ) _ <- AsyncUtil.retryUntilSatisfied( - clientConnectionHandlerOpt.isDefined) + clientConnectionHandlerOpt.isDefined + ) pingTLV = PingTLV( UInt16.one, - ByteVector.fromValidHex("00112233445566778899aabbccddeeff")) + ByteVector.fromValidHex("00112233445566778899aabbccddeeff") + ) clientConnectionHandler = clientConnectionHandlerOpt.get _ = clientProbe.send(clientConnectionHandler, pingTLV) _ = serverProbe.expectMsg(timeout, Received(LnMessage(pingTLV))) pongTLV = PongTLV.forIgnored( - ByteVector.fromValidHex("00112233445566778899aabbccddeeff")) + ByteVector.fromValidHex("00112233445566778899aabbccddeeff") + ) serverConnectionHandler = serverConnectionHandlerOpt.get _ = serverProbe.send(serverConnectionHandler, pongTLV) _ = clientProbe.expectMsg(timeout, Received(LnMessage(pongTLV))) @@ -137,8 +145,10 @@ class DLCServerTorTest bigTLV = PongTLV.forIgnored(ignored) _ = clientProbe.send(clientConnectionHandler, bigTLV) _ = serverProbe.expectMsg(timeout, Received(LnMessage(bigTLV))) - _ = clientProbe.send(clientConnectionHandler, - DLCConnectionHandler.CloseConnection) + _ = clientProbe.send( + clientConnectionHandler, + DLCConnectionHandler.CloseConnection + ) _ = clientProbe.send(clientConnectionHandler, pingTLV) _ = serverProbe.expectNoMessage() _ = serverProbe.send(serverConnectionHandler, pongTLV) @@ -156,8 +166,8 @@ class DLCServerTorTest private def withTempFile( prefix: String, suffix: String, - create: Boolean = false)( - f: File => Future[Assertion]): Future[Assertion] = { + create: Boolean = false + )(f: File => Future[Assertion]): Future[Assertion] = { val tempFile = File.createTempFile(prefix, suffix) if (!create) { tempFile.delete() diff --git a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCClient.scala b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCClient.scala index 4428400afe..c2a322b4b3 100644 --- a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCClient.scala +++ b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCClient.scala @@ -29,8 +29,8 @@ class DLCClient( handlerP: Option[Promise[ActorRef]], dataHandlerFactory: DLCDataHandler.Factory, handleWrite: (BigSizeUInt, ByteVector) => Future[Unit], - handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit]) - extends Actor + handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit] +) extends Actor with ActorLogging { import context.system @@ -50,13 +50,15 @@ class DLCClient( } context.become(connecting(peer)) - //currently our request timeout for requests sent to the backend is 60 seconds - //so we need the connection timeout to occur before the request times out - //when a user tries to submit an accept to the backend - //see: https://github.com/bitcoin-s/bitcoin-s/issues/4080 + // currently our request timeout for requests sent to the backend is 60 seconds + // so we need the connection timeout to occur before the request times out + // when a user tries to submit an accept to the backend + // see: https://github.com/bitcoin-s/bitcoin-s/issues/4080 val connectionTimeout = 45.seconds - IO(Tcp) ! Tcp.Connect(peerOrProxyAddress, - timeout = Some(connectionTimeout)) + IO(Tcp) ! Tcp.Connect( + peerOrProxyAddress, + timeout = Some(connectionTimeout) + ) } def connecting(peer: Peer): Receive = LoggingReceive { @@ -74,11 +76,14 @@ class DLCClient( log.info(s"connected to SOCKS5 proxy $proxyAddress") log.info(s"connecting to $remoteAddress via SOCKS5 $proxyAddress") val proxy = - context.actorOf(Socks5Connection.props( - sender(), - Socks5ProxyParams.proxyCredentials(proxyParams), - Socks5Connect(remoteAddress)), - "Socks5Connection") + context.actorOf( + Socks5Connection.props( + sender(), + Socks5ProxyParams.proxyCredentials(proxyParams), + Socks5Connect(remoteAddress) + ), + "Socks5Connection" + ) context watch proxy context become socks5Connecting(proxy, remoteAddress, proxyAddress) case None => @@ -86,12 +91,16 @@ class DLCClient( log.info(s"connected to $peerAddress") val _ = context.actorOf( Props( - new DLCConnectionHandler(dlcWalletApi, - connection, - handlerP, - dataHandlerFactory, - handleWrite, - handleWriteError))) + new DLCConnectionHandler( + dlcWalletApi, + connection, + handlerP, + dataHandlerFactory, + handleWrite, + handleWriteError + ) + ) + ) connectedAddress.foreach(_.success(peerAddress)) } } @@ -99,23 +108,33 @@ class DLCClient( def socks5Connecting( proxy: ActorRef, remoteAddress: InetSocketAddress, - proxyAddress: InetSocketAddress): Receive = LoggingReceive { + proxyAddress: InetSocketAddress + ): Receive = LoggingReceive { case c @ Tcp.CommandFailed(_: Socks5Connect) => - val ex = c.cause.getOrElse(new IOException( - s"Cannot connect to ${remoteAddress.getHostString}:${remoteAddress.getPort} via Tor")) - log.error(s"connection failed to $remoteAddress via SOCKS5 $proxyAddress", - ex) + val ex = c.cause.getOrElse( + new IOException( + s"Cannot connect to ${remoteAddress.getHostString}:${remoteAddress.getPort} via Tor" + ) + ) + log.error( + s"connection failed to $remoteAddress via SOCKS5 $proxyAddress", + ex + ) throw ex case Socks5Connected(_) => log.info(s"connected to $remoteAddress via SOCKS5 proxy $proxyAddress") val _ = context.actorOf( Props( - new DLCConnectionHandler(dlcWalletApi, - proxy, - handlerP, - dataHandlerFactory, - handleWrite, - handleWriteError))) + new DLCConnectionHandler( + dlcWalletApi, + proxy, + handlerP, + dataHandlerFactory, + handleWrite, + handleWriteError + ) + ) + ) connectedAddress.foreach(_.success(remoteAddress)) case Terminated(actor) if actor == proxy => context stop self @@ -140,17 +159,18 @@ object DLCClient { handlerP: Option[Promise[ActorRef]], dataHandlerFactory: DLCDataHandler.Factory, handleWrite: (BigSizeUInt, ByteVector) => Future[Unit], - handleWriteError: ( - BigSizeUInt, - ByteVector, - Throwable) => Future[Unit]): Props = + handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit] + ): Props = Props( - new DLCClient(dlcWalletApi, - connectedAddress, - handlerP, - dataHandlerFactory, - handleWrite, - handleWriteError)) + new DLCClient( + dlcWalletApi, + connectedAddress, + handlerP, + dataHandlerFactory, + handleWrite, + handleWriteError + ) + ) def connect( peer: Peer, @@ -159,17 +179,20 @@ object DLCClient { dataHandlerFactory: DLCDataHandler.Factory = DLCDataHandler.defaultFactory, handleWrite: (BigSizeUInt, ByteVector) => Future[Unit], - handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit])( - implicit system: ActorSystem): Future[InetSocketAddress] = { + handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit] + )(implicit system: ActorSystem): Future[InetSocketAddress] = { val promise = Promise[InetSocketAddress]() val actor = system.actorOf( - props(dlcWalletApi, - Some(promise), - handlerP, - dataHandlerFactory, - handleWrite, - handleWriteError)) + props( + dlcWalletApi, + Some(promise), + handlerP, + dataHandlerFactory, + handleWrite, + handleWriteError + ) + ) actor ! Connect(peer) promise.future } diff --git a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCConnectionHandler.scala b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCConnectionHandler.scala index a3becf9133..0a3d9a9f28 100644 --- a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCConnectionHandler.scala +++ b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCConnectionHandler.scala @@ -22,8 +22,8 @@ class DLCConnectionHandler( handlerP: Option[Promise[ActorRef]], dataHandlerFactory: DLCDataHandler.Factory, handleWrite: (BigSizeUInt, ByteVector) => Future[Unit], - handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit]) - extends Actor + handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit] +) extends Actor with ActorLogging { private val handler = { @@ -44,8 +44,10 @@ class DLCConnectionHandler( case lnMessage: LnMessage[TLV] => val id = tlvId(lnMessage) val byteMessage = ByteString(lnMessage.bytes.toArray) - connection ! Tcp.Write(byteMessage, - DLCConnectionHandler.Ack(lnMessage.tlv.tpe, id)) + connection ! Tcp.Write( + byteMessage, + DLCConnectionHandler.Ack(lnMessage.tlv.tpe, id) + ) connection ! Tcp.ResumeReading case tlv: TLV => @@ -71,8 +73,8 @@ class DLCConnectionHandler( connection ! Tcp.ResumeReading } - //we need to aggregate our previous 'unalignedBytes' with the new message - //we just received from our peer to hopefully be able to parse full messages + // we need to aggregate our previous 'unalignedBytes' with the new message + // we just received from our peer to hopefully be able to parse full messages val bytes: ByteVector = unalignedBytes ++ byteVec log.debug(s"Bytes for message parsing: ${bytes.toHex}") val (messages, newUnalignedBytes) = parseIndividualMessages(bytes) @@ -96,7 +98,7 @@ class DLCConnectionHandler( case Tcp.PeerClosed => context.stop(self) case DLCConnectionHandler.Ack(tlvType, tlvId) => - //is this right? do i need to block here (or not block?) + // is this right? do i need to block here (or not block?) val _ = handleWrite(tlvType, tlvId) () case c @ Tcp.CommandFailed(write: Tcp.Write) => @@ -107,7 +109,7 @@ class DLCConnectionHandler( log.error("Cannot write bytes ", ex) val (tlvType, tlvId) = write.ack match { case DLCConnectionHandler.Ack(t, id) => (t, id) - case _ => (BigSizeUInt(0), ByteVector.empty) + case _ => (BigSizeUInt(0), ByteVector.empty) } handleWriteError(tlvType, tlvId, ex) @@ -144,25 +146,28 @@ object DLCConnectionHandler extends BitcoinSLogger { handlerP: Option[Promise[ActorRef]], dataHandlerFactory: DLCDataHandler.Factory, handleWrite: (BigSizeUInt, ByteVector) => Future[Unit], - handleWriteError: ( - BigSizeUInt, - ByteVector, - Throwable) => Future[Unit]): Props = { + handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit] + ): Props = { Props( - new DLCConnectionHandler(dlcWalletApi, - connection, - handlerP, - dataHandlerFactory, - handleWrite, - handleWriteError)) + new DLCConnectionHandler( + dlcWalletApi, + connection, + handlerP, + dataHandlerFactory, + handleWrite, + handleWriteError + ) + ) } private[bitcoins] def parseIndividualMessages( - bytes: ByteVector): (Vector[LnMessage[TLV]], ByteVector) = { + bytes: ByteVector + ): (Vector[LnMessage[TLV]], ByteVector) = { @tailrec def loop( remainingBytes: ByteVector, - accum: Vector[LnMessage[TLV]]): (Vector[LnMessage[TLV]], ByteVector) = { + accum: Vector[LnMessage[TLV]] + ): (Vector[LnMessage[TLV]], ByteVector) = { if (remainingBytes.length <= 0) { (accum, remainingBytes) } else { @@ -175,7 +180,8 @@ object DLCConnectionHandler extends BitcoinSLogger { case Success(message) => val newRemainingBytes = remainingBytes.drop(message.byteSize) logger.debug( - s"Parsed a message=${message.typeName} from bytes, continuing with remainingBytes=${newRemainingBytes.length}") + s"Parsed a message=${message.typeName} from bytes, continuing with remainingBytes=${newRemainingBytes.length}" + ) loop(newRemainingBytes, accum :+ message) } } diff --git a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCDataHandler.scala b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCDataHandler.scala index 35333c07fd..a7eddcd158 100644 --- a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCDataHandler.scala +++ b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCDataHandler.scala @@ -48,7 +48,7 @@ class DLCDataHandler(dlcWalletApi: DLCWalletApi, connectionHandler: ActorRef) Future.unit // todo init logic case error: ErrorTLV => log.error(error.toString) - Future.unit //is this right? + Future.unit // is this right? case ping: PingTLV => val pong = PongTLV.forIgnored(ping.ignored) send(LnMessage(pong)) @@ -65,7 +65,8 @@ class DLCDataHandler(dlcWalletApi: DLCWalletApi, connectionHandler: ActorRef) _ <- dlcWalletApi.registerIncomingDLCOffer( offerTLV = dlcOfferMessage.offer, peer = Some(dlcOfferMessage.peer), - message = Some(dlcOfferMessage.message)) + message = Some(dlcOfferMessage.message) + ) } yield () case dlcAccept: DLCAcceptTLV => val f = for { @@ -99,7 +100,8 @@ object DLCDataHandler { def defaultFactory( dlcWalletApi: DLCWalletApi, context: ActorContext, - connectionHandler: ActorRef): ActorRef = { + connectionHandler: ActorRef + ): ActorRef = { context.actorOf(props(dlcWalletApi, connectionHandler)) } diff --git a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCNode.scala b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCNode.scala index 8b2cc95651..036a6aa21e 100644 --- a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCNode.scala +++ b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCNode.scala @@ -18,15 +18,16 @@ import scala.util.{Failure, Success} case class DLCNode(wallet: DLCWalletApi)(implicit system: ActorSystem, - val config: DLCNodeAppConfig) - extends DLCNodeApi + val config: DLCNodeAppConfig +) extends DLCNodeApi with BitcoinSLogger { implicit val ec: ExecutionContextExecutor = system.dispatcher private[node] lazy val serverBindF: Future[(InetSocketAddress, ActorRef)] = { logger.info( - s"Binding server to ${config.listenAddress}, with tor hidden service: ${config.torParams.isDefined}") + s"Binding server to ${config.listenAddress}, with tor hidden service: ${config.torParams.isDefined}" + ) DLCServer .bind( wallet, @@ -66,22 +67,24 @@ case class DLCNode(wallet: DLCWalletApi)(implicit peerAddress: InetSocketAddress, dlcOffer: LnMessage[DLCOfferTLV], externalPayoutAddress: Option[BitcoinAddress], - externalChangeAddress: Option[BitcoinAddress]): Future[ - DLCMessage.DLCAccept] = { + externalChangeAddress: Option[BitcoinAddress] + ): Future[DLCMessage.DLCAccept] = { val f = for { handler <- connectToPeer(peerAddress) - accept <- wallet.acceptDLCOffer(dlcOffer.tlv, - Some(peerAddress), - externalPayoutAddress, - externalChangeAddress) + accept <- wallet.acceptDLCOffer( + dlcOffer.tlv, + Some(peerAddress), + externalPayoutAddress, + externalChangeAddress + ) } yield { handler ! DLCDataHandler.Send(accept.toMessage) accept } f.failed.foreach(err => - config.callBacks.executeOnAcceptFailed(dlcOffer.tlv.tempContractId, - err.getMessage)) + config.callBacks + .executeOnAcceptFailed(dlcOffer.tlv.tempContractId, err.getMessage)) f } @@ -89,16 +92,19 @@ case class DLCNode(wallet: DLCWalletApi)(implicit override def sendDLCOffer( peerAddress: InetSocketAddress, message: String, - offerTLV: DLCOfferTLV): Future[Sha256Digest] = { + offerTLV: DLCOfferTLV + ): Future[Sha256Digest] = { val f = for { handler <- connectToPeer(peerAddress) localAddress <- getHostAddress } yield { val peer = NormalizedString( - localAddress.getHostString + ":" + peerAddress.getPort) + localAddress.getHostString + ":" + peerAddress.getPort + ) val msg = NormalizedString(message) val lnMessage = LnMessage( - SendOfferTLV(peer = peer, message = msg, offer = offerTLV)) + SendOfferTLV(peer = peer, message = msg, offer = offerTLV) + ) handler ! DLCDataHandler.Send(lnMessage) offerTLV.tempContractId } @@ -106,9 +112,12 @@ case class DLCNode(wallet: DLCWalletApi)(implicit f.failed.foreach { err => logger.error( s"Failed to send offer.tempContractId=${offerTLV.tempContractId}", - err) - config.callBacks.executeOnOfferSendFailed(offerTLV.tempContractId, - err.getMessage) + err + ) + config.callBacks.executeOnOfferSendFailed( + offerTLV.tempContractId, + err.getMessage + ) } f @@ -117,22 +126,28 @@ case class DLCNode(wallet: DLCWalletApi)(implicit override def sendDLCOffer( peerAddress: InetSocketAddress, message: String, - temporaryContractId: Sha256Digest): Future[Sha256Digest] = { + temporaryContractId: Sha256Digest + ): Future[Sha256Digest] = { for { dlcOpt <- wallet.findDLCByTemporaryContractId(temporaryContractId) dlc = dlcOpt.getOrElse( throw new IllegalArgumentException( - s"Cannot find a DLC with temp contact ID $temporaryContractId")) + s"Cannot find a DLC with temp contact ID $temporaryContractId" + ) + ) offerOpt <- wallet.getDLCOffer(dlc.dlcId) offer = offerOpt.getOrElse( throw new IllegalArgumentException( - s"Cannot find an offer with for DLC ID ${dlc.dlcId}")) + s"Cannot find an offer with for DLC ID ${dlc.dlcId}" + ) + ) res <- sendDLCOffer(peerAddress, message, offer.toTLV) } yield res } override def checkPeerConnection( - peerAddress: InetSocketAddress): Future[Unit] = { + peerAddress: InetSocketAddress + ): Future[Unit] = { for { handler <- connectToPeer(peerAddress) } yield { @@ -143,45 +158,57 @@ case class DLCNode(wallet: DLCWalletApi)(implicit private def handleTLVSendFailed( tlvType: BigSizeUInt, tlvId: ByteVector, - error: Throwable): Future[Unit] = { + error: Throwable + ): Future[Unit] = { logger.info("TLV send error ", error) tlvType match { case SendOfferTLV.tpe | DLCOfferTLV.tpe => - config.callBacks.executeOnOfferSendFailed(Sha256Digest.fromBytes(tlvId), - error.getMessage) + config.callBacks.executeOnOfferSendFailed( + Sha256Digest.fromBytes(tlvId), + error.getMessage + ) case DLCAcceptTLV.tpe => - config.callBacks.executeOnAcceptFailed(Sha256Digest.fromBytes(tlvId), - error.getMessage) + config.callBacks.executeOnAcceptFailed( + Sha256Digest.fromBytes(tlvId), + error.getMessage + ) case DLCSignTLV.tpe => - config.callBacks.executeOnSignFailed(Sha256Digest.fromBytes(tlvId), - error.getMessage) + config.callBacks.executeOnSignFailed( + Sha256Digest.fromBytes(tlvId), + error.getMessage + ) case unknown => val exn = new RuntimeException( - s"Unknown tpe=$unknown inside of handleTLVSendFailed") + s"Unknown tpe=$unknown inside of handleTLVSendFailed" + ) Future.failed(exn) } } private def handleTLVSendSucceed( tlvType: BigSizeUInt, - tlvId: ByteVector): Future[Unit] = { + tlvId: ByteVector + ): Future[Unit] = { tlvType match { case SendOfferTLV.tpe | DLCOfferTLV.tpe => config.callBacks.executeOnOfferSendSucceed( - Sha256Digest.fromBytes(tlvId)) + Sha256Digest.fromBytes(tlvId) + ) case DLCAcceptTLV.tpe => config.callBacks.executeOnAcceptSucceed(Sha256Digest.fromBytes(tlvId)) case DLCSignTLV.tpe => config.callBacks.executeOnSignSucceed(Sha256Digest.fromBytes(tlvId)) case unknown => val exn = new RuntimeException( - s"Unknown tpe=$unknown inside of handleTLVSendSucceed") + s"Unknown tpe=$unknown inside of handleTLVSendSucceed" + ) Future.failed(exn) } } private def connectToPeer( - peerAddress: InetSocketAddress): Future[ActorRef] = { + peerAddress: InetSocketAddress + ): Future[ActorRef] = { val peer = Peer(socket = peerAddress, socks5ProxyParams = config.socks5ProxyParams) @@ -190,11 +217,13 @@ case class DLCNode(wallet: DLCWalletApi)(implicit val f = for { _ <- config.callBacks.executeOnPeerConnectionInitiated(peerAddress) - _ <- DLCClient.connect(peer, - wallet, - Some(handlerP), - handleWrite = handleTLVSendSucceed, - handleWriteError = handleTLVSendFailed) + _ <- DLCClient.connect( + peer, + wallet, + Some(handlerP), + handleWrite = handleTLVSendSucceed, + handleWriteError = handleTLVSendFailed + ) handler <- handlerP.future } yield handler diff --git a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCNodeCallbacks.scala b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCNodeCallbacks.scala index 3bfadef8c0..c606e0529a 100644 --- a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCNodeCallbacks.scala +++ b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCNodeCallbacks.scala @@ -13,23 +13,19 @@ trait DLCNodeCallbacks extends ModuleCallbacks[DLCNodeCallbacks] with BitcoinSLogger { - def onPeerConnectionInitiated: CallbackHandler[ - InetSocketAddress, - OnPeerConnectionInitiated] + def onPeerConnectionInitiated + : CallbackHandler[InetSocketAddress, OnPeerConnectionInitiated] - def onPeerConnectionEstablished: CallbackHandler[ - InetSocketAddress, - OnPeerConnectionEstablished] + def onPeerConnectionEstablished + : CallbackHandler[InetSocketAddress, OnPeerConnectionEstablished] - def onPeerConnectionFailed: CallbackHandler[ - InetSocketAddress, - OnPeerConnectionFailed] + def onPeerConnectionFailed + : CallbackHandler[InetSocketAddress, OnPeerConnectionFailed] def onOfferSendSucceed: CallbackHandler[Sha256Digest, OnOfferSendSucceed] - def onOfferSendFailed: CallbackHandler[ - (Sha256Digest, String), - OnOfferSendFailed] + def onOfferSendFailed + : CallbackHandler[(Sha256Digest, String), OnOfferSendFailed] def onAcceptSucceed: CallbackHandler[Sha256Digest, OnAcceptSucceed] @@ -41,88 +37,116 @@ trait DLCNodeCallbacks override def +(other: DLCNodeCallbacks): DLCNodeCallbacks - def executeOnPeerConnectionInitiated(peerAddress: InetSocketAddress)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnPeerConnectionInitiated( + peerAddress: InetSocketAddress + )(implicit ec: ExecutionContext): Future[Unit] = { onPeerConnectionInitiated.execute( peerAddress, (err: Throwable) => logger.error( s"${onPeerConnectionInitiated.name} Callback failed with error: ", - err)) + err + ) + ) } - def executeOnPeerConnectionEstablished(peerAddress: InetSocketAddress)( - implicit ec: ExecutionContext): Future[Unit] = { + def executeOnPeerConnectionEstablished( + peerAddress: InetSocketAddress + )(implicit ec: ExecutionContext): Future[Unit] = { onPeerConnectionEstablished.execute( peerAddress, (err: Throwable) => logger.error( s"${onPeerConnectionEstablished.name} Callback failed with error: ", - err)) + err + ) + ) } - def executeOnPeerConnectionFailed(peerAddress: InetSocketAddress)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnPeerConnectionFailed( + peerAddress: InetSocketAddress + )(implicit ec: ExecutionContext): Future[Unit] = { onPeerConnectionFailed.execute( peerAddress, (err: Throwable) => logger.error( s"${onPeerConnectionFailed.name} Callback failed with error: ", - err)) + err + ) + ) } - def executeOnOfferSendSucceed(tempContractId: Sha256Digest)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnOfferSendSucceed( + tempContractId: Sha256Digest + )(implicit ec: ExecutionContext): Future[Unit] = { onOfferSendSucceed.execute( tempContractId, (err: Throwable) => - logger.error(s"${onOfferSendSucceed.name} Callback failed with error: ", - err)) + logger.error( + s"${onOfferSendSucceed.name} Callback failed with error: ", + err + ) + ) } def executeOnOfferSendFailed( tempContractId: Sha256Digest, - errorMessage: String)(implicit ec: ExecutionContext): Future[Unit] = { + errorMessage: String + )(implicit ec: ExecutionContext): Future[Unit] = { onOfferSendFailed.execute( (tempContractId, errorMessage), (err: Throwable) => - logger.error(s"${onOfferSendFailed.name} Callback failed with error: ", - err)) + logger.error( + s"${onOfferSendFailed.name} Callback failed with error: ", + err + ) + ) } - def executeOnAcceptSucceed(tempContractId: Sha256Digest)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnAcceptSucceed( + tempContractId: Sha256Digest + )(implicit ec: ExecutionContext): Future[Unit] = { onAcceptSucceed.execute( tempContractId, (err: Throwable) => - logger.error(s"${onAcceptSucceed.name} Callback failed with error: ", - err)) + logger.error( + s"${onAcceptSucceed.name} Callback failed with error: ", + err + ) + ) } def executeOnAcceptFailed(tempContractId: Sha256Digest, errorMessage: String)( - implicit ec: ExecutionContext): Future[Unit] = { + implicit ec: ExecutionContext + ): Future[Unit] = { onAcceptFailed.execute( (tempContractId, errorMessage), (err: Throwable) => - logger.error(s"${onAcceptFailed.name} Callback failed with error: ", - err)) + logger.error( + s"${onAcceptFailed.name} Callback failed with error: ", + err + ) + ) } - def executeOnSignSucceed(tempContractId: Sha256Digest)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnSignSucceed( + tempContractId: Sha256Digest + )(implicit ec: ExecutionContext): Future[Unit] = { onSignSucceed.execute( tempContractId, (err: Throwable) => - logger.error(s"${onSignSucceed.name} Callback failed with error: ", - err)) + logger.error(s"${onSignSucceed.name} Callback failed with error: ", err) + ) } def executeOnSignFailed(tempContractId: Sha256Digest, errorMessage: String)( - implicit ec: ExecutionContext): Future[Unit] = { + implicit ec: ExecutionContext + ): Future[Unit] = { onSignFailed.execute( (tempContractId, errorMessage), (err: Throwable) => - logger.error(s"${onSignFailed.name} Callback failed with error: ", err)) + logger.error(s"${onSignFailed.name} Callback failed with error: ", err) + ) } } @@ -150,22 +174,26 @@ object DLCNodeCallbacks extends CallbackFactory[DLCNodeCallbacks] { private case class DLCNodeCallbacksImpl( onPeerConnectionInitiated: CallbackHandler[ InetSocketAddress, - OnPeerConnectionInitiated], + OnPeerConnectionInitiated + ], onPeerConnectionEstablished: CallbackHandler[ InetSocketAddress, - OnPeerConnectionEstablished], + OnPeerConnectionEstablished + ], onPeerConnectionFailed: CallbackHandler[ InetSocketAddress, - OnPeerConnectionFailed], + OnPeerConnectionFailed + ], onOfferSendSucceed: CallbackHandler[Sha256Digest, OnOfferSendSucceed], onOfferSendFailed: CallbackHandler[ (Sha256Digest, String), - OnOfferSendFailed], + OnOfferSendFailed + ], onAcceptSucceed: CallbackHandler[Sha256Digest, OnAcceptSucceed], onAcceptFailed: CallbackHandler[(Sha256Digest, String), OnAcceptFailed], onSignSucceed: CallbackHandler[Sha256Digest, OnSignSucceed], - onSignFailed: CallbackHandler[(Sha256Digest, String), OnSignFailed]) - extends DLCNodeCallbacks { + onSignFailed: CallbackHandler[(Sha256Digest, String), OnSignFailed] + ) extends DLCNodeCallbacks { override def +(other: DLCNodeCallbacks): DLCNodeCallbacks = copy( @@ -185,11 +213,13 @@ object DLCNodeCallbacks extends CallbackFactory[DLCNodeCallbacks] { } def onPeerConnectionInitiated( - f: OnPeerConnectionInitiated): DLCNodeCallbacks = + f: OnPeerConnectionInitiated + ): DLCNodeCallbacks = DLCNodeCallbacks(onPeerConnectionInitiated = Vector(f)) def onPeerConnectionEstablished( - f: OnPeerConnectionEstablished): DLCNodeCallbacks = + f: OnPeerConnectionEstablished + ): DLCNodeCallbacks = DLCNodeCallbacks(onPeerConnectionEstablished = Vector(f)) def onPeerConnectionFailed(f: OnPeerConnectionFailed): DLCNodeCallbacks = @@ -216,34 +246,43 @@ object DLCNodeCallbacks extends CallbackFactory[DLCNodeCallbacks] { onPeerConnectionInitiated = CallbackHandler[InetSocketAddress, OnPeerConnectionInitiated]( "onPeerConnectionInitiated", - onPeerConnectionInitiated), + onPeerConnectionInitiated + ), onPeerConnectionEstablished = CallbackHandler[InetSocketAddress, OnPeerConnectionEstablished]( "onPeerConnectionEstablished", - onPeerConnectionEstablished), + onPeerConnectionEstablished + ), onPeerConnectionFailed = CallbackHandler[InetSocketAddress, OnPeerConnectionFailed]( "onPeerConnectionFailed", - onPeerConnectionFailed), - onOfferSendSucceed = - CallbackHandler[Sha256Digest, OnOfferSendSucceed]("onOfferSendSucceed", - onOfferSendSucceed), + onPeerConnectionFailed + ), + onOfferSendSucceed = CallbackHandler[Sha256Digest, OnOfferSendSucceed]( + "onOfferSendSucceed", + onOfferSendSucceed + ), onOfferSendFailed = CallbackHandler[(Sha256Digest, String), OnOfferSendFailed]( "onOfferSendFailed", - onOfferSendFailed), - onAcceptSucceed = - CallbackHandler[Sha256Digest, OnAcceptSucceed]("onAcceptSucceed", - onAcceptSucceed), + onOfferSendFailed + ), + onAcceptSucceed = CallbackHandler[Sha256Digest, OnAcceptSucceed]( + "onAcceptSucceed", + onAcceptSucceed + ), onAcceptFailed = CallbackHandler[(Sha256Digest, String), OnAcceptFailed]( "onAcceptFailed", - onAcceptFailed), - onSignSucceed = - CallbackHandler[Sha256Digest, OnSignSucceed]("onSignSucceed", - onSignSucceed), - onSignFailed = - CallbackHandler[(Sha256Digest, String), OnSignFailed]("onSignFailed", - onSignFailed) + onAcceptFailed + ), + onSignSucceed = CallbackHandler[Sha256Digest, OnSignSucceed]( + "onSignSucceed", + onSignSucceed + ), + onSignFailed = CallbackHandler[(Sha256Digest, String), OnSignFailed]( + "onSignFailed", + onSignFailed + ) ) } } diff --git a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCServer.scala b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCServer.scala index 951d8a294d..fa501ec434 100644 --- a/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCServer.scala +++ b/dlc-node/src/main/scala/org/bitcoins/dlc/node/DLCServer.scala @@ -25,8 +25,8 @@ class DLCServer( boundAddress: Option[Promise[InetSocketAddress]], dataHandlerFactory: DLCDataHandler.Factory, handleWrite: (BigSizeUInt, ByteVector) => Future[Unit], - handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit]) - extends Actor + handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit] +) extends Actor with ActorLogging { import context.system @@ -55,12 +55,16 @@ class DLCServer( log.info(s"Received a connection from $remoteAddress") val _ = context.actorOf( Props( - new DLCConnectionHandler(dlcWalletApi, - connection, - None, - dataHandlerFactory, - handleWrite, - handleWriteError))) + new DLCConnectionHandler( + dlcWalletApi, + connection, + None, + dataHandlerFactory, + handleWrite, + handleWriteError + ) + ) + ) } override def postStop(): Unit = { @@ -88,17 +92,18 @@ object DLCServer extends BitcoinSLogger { boundAddress: Option[Promise[InetSocketAddress]] = None, dataHandlerFactory: DLCDataHandler.Factory, handleWrite: (BigSizeUInt, ByteVector) => Future[Unit], - handleWriteError: ( - BigSizeUInt, - ByteVector, - Throwable) => Future[Unit]): Props = + handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit] + ): Props = Props( - new DLCServer(dlcWalletApi, - bindAddress, - boundAddress, - dataHandlerFactory, - handleWrite, - handleWriteError)) + new DLCServer( + dlcWalletApi, + bindAddress, + boundAddress, + dataHandlerFactory, + handleWrite, + handleWriteError + ) + ) def bind( dlcWalletApi: DLCWalletApi, @@ -107,9 +112,8 @@ object DLCServer extends BitcoinSLogger { torParams: Option[TorParams], handleWrite: (BigSizeUInt, ByteVector) => Future[Unit], handleWriteError: (BigSizeUInt, ByteVector, Throwable) => Future[Unit], - dataHandlerFactory: DLCDataHandler.Factory = - DLCDataHandler.defaultFactory)(implicit - system: ActorSystem): Future[(InetSocketAddress, ActorRef)] = { + dataHandlerFactory: DLCDataHandler.Factory = DLCDataHandler.defaultFactory + )(implicit system: ActorSystem): Future[(InetSocketAddress, ActorRef)] = { import system.dispatcher val promise = Promise[InetSocketAddress]() @@ -128,16 +132,20 @@ object DLCServer extends BitcoinSLogger { .map(Some(_)) case None => logger.warn( - s"Tor must be enabled to negotiate a dlc, you can set this with bitcoin-s.tor.enabled=true and bitcoin-s.control.enabled=true in your bitcoin-s.conf") + s"Tor must be enabled to negotiate a dlc, you can set this with bitcoin-s.tor.enabled=true and bitcoin-s.control.enabled=true in your bitcoin-s.conf" + ) Future.successful(None) } actorRef = system.actorOf( - props(dlcWalletApi, - bindAddress, - Some(promise), - dataHandlerFactory, - handleWrite, - handleWriteError)) + props( + dlcWalletApi, + bindAddress, + Some(promise), + dataHandlerFactory, + handleWrite, + handleWriteError + ) + ) boundAddress <- promise.future } yield { val addr = onionAddress.getOrElse(boundAddress) diff --git a/dlc-node/src/main/scala/org/bitcoins/dlc/node/config/DLCNodeAppConfig.scala b/dlc-node/src/main/scala/org/bitcoins/dlc/node/config/DLCNodeAppConfig.scala index dada9b97a1..de018497f6 100644 --- a/dlc-node/src/main/scala/org/bitcoins/dlc/node/config/DLCNodeAppConfig.scala +++ b/dlc-node/src/main/scala/org/bitcoins/dlc/node/config/DLCNodeAppConfig.scala @@ -17,12 +17,14 @@ import scala.concurrent._ /** Configuration for the Bitcoin-S wallet * - * @param directory The data directory of the wallet - * @param conf Optional sequence of configuration overrides + * @param directory + * The data directory of the wallet + * @param conf + * Optional sequence of configuration overrides */ case class DLCNodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( - implicit ec: ExecutionContext) - extends AppConfig + implicit ec: ExecutionContext +) extends AppConfig with CallbackConfig[DLCNodeCallbacks] { override protected[bitcoins] def moduleName: String = @@ -31,7 +33,8 @@ case class DLCNodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( override protected[bitcoins] type ConfigType = DLCNodeAppConfig override protected[bitcoins] def newConfigOfType( - configs: Vector[Config]): DLCNodeAppConfig = + configs: Vector[Config] + ): DLCNodeAppConfig = DLCNodeAppConfig(baseDatadir, configs) override def start(): Future[Unit] = { @@ -66,8 +69,9 @@ case class DLCNodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( } } - def createDLCNode(dlcWallet: DLCWalletApi)(implicit - system: ActorSystem): DLCNode = { + def createDLCNode( + dlcWallet: DLCWalletApi + )(implicit system: ActorSystem): DLCNode = { DLCNode(dlcWallet)(system, this) } } @@ -76,6 +80,7 @@ object DLCNodeAppConfig extends AppConfigFactory[DLCNodeAppConfig] { override val moduleName: String = "dlcnode" override def fromDatadir(datadir: Path, confs: Vector[Config])(implicit - ec: ExecutionContext): DLCNodeAppConfig = + ec: ExecutionContext + ): DLCNodeAppConfig = DLCNodeAppConfig(datadir, confs) } diff --git a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/AttestationVerificationTest.scala b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/AttestationVerificationTest.scala index 13654f0c3e..e10a3fdaee 100644 --- a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/AttestationVerificationTest.scala +++ b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/AttestationVerificationTest.scala @@ -18,10 +18,12 @@ class AttestationVerificationTest extends BitcoinSUnitTest { val enumAnnouncement: OracleAnnouncementV0TLV = OracleAnnouncementV0TLV( - "fdd8249917caf0b7f6cd8be0cd7a98530464329e42219e3b0f0cd75609de1d7342e8eba7ab47f111e1825af3322fd4d97f6d1b5f5063394f9a2dae05c14567a1f10819fa545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a85fdd8223500013168cb6d4c4e52aeb5bb75ce141cd9e1aa40e1d9123134d9aa390cffb338d51e600a1580fdd806060002016101620474657374") + "fdd8249917caf0b7f6cd8be0cd7a98530464329e42219e3b0f0cd75609de1d7342e8eba7ab47f111e1825af3322fd4d97f6d1b5f5063394f9a2dae05c14567a1f10819fa545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a85fdd8223500013168cb6d4c4e52aeb5bb75ce141cd9e1aa40e1d9123134d9aa390cffb338d51e600a1580fdd806060002016101620474657374" + ) val validEnumAttestation: OracleAttestmentV0TLV = OracleAttestmentV0TLV( - "fdd868690474657374545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a8500013168cb6d4c4e52aeb5bb75ce141cd9e1aa40e1d9123134d9aa390cffb338d51e323d991dadb52f32d0541027f973c363c0b746bb40dd1d42686f172d88ddef380161") + "fdd868690474657374545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a8500013168cb6d4c4e52aeb5bb75ce141cd9e1aa40e1d9123134d9aa390cffb338d51e323d991dadb52f32d0541027f973c363c0b746bb40dd1d42686f172d88ddef380161" + ) val invalidEnumAttestation: OracleAttestmentV0TLV = { val unsorted = validEnumAttestation.sigs.map(_.copy(sig = FieldElement.one)) @@ -30,16 +32,19 @@ class AttestationVerificationTest extends BitcoinSUnitTest { val unsignedDigitDecompAnnouncement: OracleAnnouncementV0TLV = OracleAnnouncementV0TLV( - "fdd824fd0143e3335c998ff6b188da3ee303b8775f64ca7810685a4051fbf1acd1181f4dbcbc15ac5b418e37d9600229e5c31b97d130ceb9130d163c9592bf0481956dde0d64545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a85fdd822df0006280b657b9c1cd8de3da2619194e2c71831598be3e60d39a242c232f580451c43bd61d1a6c395c99202058ddabf851e1c8220f12bd801bbb90efcf45d4a2d769c57ae1c605b9d36ff8477baa8c216abbfe6c3742236ecfad2415745a7cf7850c646f4835c5b80ca64832a6b9e7526fd575db4913ce0a9686072c5f970f94c3a2e87d4b2e93e52b2283c81185fb8ab14a757ff04b00b821d1aaac0a81e05d15da64ca823f9aa4b18525521073096f73fd583205086c7db2b6ac243901e4f1898bc600b6700fdd80a0f00020005756e6974730000000000060564756d6d79") + "fdd824fd0143e3335c998ff6b188da3ee303b8775f64ca7810685a4051fbf1acd1181f4dbcbc15ac5b418e37d9600229e5c31b97d130ceb9130d163c9592bf0481956dde0d64545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a85fdd822df0006280b657b9c1cd8de3da2619194e2c71831598be3e60d39a242c232f580451c43bd61d1a6c395c99202058ddabf851e1c8220f12bd801bbb90efcf45d4a2d769c57ae1c605b9d36ff8477baa8c216abbfe6c3742236ecfad2415745a7cf7850c646f4835c5b80ca64832a6b9e7526fd575db4913ce0a9686072c5f970f94c3a2e87d4b2e93e52b2283c81185fb8ab14a757ff04b00b821d1aaac0a81e05d15da64ca823f9aa4b18525521073096f73fd583205086c7db2b6ac243901e4f1898bc600b6700fdd80a0f00020005756e6974730000000000060564756d6d79" + ) val validUnsignedDigitDecompAttestation: OracleAttestmentV0TLV = OracleAttestmentV0TLV( - "fdd868fd01b40564756d6d79545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a850006280b657b9c1cd8de3da2619194e2c71831598be3e60d39a242c232f580451c43050ce8ac95b549bb5fed9e3800cf3c040207071032a5c458485ad1817373c0b7bd61d1a6c395c99202058ddabf851e1c8220f12bd801bbb90efcf45d4a2d769cdaa4e883da6b59cac21fc8f18dae7893997d5d13ac63f33fdb7643bba4c4fc8d57ae1c605b9d36ff8477baa8c216abbfe6c3742236ecfad2415745a7cf7850c6cb6a147a2e2a8875133147055027ed130dec47c6a9f75983d532a5c5940a763546f4835c5b80ca64832a6b9e7526fd575db4913ce0a9686072c5f970f94c3a2e72d0655c541eac15e9caa5af059c1f3e433507f1782e8775c555f1c402509f0c87d4b2e93e52b2283c81185fb8ab14a757ff04b00b821d1aaac0a81e05d15da68e710b25a91bfdacf179d9da3b90dec98844d8ac1ed534922dfa362b9db86c134ca823f9aa4b18525521073096f73fd583205086c7db2b6ac243901e4f1898bc476a311fbcd5d2fb7a355a9032c67dead084fe66eed00f7e9646e6fa83902bc7013001300130013001300130") + "fdd868fd01b40564756d6d79545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a850006280b657b9c1cd8de3da2619194e2c71831598be3e60d39a242c232f580451c43050ce8ac95b549bb5fed9e3800cf3c040207071032a5c458485ad1817373c0b7bd61d1a6c395c99202058ddabf851e1c8220f12bd801bbb90efcf45d4a2d769cdaa4e883da6b59cac21fc8f18dae7893997d5d13ac63f33fdb7643bba4c4fc8d57ae1c605b9d36ff8477baa8c216abbfe6c3742236ecfad2415745a7cf7850c6cb6a147a2e2a8875133147055027ed130dec47c6a9f75983d532a5c5940a763546f4835c5b80ca64832a6b9e7526fd575db4913ce0a9686072c5f970f94c3a2e72d0655c541eac15e9caa5af059c1f3e433507f1782e8775c555f1c402509f0c87d4b2e93e52b2283c81185fb8ab14a757ff04b00b821d1aaac0a81e05d15da68e710b25a91bfdacf179d9da3b90dec98844d8ac1ed534922dfa362b9db86c134ca823f9aa4b18525521073096f73fd583205086c7db2b6ac243901e4f1898bc476a311fbcd5d2fb7a355a9032c67dead084fe66eed00f7e9646e6fa83902bc7013001300130013001300130" + ) // this one was generated with the same public key val invalidUnsignedDigitDecompAttestation: OracleAttestmentV0TLV = { val unsorted = validUnsignedDigitDecompAttestation.sigs.map( - _.copy(sig = FieldElement.one)) + _.copy(sig = FieldElement.one) + ) val sorted = OrderedSchnorrSignatures.fromUnsorted(unsorted.toVector) validUnsignedDigitDecompAttestation.copy(unsortedSignatures = sorted.toVector) @@ -48,15 +53,18 @@ class AttestationVerificationTest extends BitcoinSUnitTest { // this one was generated with a different public key val invalidUnsignedDigitDecompAttestation1: OracleAttestmentV0TLV = OracleAttestmentV0TLV( - "fdd868fd01b00161d485e5557110ec2a4909438ce55f02d9ec349b33989c6344fbbd19aec4ae56d8000667aabd3d20e82e2975d8629240f77295e8d76985f525450372763db775ea0f9029aa9bfb01cc81a39849e81f6d96057e528dcf4decb40a5a521bed2f580871bea09840a976ae6bb2a4052b955bf4720f8178cabe2cd95e490d4853f5772c40060c3a6ed993e7104ceb951a222cd14d0fac69d26ec00d07c3c7de65be07d10fdf994e8ea291c438d11067b84a859e73d99ee7030a246eaaeb8573ad2d7fc1844b2afca351f6dd0c8171090196dfc8fa9641e0748902bcbad6270b36179252fc31ce5c536d7cb69d509f583aa1bd09aac5e7ebbd65872e2809176f55af9f810514a82a8a51b5306ef586aabe8789d3cc47972124a4da4834a2507d1315b7893d5ecb7fd7d4d4bd27eb7c9ce7ff92080b9959625cb4d2a92ac1a0d487168402dfd23248c8f9bce7963f097e58ca5412db68b2f9f9bca86bfe35d83fcedbafb9edccb363f7788fa111bdd9ba8558e7e1c921f04144e24d03a98a81567301df4e511c4ffbbc691beb13498b6628817915ecfb41e5f1e63317d646920df10f4ae9797c013001300130013001300130") + "fdd868fd01b00161d485e5557110ec2a4909438ce55f02d9ec349b33989c6344fbbd19aec4ae56d8000667aabd3d20e82e2975d8629240f77295e8d76985f525450372763db775ea0f9029aa9bfb01cc81a39849e81f6d96057e528dcf4decb40a5a521bed2f580871bea09840a976ae6bb2a4052b955bf4720f8178cabe2cd95e490d4853f5772c40060c3a6ed993e7104ceb951a222cd14d0fac69d26ec00d07c3c7de65be07d10fdf994e8ea291c438d11067b84a859e73d99ee7030a246eaaeb8573ad2d7fc1844b2afca351f6dd0c8171090196dfc8fa9641e0748902bcbad6270b36179252fc31ce5c536d7cb69d509f583aa1bd09aac5e7ebbd65872e2809176f55af9f810514a82a8a51b5306ef586aabe8789d3cc47972124a4da4834a2507d1315b7893d5ecb7fd7d4d4bd27eb7c9ce7ff92080b9959625cb4d2a92ac1a0d487168402dfd23248c8f9bce7963f097e58ca5412db68b2f9f9bca86bfe35d83fcedbafb9edccb363f7788fa111bdd9ba8558e7e1c921f04144e24d03a98a81567301df4e511c4ffbbc691beb13498b6628817915ecfb41e5f1e63317d646920df10f4ae9797c013001300130013001300130" + ) val signedDigitDecompAnnouncement: OracleAnnouncementV0TLV = OracleAnnouncementV0TLV( - "fdd824fd010126487da78218c4fd04d85575595584c54bbec4f2ab3cb64f820bab24c14f9738f4284846c3780985f5c1189decc7680d9c0dbfa5e454b72ac6e292de0df0121ec22db0a9b26f825ccff38cd776103c952c5ede3fc5da3a69770d446011ac126ffdd8229d00049ef0f2b1e7befd3840b4ae6b9f690c6ed42ba9fcddbcde1a7ee91732d63b802ec1e88c69f414e1b47db730ccd4ec1f6e2049e5ce7d569b9dc42263503efb85ed60cbb1d5d42b28d571ef9cb37dba9927a65c819742267862d88acd50a276ad9a624b05aa3829dc181f785f31a0450299a972cc0eb44384529ef30a9a17c0f2aa63328350fdd80a0e00020004746573740000000000040474657374") + "fdd824fd010126487da78218c4fd04d85575595584c54bbec4f2ab3cb64f820bab24c14f9738f4284846c3780985f5c1189decc7680d9c0dbfa5e454b72ac6e292de0df0121ec22db0a9b26f825ccff38cd776103c952c5ede3fc5da3a69770d446011ac126ffdd8229d00049ef0f2b1e7befd3840b4ae6b9f690c6ed42ba9fcddbcde1a7ee91732d63b802ec1e88c69f414e1b47db730ccd4ec1f6e2049e5ce7d569b9dc42263503efb85ed60cbb1d5d42b28d571ef9cb37dba9927a65c819742267862d88acd50a276ad9a624b05aa3829dc181f785f31a0450299a972cc0eb44384529ef30a9a17c0f2aa63328350fdd80a0e00020004746573740000000000040474657374" + ) val validSignedDigitDecompAttestation: OracleAttestmentV0TLV = OracleAttestmentV0TLV( - "fdd868fd012f0474657374c22db0a9b26f825ccff38cd776103c952c5ede3fc5da3a69770d446011ac126f00049ef0f2b1e7befd3840b4ae6b9f690c6ed42ba9fcddbcde1a7ee91732d63b802ec8230d8b4f0c926fa79dd4d24dcda5487c6e4957f4b208811baa11fde9849dddc1e88c69f414e1b47db730ccd4ec1f6e2049e5ce7d569b9dc42263503efb85ed08bfb84dab00ad7f1d1c07eb8e1559ba0c700e88f7387e936883fe77b406efb560cbb1d5d42b28d571ef9cb37dba9927a65c819742267862d88acd50a276ad9a1b25f23a7c49150f83f6b241a5b6b0f91951f285853452ae05ea5f7e8f3846a5624b05aa3829dc181f785f31a0450299a972cc0eb44384529ef30a9a17c0f2aa593b017b084ea40c7f364e5235c9a27f659dc2cfa689e0aa80f4a4cacd4d4de10131013101300130") + "fdd868fd012f0474657374c22db0a9b26f825ccff38cd776103c952c5ede3fc5da3a69770d446011ac126f00049ef0f2b1e7befd3840b4ae6b9f690c6ed42ba9fcddbcde1a7ee91732d63b802ec8230d8b4f0c926fa79dd4d24dcda5487c6e4957f4b208811baa11fde9849dddc1e88c69f414e1b47db730ccd4ec1f6e2049e5ce7d569b9dc42263503efb85ed08bfb84dab00ad7f1d1c07eb8e1559ba0c700e88f7387e936883fe77b406efb560cbb1d5d42b28d571ef9cb37dba9927a65c819742267862d88acd50a276ad9a1b25f23a7c49150f83f6b241a5b6b0f91951f285853452ae05ea5f7e8f3846a5624b05aa3829dc181f785f31a0450299a972cc0eb44384529ef30a9a17c0f2aa593b017b084ea40c7f364e5235c9a27f659dc2cfa689e0aa80f4a4cacd4d4de10131013101300130" + ) val invalidSignedDigitDecompAttestation: OracleAttestmentV0TLV = { val unsorted = @@ -67,70 +75,104 @@ class AttestationVerificationTest extends BitcoinSUnitTest { val invalidSignedDigitDecompAttestation1: OracleAttestmentV0TLV = OracleAttestmentV0TLV( - "fdd868fd01f2017ad485e5557110ec2a4909438ce55f02d9ec349b33989c6344fbbd19aec4ae56d800073da5fcd784525041016e96b7021bd626eed2b88fadb36d073613ab16898b34cc70a20df7bb4324db5f1287c3c1b4e3a860d578bc7327b4b1cc7573798cf071b26c8d3611a45d93c511ea6c94b548d736e79bc485d29c84f071d36c8582e9d70d86d46379556b52b280c35821425dbcefd9f68044bd36e795dc4bd875e1e28ec2d24d6de99140c670b47976d6b97f4c524cfdedd64ef95bef83c4eae85adca9a3dec4632b918aba93702a7efa5847ae64dda9dcea35c54cf42c4b8bf5cdbe5e5561eb3b37e209d762a15e2e967cea608005019e217c6b8178517df319ee82f77688fe174f4424a324e6ee4d9444343350de7454e1cb761436e60fa31bc6f0b1f98a5810dcf8f1ac393df004384c25e15834215f87be3d96c2cc2dc3e8b396f0ae24e6979e7242628852b32e94892812ab63c0c9abb2c72195161e42894f80c4d5bcf9e9c2153857dd15c9b338dc168b04e018b6c983ad41365b6e7827eb8aa2f4e89e535045a904ac19ed08c3cd49a08ad3ca98d264846223e52506c447eb12d420475c9f297957e2467eff0873ff97d8aa5fef0b363665ff6979d36d1a04eaac4d3a4f85eac1111ee9e323ae5638b019d15282cd9b18c35aa0a1b7951957ef3f012b013001300130013001300130") + "fdd868fd01f2017ad485e5557110ec2a4909438ce55f02d9ec349b33989c6344fbbd19aec4ae56d800073da5fcd784525041016e96b7021bd626eed2b88fadb36d073613ab16898b34cc70a20df7bb4324db5f1287c3c1b4e3a860d578bc7327b4b1cc7573798cf071b26c8d3611a45d93c511ea6c94b548d736e79bc485d29c84f071d36c8582e9d70d86d46379556b52b280c35821425dbcefd9f68044bd36e795dc4bd875e1e28ec2d24d6de99140c670b47976d6b97f4c524cfdedd64ef95bef83c4eae85adca9a3dec4632b918aba93702a7efa5847ae64dda9dcea35c54cf42c4b8bf5cdbe5e5561eb3b37e209d762a15e2e967cea608005019e217c6b8178517df319ee82f77688fe174f4424a324e6ee4d9444343350de7454e1cb761436e60fa31bc6f0b1f98a5810dcf8f1ac393df004384c25e15834215f87be3d96c2cc2dc3e8b396f0ae24e6979e7242628852b32e94892812ab63c0c9abb2c72195161e42894f80c4d5bcf9e9c2153857dd15c9b338dc168b04e018b6c983ad41365b6e7827eb8aa2f4e89e535045a904ac19ed08c3cd49a08ad3ca98d264846223e52506c447eb12d420475c9f297957e2467eff0873ff97d8aa5fef0b363665ff6979d36d1a04eaac4d3a4f85eac1111ee9e323ae5638b019d15282cd9b18c35aa0a1b7951957ef3f012b013001300130013001300130" + ) it should "validate valid enum attestations" in { assert( OracleEvent - .verifyAttestations(enumAnnouncement, - validEnumAttestation, - signingVersion)) + .verifyAttestations( + enumAnnouncement, + validEnumAttestation, + signingVersion + ) + ) } it should "not validate invalid enum attestations" in { assert( !OracleEvent - .verifyAttestations(enumAnnouncement, - invalidEnumAttestation, - signingVersion)) + .verifyAttestations( + enumAnnouncement, + invalidEnumAttestation, + signingVersion + ) + ) assert( - !OracleEvent.verifyAttestations(enumAnnouncement, - validUnsignedDigitDecompAttestation, - signingVersion)) + !OracleEvent.verifyAttestations( + enumAnnouncement, + validUnsignedDigitDecompAttestation, + signingVersion + ) + ) } it should "validate valid unsigned digit decomp attestations" in { assert( - OracleEvent.verifyAttestations(unsignedDigitDecompAnnouncement, - validUnsignedDigitDecompAttestation, - signingVersion)) + OracleEvent.verifyAttestations( + unsignedDigitDecompAnnouncement, + validUnsignedDigitDecompAttestation, + signingVersion + ) + ) } it should "not validate invalid unsigned digit decomp attestations" in { assert( - !OracleEvent.verifyAttestations(unsignedDigitDecompAnnouncement, - validEnumAttestation, - signingVersion)) + !OracleEvent.verifyAttestations( + unsignedDigitDecompAnnouncement, + validEnumAttestation, + signingVersion + ) + ) assert( - !OracleEvent.verifyAttestations(unsignedDigitDecompAnnouncement, - invalidUnsignedDigitDecompAttestation, - signingVersion)) + !OracleEvent.verifyAttestations( + unsignedDigitDecompAnnouncement, + invalidUnsignedDigitDecompAttestation, + signingVersion + ) + ) assert( - !OracleEvent.verifyAttestations(unsignedDigitDecompAnnouncement, - invalidUnsignedDigitDecompAttestation1, - signingVersion)) + !OracleEvent.verifyAttestations( + unsignedDigitDecompAnnouncement, + invalidUnsignedDigitDecompAttestation1, + signingVersion + ) + ) } it should "validate valid signed digit decomp attestations" in { assert( - OracleEvent.verifyAttestations(signedDigitDecompAnnouncement, - validSignedDigitDecompAttestation, - signingVersion)) + OracleEvent.verifyAttestations( + signedDigitDecompAnnouncement, + validSignedDigitDecompAttestation, + signingVersion + ) + ) } it should "not validate invalid signed digit decomp attestations" in { assert( - !OracleEvent.verifyAttestations(signedDigitDecompAnnouncement, - validEnumAttestation, - signingVersion)) + !OracleEvent.verifyAttestations( + signedDigitDecompAnnouncement, + validEnumAttestation, + signingVersion + ) + ) assert( - !OracleEvent.verifyAttestations(signedDigitDecompAnnouncement, - invalidSignedDigitDecompAttestation, - signingVersion)) + !OracleEvent.verifyAttestations( + signedDigitDecompAnnouncement, + invalidSignedDigitDecompAttestation, + signingVersion + ) + ) assert( - !OracleEvent.verifyAttestations(signedDigitDecompAnnouncement, - invalidSignedDigitDecompAttestation1, - signingVersion)) + !OracleEvent.verifyAttestations( + signedDigitDecompAnnouncement, + invalidSignedDigitDecompAttestation1, + signingVersion + ) + ) } it must "validate announcement/attesation with out of order nonces" in { @@ -157,9 +199,11 @@ class AttestationVerificationTest extends BitcoinSUnitTest { "3001310130013101300130" val attestationV0 = OracleAttestmentV0TLV.fromHex(attestationHex) - val result = OracleEvent.verifyAttestations(annV0, - attestationV0, - SigningVersion.latest) + val result = OracleEvent.verifyAttestations( + annV0, + attestationV0, + SigningVersion.latest + ) assert(result) } diff --git a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/DLCOracleTest.scala b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/DLCOracleTest.scala index dc3b6d9789..672d74d406 100644 --- a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/DLCOracleTest.scala +++ b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/DLCOracleTest.scala @@ -25,7 +25,8 @@ class DLCOracleTest extends DLCOracleFixture { val futureTime: Instant = TimeUtil.now.plusSeconds(100000) val testDescriptor: EnumEventDescriptorV0TLV = EnumEventDescriptorV0TLV( - enumOutcomes) + enumOutcomes + ) behavior of "DLCOracle" @@ -55,8 +56,10 @@ class DLCOracleTest extends DLCOracleFixture { it must "calculate the correct staking address" in { dlcOracle: DLCOracle => forAllAsync(ChainParamsGenerator.bitcoinNetworkParams) { network => val expected = - Bech32Address(P2WPKHWitnessSPKV0(dlcOracle.publicKey.publicKey), - network) + Bech32Address( + P2WPKHWitnessSPKV0(dlcOracle.publicKey.publicKey), + network + ) assert(dlcOracle.stakingAddress(network) == expected) } } @@ -65,24 +68,28 @@ class DLCOracleTest extends DLCOracleFixture { val message = "hello world" val signature = dlcOracle.signMessage(message) assert( - dlcOracle.publicKey.verify(CryptoUtil.sha256(message).bytes, signature)) + dlcOracle.publicKey.verify(CryptoUtil.sha256(message).bytes, signature) + ) } it must "get the correctly sorted nonces in an announcement " in { dlcOracle: DLCOracle => val eventName = "test" val descriptorTLV = - DigitDecompositionEventDescriptorV0TLV(base = UInt16(2), - isSigned = false, - numDigits = 3, - unit = "units", - precision = Int32.zero) + DigitDecompositionEventDescriptorV0TLV( + base = UInt16(2), + isSigned = false, + numDigits = 3, + unit = "units", + precision = Int32.zero + ) for { - announcement <- dlcOracle.createNewAnnouncement(eventName = eventName, - maturationTime = - futureTime, - descriptorTLV) + announcement <- dlcOracle.createNewAnnouncement( + eventName = eventName, + maturationTime = futureTime, + descriptorTLV + ) // To get around foreign key, won't be needed _ <- dlcOracle.eventOutcomeDAO.deleteAll() @@ -107,8 +114,11 @@ class DLCOracleTest extends DLCOracleFixture { oracleA: DLCOracle => // set to mainnet and give separate db val newConf = oracleA.conf.newConfigOfType( - Vector(ConfigFactory.parseString("bitcoin-s.network = mainnet"), - ConfigFactory.parseString("bitcoin-s.oracle.db.name = oracle1"))) + Vector( + ConfigFactory.parseString("bitcoin-s.network = mainnet"), + ConfigFactory.parseString("bitcoin-s.oracle.db.name = oracle1") + ) + ) newConf.start().flatMap { _ => val oracleB = new DLCOracle()(newConf) @@ -116,21 +126,25 @@ class DLCOracleTest extends DLCOracleFixture { val eventName = "test" val descriptorTLV = - DigitDecompositionEventDescriptorV0TLV(base = UInt16(2), - isSigned = false, - numDigits = 3, - unit = "units", - precision = Int32.zero) + DigitDecompositionEventDescriptorV0TLV( + base = UInt16(2), + isSigned = false, + numDigits = 3, + unit = "units", + precision = Int32.zero + ) for { - announcementA <- oracleA.createNewAnnouncement(eventName = eventName, - maturationTime = - futureTime, - descriptorTLV) - announcementB <- oracleB.createNewAnnouncement(eventName = eventName, - maturationTime = - futureTime, - descriptorTLV) + announcementA <- oracleA.createNewAnnouncement( + eventName = eventName, + maturationTime = futureTime, + descriptorTLV + ) + announcementB <- oracleB.createNewAnnouncement( + eventName = eventName, + maturationTime = futureTime, + descriptorTLV + ) // Can't compare announcementTLV because different nonces might be used for signature _ = assert(announcementA.publicKey == announcementB.publicKey) @@ -140,10 +154,13 @@ class DLCOracleTest extends DLCOracleFixture { eventB <- oracleB.signDigits(eventName, 1) } yield { (eventA, eventB) match { - case (completedA: CompletedDigitDecompositionV0OracleEvent, - completedB: CompletedDigitDecompositionV0OracleEvent) => + case ( + completedA: CompletedDigitDecompositionV0OracleEvent, + completedB: CompletedDigitDecompositionV0OracleEvent + ) => assert( - completedA.oracleAttestmentV0TLV == completedB.oracleAttestmentV0TLV) + completedA.oracleAttestmentV0TLV == completedB.oracleAttestmentV0TLV + ) case (_, _) => fail("Unexpected outcome") } @@ -181,22 +198,26 @@ class DLCOracleTest extends DLCOracleFixture { it must "create two events and use incrementing key indexes" in { dlcOracle: DLCOracle => val create1F = - dlcOracle.createNewDigitDecompAnnouncement(eventName = "test1", - maturationTime = futureTime, - base = UInt16(10), - isSigned = false, - numDigits = 3, - unit = "units", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = "test1", + maturationTime = futureTime, + base = UInt16(10), + isSigned = false, + numDigits = 3, + unit = "units", + precision = Int32.zero + ) val create2F = - dlcOracle.createNewDigitDecompAnnouncement(eventName = "test2", - maturationTime = futureTime, - base = UInt16(10), - isSigned = false, - numDigits = 3, - unit = "units", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = "test2", + maturationTime = futureTime, + base = UInt16(10), + isSigned = false, + numDigits = 3, + unit = "units", + precision = Int32.zero + ) for { _ <- create1F @@ -214,7 +235,8 @@ class DLCOracleTest extends DLCOracleFixture { for { _ <- dlcOracle.createNewAnnouncement("test", futureTime, testDescriptor) res <- recoverToSucceededIf[IllegalArgumentException]( - dlcOracle.createNewAnnouncement("test", futureTime, testDescriptor)) + dlcOracle.createNewAnnouncement("test", futureTime, testDescriptor) + ) } yield res } @@ -241,17 +263,21 @@ class DLCOracleTest extends DLCOracleFixture { assert(event.maturationTime.getEpochSecond == time.getEpochSecond) val expectedEventTLV = - OracleEventV0TLV(event.nonces.toVector, - UInt32(event.maturationTime.getEpochSecond), - testDescriptor, - eventName) + OracleEventV0TLV( + event.nonces.toVector, + UInt32(event.maturationTime.getEpochSecond), + testDescriptor, + eventName + ) assert(event.eventTLV == expectedEventTLV) val expectedAnnouncementTLV = - OracleAnnouncementV0TLV(event.announcementSignature, - event.pubkey, - expectedEventTLV) + OracleAnnouncementV0TLV( + event.announcementSignature, + event.pubkey, + expectedEventTLV + ) assert(event.announcementTLV == expectedAnnouncementTLV) @@ -259,8 +285,8 @@ class DLCOracleTest extends DLCOracleFixture { SigningVersion.latest.calcAnnouncementHash(event.eventTLV) assert( - dlcOracle.publicKey.verify(announceBytes, - event.announcementSignature)) + dlcOracle.publicKey.verify(announceBytes, event.announcementSignature) + ) } } @@ -292,13 +318,18 @@ class DLCOracleTest extends DLCOracleFixture { assert(dlcOracle.publicKey.verify(hash, sig)) assert( - SchnorrDigitalSignature(completedEvent.nonces.head, - completedEvent.attestation) == sig) + SchnorrDigitalSignature( + completedEvent.nonces.head, + completedEvent.attestation + ) == sig + ) assert( - OracleEvent.verifyAttestations(announcement, - completedEvent.oracleAttestmentV0TLV, - signingVersion = - SigningVersion.latest)) + OracleEvent.verifyAttestations( + announcement, + completedEvent.oracleAttestmentV0TLV, + signingVersion = SigningVersion.latest + ) + ) case _: PendingOracleEvent | _: CompletedOracleEvent => fail() } @@ -310,13 +341,15 @@ class DLCOracleTest extends DLCOracleFixture { for { announcement <- - dlcOracle.createNewDigitDecompAnnouncement(eventName = "test", - maturationTime = futureTime, - base = UInt16(10), - isSigned = true, - numDigits = 3, - unit = "units", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = "test", + maturationTime = futureTime, + base = UInt16(10), + isSigned = true, + numDigits = 3, + unit = "units", + precision = Int32.zero + ) _ = assert(announcement.validateSignature) @@ -327,9 +360,11 @@ class DLCOracleTest extends DLCOracleFixture { event match { case completedEvent: CompletedDigitDecompositionV0OracleEvent => val signOutcome = DigitDecompositionSignAttestation(outcome >= 0) - val digitOutcomes = Vector(DigitDecompositionAttestation(3), - DigitDecompositionAttestation(2), - DigitDecompositionAttestation(1)) + val digitOutcomes = Vector( + DigitDecompositionAttestation(3), + DigitDecompositionAttestation(2), + DigitDecompositionAttestation(1) + ) assert(completedEvent.outcomes == signOutcome +: digitOutcomes) // Sign Signature Check @@ -339,37 +374,51 @@ class DLCOracleTest extends DLCOracleFixture { assert( SchnorrDigitalSignature( completedEvent.nonces.head, - completedEvent.attestations.head) == signSig) + completedEvent.attestations.head + ) == signSig + ) // 100s Place signature Check val hash100 = SigningVersion.latest.calcOutcomeHash( - DigitDecompositionAttestation(3).bytes) + DigitDecompositionAttestation(3).bytes + ) val sig100 = completedEvent.signatures(1) assert(dlcOracle.publicKey.verify(hash100, sig100)) assert( - SchnorrDigitalSignature(completedEvent.nonces(1), - completedEvent.attestations(1)) == sig100) + SchnorrDigitalSignature( + completedEvent.nonces(1), + completedEvent.attestations(1) + ) == sig100 + ) // 10s Place signature Check val hash10 = SigningVersion.latest.calcOutcomeHash( - DigitDecompositionAttestation(2).bytes) + DigitDecompositionAttestation(2).bytes + ) val sig10 = completedEvent.signatures(2) assert(dlcOracle.publicKey.verify(hash10, sig10)) assert( - SchnorrDigitalSignature(completedEvent.nonces(2), - completedEvent.attestations(2)) == sig10) + SchnorrDigitalSignature( + completedEvent.nonces(2), + completedEvent.attestations(2) + ) == sig10 + ) // 1s Place signature Check val hash1 = SigningVersion.latest.calcOutcomeHash( - DigitDecompositionAttestation(1).bytes) + DigitDecompositionAttestation(1).bytes + ) val sig1 = completedEvent.signatures(3) assert(dlcOracle.publicKey.verify(hash1, sig1)) assert( - SchnorrDigitalSignature(completedEvent.nonces(3), - completedEvent.attestations(3)) == sig1) + SchnorrDigitalSignature( + completedEvent.nonces(3), + completedEvent.attestations(3) + ) == sig1 + ) case _: PendingOracleEvent | _: CompletedOracleEvent => fail() } @@ -382,14 +431,15 @@ class DLCOracleTest extends DLCOracleFixture { for { announcement <- - dlcOracle.createNewDigitDecompAnnouncement(eventName = "test", - maturationTime = - futureTime, - base = UInt16(16), - isSigned = true, - numDigits = 3, - unit = "units", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = "test", + maturationTime = futureTime, + base = UInt16(16), + isSigned = true, + numDigits = 3, + unit = "units", + precision = Int32.zero + ) _ = assert(announcement.validateSignature) @@ -400,9 +450,11 @@ class DLCOracleTest extends DLCOracleFixture { event match { case completedEvent: CompletedDigitDecompositionV0OracleEvent => val signOutcome = DigitDecompositionSignAttestation(outcome >= 0) - val digitOutcomes = Vector(DigitDecompositionAttestation(7), - DigitDecompositionAttestation(8), - DigitDecompositionAttestation(11)) + val digitOutcomes = Vector( + DigitDecompositionAttestation(7), + DigitDecompositionAttestation(8), + DigitDecompositionAttestation(11) + ) assert(completedEvent.outcomes == signOutcome +: digitOutcomes) // Sign Signature Check @@ -413,37 +465,51 @@ class DLCOracleTest extends DLCOracleFixture { assert( SchnorrDigitalSignature( completedEvent.nonces.head, - completedEvent.attestations.head) == signSig) + completedEvent.attestations.head + ) == signSig + ) // 100s Place signature Check val hash100 = SigningVersion.latest.calcOutcomeHash( - DigitDecompositionAttestation(7).bytes) + DigitDecompositionAttestation(7).bytes + ) val sig100 = completedEvent.signatures(1) assert(dlcOracle.publicKey.verify(hash100, sig100)) assert( - SchnorrDigitalSignature(completedEvent.nonces(1), - completedEvent.attestations(1)) == sig100) + SchnorrDigitalSignature( + completedEvent.nonces(1), + completedEvent.attestations(1) + ) == sig100 + ) // 10s Place signature Check val hash10 = SigningVersion.latest.calcOutcomeHash( - DigitDecompositionAttestation(8).bytes) + DigitDecompositionAttestation(8).bytes + ) val sig10 = completedEvent.signatures(2) assert(dlcOracle.publicKey.verify(hash10, sig10)) assert( - SchnorrDigitalSignature(completedEvent.nonces(2), - completedEvent.attestations(2)) == sig10) + SchnorrDigitalSignature( + completedEvent.nonces(2), + completedEvent.attestations(2) + ) == sig10 + ) // 1s Place signature Check val hash1 = SigningVersion.latest.calcOutcomeHash( - DigitDecompositionAttestation(11).bytes) + DigitDecompositionAttestation(11).bytes + ) val sig1 = completedEvent.signatures(3) assert(dlcOracle.publicKey.verify(hash1, sig1)) assert( - SchnorrDigitalSignature(completedEvent.nonces(3), - completedEvent.attestations(3)) == sig1) + SchnorrDigitalSignature( + completedEvent.nonces(3), + completedEvent.attestations(3) + ) == sig1 + ) case _: PendingOracleEvent | _: CompletedOracleEvent => fail() } @@ -456,14 +522,15 @@ class DLCOracleTest extends DLCOracleFixture { for { announcement <- - dlcOracle.createNewDigitDecompAnnouncement(eventName = "test", - maturationTime = - futureTime, - base = UInt16(2), - isSigned = false, - numDigits = 3, - unit = "units", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = "test", + maturationTime = futureTime, + base = UInt16(2), + isSigned = false, + numDigits = 3, + unit = "units", + precision = Int32.zero + ) _ = assert(announcement.validateSignature) @@ -473,41 +540,54 @@ class DLCOracleTest extends DLCOracleFixture { } yield { event match { case completedEvent: CompletedDigitDecompositionV0OracleEvent => - val digitOutcomes = Vector(DigitDecompositionAttestation(0), - DigitDecompositionAttestation(1), - DigitDecompositionAttestation(0)) + val digitOutcomes = Vector( + DigitDecompositionAttestation(0), + DigitDecompositionAttestation(1), + DigitDecompositionAttestation(0) + ) assert(completedEvent.outcomes == digitOutcomes) // 100s Place signature Check val hash100 = SigningVersion.latest.calcOutcomeHash( - DigitDecompositionAttestation(0).bytes) + DigitDecompositionAttestation(0).bytes + ) val sig100 = completedEvent.signatures.head assert(dlcOracle.publicKey.verify(hash100, sig100)) assert( SchnorrDigitalSignature( completedEvent.nonces.head, - completedEvent.attestations.head) == sig100) + completedEvent.attestations.head + ) == sig100 + ) // 10s Place signature Check val hash10 = SigningVersion.latest.calcOutcomeHash( - DigitDecompositionAttestation(1).bytes) + DigitDecompositionAttestation(1).bytes + ) val sig10 = completedEvent.signatures(1) assert(dlcOracle.publicKey.verify(hash10, sig10)) assert( - SchnorrDigitalSignature(completedEvent.nonces(1), - completedEvent.attestations(1)) == sig10) + SchnorrDigitalSignature( + completedEvent.nonces(1), + completedEvent.attestations(1) + ) == sig10 + ) // 1s Place signature Check val hash1 = SigningVersion.latest.calcOutcomeHash( - DigitDecompositionAttestation(0).bytes) + DigitDecompositionAttestation(0).bytes + ) val sig1 = completedEvent.signatures(2) assert(dlcOracle.publicKey.verify(hash1, sig1)) assert( - SchnorrDigitalSignature(completedEvent.nonces(2), - completedEvent.attestations(2)) == sig1) + SchnorrDigitalSignature( + completedEvent.nonces(2), + completedEvent.attestations(2) + ) == sig1 + ) case _: PendingOracleEvent | _: CompletedOracleEvent => fail() } @@ -516,22 +596,23 @@ class DLCOracleTest extends DLCOracleFixture { it must "create and sign a decomp event with a large num digits" in { dlcOracle: DLCOracle => - //trying make sure we don't regress on - //https://github.com/bitcoin-s/bitcoin-s/issues/3431 + // trying make sure we don't regress on + // https://github.com/bitcoin-s/bitcoin-s/issues/3431 val outcome = 30816 val numDigits = 18 val eventName = "test" for { announcement <- - dlcOracle.createNewDigitDecompAnnouncement(eventName = eventName, - maturationTime = - futureTime, - base = UInt16(2), - isSigned = false, - numDigits = numDigits, - unit = "units", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = eventName, + maturationTime = futureTime, + base = UInt16(2), + isSigned = false, + numDigits = numDigits, + unit = "units", + precision = Int32.zero + ) _ = assert(announcement.validateSignature) @@ -579,8 +660,8 @@ class DLCOracleTest extends DLCOracleFixture { dlcOracle: DLCOracle => val dummyNonce = SchnorrNonce(ECPublicKey.freshPublicKey.bytes.tail) recoverToSucceededIf[RuntimeException]( - dlcOracle.createAttestation(dummyNonce, - EnumAttestation("testOutcomes"))) + dlcOracle.createAttestation(dummyNonce, EnumAttestation("testOutcomes")) + ) } it must "fail to sign an enum outcome that doesn't exist" in { @@ -588,9 +669,11 @@ class DLCOracleTest extends DLCOracleFixture { recoverToSucceededIf[RuntimeException] { for { announcement <- - dlcOracle.createNewEnumAnnouncement("test", - futureTime, - enumOutcomes) + dlcOracle.createNewEnumAnnouncement( + "test", + futureTime, + enumOutcomes + ) nonce = announcement.eventTLV match { case v0: OracleEventV0TLV => v0.nonces.head @@ -598,7 +681,8 @@ class DLCOracleTest extends DLCOracleFixture { _ <- dlcOracle.createAttestation( nonce, - EnumAttestation("not a real outcome")) + EnumAttestation("not a real outcome") + ) } yield () } } @@ -607,14 +691,15 @@ class DLCOracleTest extends DLCOracleFixture { dlcOracle: DLCOracle => for { announcement <- - dlcOracle.createNewDigitDecompAnnouncement(eventName = "test", - maturationTime = - futureTime, - base = UInt16(2), - isSigned = false, - numDigits = 3, - unit = "units", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = "test", + maturationTime = futureTime, + base = UInt16(2), + isSigned = false, + numDigits = 3, + unit = "units", + precision = Int32.zero + ) res <- dlcOracle.signDigits(announcement.eventTLV, -2) } yield { @@ -640,17 +725,19 @@ class DLCOracleTest extends DLCOracleFixture { val rValDb = RValueDb(nonce, eventName, HDPurpose(0), HDCoinType.Bitcoin, 0, 0, 0) val eventDb = - EventDb(nonce, - publicKey, - 0, - eventName, - 0, - sigVersion, - futureTime, - None, - None, - SchnorrDigitalSignature(nonce, FieldElement.one), - testDescriptor) + EventDb( + nonce, + publicKey, + 0, + eventName, + 0, + sigVersion, + futureTime, + None, + None, + SchnorrDigitalSignature(nonce, FieldElement.one), + testDescriptor + ) val setupF = for { _ <- dlcOracle.rValueDAO.create(rValDb) @@ -710,10 +797,12 @@ class DLCOracleTest extends DLCOracleFixture { val eventName = "signed" val maturationTime = futureTime val descriptor = - SignedDigitDecompositionEventDescriptor(UInt16(2), - UInt16(3), - "unit", - Int32(0)) + SignedDigitDecompositionEventDescriptor( + UInt16(2), + UInt16(3), + "unit", + Int32(0) + ) for { announcement: OracleAnnouncementTLV <- @@ -727,10 +816,12 @@ class DLCOracleTest extends DLCOracleFixture { .asInstanceOf[CompletedDigitDecompositionV0OracleEvent] .oracleAttestmentV0TLV assert( - OracleEvent.verifyAttestations(announcement, - attestations, - signingVersion = - SigningVersion.latest)) + OracleEvent.verifyAttestations( + announcement, + attestations, + signingVersion = SigningVersion.latest + ) + ) } } @@ -739,10 +830,12 @@ class DLCOracleTest extends DLCOracleFixture { val eventName = "unsigned" val maturationTime = futureTime val descriptor = - UnsignedDigitDecompositionEventDescriptor(UInt16(2), - UInt16(3), - "unit", - Int32(0)) + UnsignedDigitDecompositionEventDescriptor( + UInt16(2), + UInt16(3), + "unit", + Int32(0) + ) for { announcement: OracleAnnouncementTLV <- @@ -756,10 +849,12 @@ class DLCOracleTest extends DLCOracleFixture { .asInstanceOf[CompletedDigitDecompositionV0OracleEvent] .oracleAttestmentV0TLV assert( - OracleEvent.verifyAttestations(announcement, - attestations, - signingVersion = - SigningVersion.latest)) + OracleEvent.verifyAttestations( + announcement, + attestations, + signingVersion = SigningVersion.latest + ) + ) } } @@ -769,20 +864,26 @@ class DLCOracleTest extends DLCOracleFixture { val eventName2 = "unsigned2" val maturationTime = futureTime val descriptor = - UnsignedDigitDecompositionEventDescriptor(UInt16(2), - UInt16(3), - "unit", - Int32(0)) + UnsignedDigitDecompositionEventDescriptor( + UInt16(2), + UInt16(3), + "unit", + Int32(0) + ) for { announcement1: OracleAnnouncementTLV <- - dlcOracle.createNewAnnouncement(eventName1, - maturationTime, - descriptor) + dlcOracle.createNewAnnouncement( + eventName1, + maturationTime, + descriptor + ) announcement2: OracleAnnouncementTLV <- - dlcOracle.createNewAnnouncement(eventName2, - maturationTime, - descriptor) + dlcOracle.createNewAnnouncement( + eventName2, + maturationTime, + descriptor + ) event1 <- dlcOracle .signDigits(announcement1.eventTLV, 2) @@ -800,15 +901,19 @@ class DLCOracleTest extends DLCOracleFixture { .oracleAttestmentV0TLV assert( - !OracleEvent.verifyAttestations(announcement1, - attestations2, - signingVersion = - SigningVersion.latest)) + !OracleEvent.verifyAttestations( + announcement1, + attestations2, + signingVersion = SigningVersion.latest + ) + ) assert( - !OracleEvent.verifyAttestations(announcement2, - attestations1, - signingVersion = - SigningVersion.latest)) + !OracleEvent.verifyAttestations( + announcement2, + attestations1, + signingVersion = SigningVersion.latest + ) + ) } } @@ -852,10 +957,12 @@ class DLCOracleTest extends DLCOracleFixture { it must "create and delete signatures for a decomp event" in { dlcOracle: DLCOracle => val descriptor = - UnsignedDigitDecompositionEventDescriptor(UInt16(2), - UInt16(3), - "unit", - Int32(0)) + UnsignedDigitDecompositionEventDescriptor( + UInt16(2), + UInt16(3), + "unit", + Int32(0) + ) for { _ <- dlcOracle.createNewAnnouncement("test", futureTime, descriptor) @@ -887,20 +994,24 @@ class DLCOracleTest extends DLCOracleFixture { it must "fail to delete signatures for an unsigned enum event" in { dlcOracle: DLCOracle => val descriptor = - UnsignedDigitDecompositionEventDescriptor(UInt16(2), - UInt16(3), - "unit", - Int32(0)) + UnsignedDigitDecompositionEventDescriptor( + UInt16(2), + UInt16(3), + "unit", + Int32(0) + ) for { _ <- dlcOracle.createNewAnnouncement("test", futureTime, descriptor) signedEvent <- dlcOracle.findEvent("test").map(_.get) _ = assert( - signedEvent.isInstanceOf[PendingDigitDecompositionV0OracleEvent]) + signedEvent.isInstanceOf[PendingDigitDecompositionV0OracleEvent] + ) res <- recoverToSucceededIf[IllegalArgumentException]( - dlcOracle.deleteAttestation("test")) + dlcOracle.deleteAttestation("test") + ) } yield res } @@ -915,20 +1026,23 @@ class DLCOracleTest extends DLCOracleFixture { _ = assert(signedEvent.isInstanceOf[PendingEnumV0OracleEvent]) res <- recoverToSucceededIf[IllegalArgumentException]( - dlcOracle.deleteAttestation("test")) + dlcOracle.deleteAttestation("test") + ) } yield res } it must "delete enum announcements" in { dlcOracle => val eventName = "test" val createdF = - dlcOracle.createNewEnumAnnouncement(eventName, - futureTime, - Vector("0", "1", "2")) + dlcOracle.createNewEnumAnnouncement( + eventName, + futureTime, + Vector("0", "1", "2") + ) for { c <- createdF _ <- dlcOracle.deleteAnnouncement(c) - //make sure we can't find it + // make sure we can't find it annOpt <- dlcOracle.findEvent(eventName) } yield { assert(annOpt.isEmpty) @@ -938,17 +1052,19 @@ class DLCOracleTest extends DLCOracleFixture { it must "delete numeric announcements" in { dlcOracle => val eventName = "test" val createdF = - dlcOracle.createNewDigitDecompAnnouncement(eventName = eventName, - maturationTime = futureTime, - base = UInt16.two, - isSigned = false, - numDigits = 2, - unit = "UNIT", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = eventName, + maturationTime = futureTime, + base = UInt16.two, + isSigned = false, + numDigits = 2, + unit = "UNIT", + precision = Int32.zero + ) for { c <- createdF _ <- dlcOracle.deleteAnnouncement(c) - //make sure we can't find it + // make sure we can't find it annOpt <- dlcOracle.findEvent(eventName) } yield { assert(annOpt.isEmpty) @@ -959,13 +1075,15 @@ class DLCOracleTest extends DLCOracleFixture { dlcOracle => val eventName = "test" val createdF = - dlcOracle.createNewDigitDecompAnnouncement(eventName = eventName, - maturationTime = futureTime, - base = UInt16(2), - isSigned = false, - numDigits = 2, - unit = "UNIT", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = eventName, + maturationTime = futureTime, + base = UInt16(2), + isSigned = false, + numDigits = 2, + unit = "UNIT", + precision = Int32.zero + ) val resultF = for { _ <- createdF @@ -997,13 +1115,15 @@ class DLCOracleTest extends DLCOracleFixture { it must "delete numeric attestations" in { dlcOracle: DLCOracle => val eventName = "test" val createdF = - dlcOracle.createNewDigitDecompAnnouncement(eventName = eventName, - maturationTime = futureTime, - base = UInt16(2), - isSigned = false, - numDigits = 2, - unit = "UNIT", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = eventName, + maturationTime = futureTime, + base = UInt16(2), + isSigned = false, + numDigits = 2, + unit = "UNIT", + precision = Int32.zero + ) for { _ <- createdF @@ -1020,13 +1140,15 @@ class DLCOracleTest extends DLCOracleFixture { dlcOracle: DLCOracle => val eventName = "test" val createdF = - dlcOracle.createNewDigitDecompAnnouncement(eventName = eventName, - maturationTime = futureTime, - base = UInt16(2), - isSigned = false, - numDigits = 2, - unit = "UNIT", - precision = Int32.zero) + dlcOracle.createNewDigitDecompAnnouncement( + eventName = eventName, + maturationTime = futureTime, + base = UInt16(2), + isSigned = false, + numDigits = 2, + unit = "UNIT", + precision = Int32.zero + ) for { _ <- createdF diff --git a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfigTest.scala b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfigTest.scala index 3cecf36bd8..f737d4c390 100644 --- a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfigTest.scala +++ b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfigTest.scala @@ -36,26 +36,26 @@ class DLCOracleAppConfigTest extends DLCOracleAppConfigFixture { dlcOracle.publicKey } - //stop old oracle + // stop old oracle val stoppedF = for { _ <- startedF _ <- dlcOracleAppConfig.stop() } yield () - //move the seed file to a new datadir + // move the seed file to a new datadir val newDatadir = BitcoinSTestAppConfig.tmpDir() val newSeedPath = newDatadir .resolve("seeds") .resolve(WalletStorage.ENCRYPTED_SEED_FILE_NAME) - //create seed directory + // create seed directory Files.createDirectories(newSeedPath.getParent) val copyF = startedF.map { _ => - //copy seed file to new directory + // copy seed file to new directory Files.copy(seedFile, newSeedPath) } - //start the new app config from the new datadir + // start the new app config from the new datadir val appConfig = DLCOracleAppConfig .fromDatadir(newDatadir) @@ -80,7 +80,7 @@ class DLCOracleAppConfigTest extends DLCOracleAppConfigFixture { val seedFile = dlcOracleAppConfig.seedPath val startedF = dlcOracleAppConfig.start() - //stop old oracle + // stop old oracle val stoppedF = for { _ <- startedF _ <- dlcOracleAppConfig.stop() @@ -89,7 +89,7 @@ class DLCOracleAppConfigTest extends DLCOracleAppConfigFixture { val deletedF = for { _ <- stoppedF } yield { - //delete the seed so we start with a new seed + // delete the seed so we start with a new seed Files.delete(seedFile) } @@ -98,7 +98,7 @@ class DLCOracleAppConfigTest extends DLCOracleAppConfigFixture { _ <- dlcOracleAppConfig.start() } yield () - //start it again and except an exception + // start it again and except an exception recoverToSucceededIf[RuntimeException] { start2F } diff --git a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/storage/EventDAOTest.scala b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/storage/EventDAOTest.scala index 00ce0340f1..056d0b7374 100644 --- a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/storage/EventDAOTest.scala +++ b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/storage/EventDAOTest.scala @@ -43,17 +43,19 @@ class EventDAOTest extends DLCOracleDAOFixture { val eventDAO = daos.eventDAO val eventDb = - EventDb(nonce, - publicKey, - 0, - eventName, - 0, - sigVersion, - time, - None, - None, - dummySig, - descriptor) + EventDb( + nonce, + publicKey, + 0, + eventName, + 0, + sigVersion, + time, + None, + None, + dummySig, + descriptor + ) for { _ <- rValDAO.create(dummyRValDb) @@ -67,17 +69,19 @@ class EventDAOTest extends DLCOracleDAOFixture { val eventDAO = daos.eventDAO val eventDb = - EventDb(nonce, - publicKey, - 0, - eventName, - 0, - sigVersion, - time, - None, - None, - dummySig, - descriptor) + EventDb( + nonce, + publicKey, + 0, + eventName, + 0, + sigVersion, + time, + None, + None, + dummySig, + descriptor + ) for { _ <- rValDAO.create(dummyRValDb) diff --git a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/storage/EventOutcomeDAOTest.scala b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/storage/EventOutcomeDAOTest.scala index 75f732849f..6622a06228 100644 --- a/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/storage/EventOutcomeDAOTest.scala +++ b/dlc-oracle-test/src/test/scala/org/bitcoins/dlc/oracle/storage/EventOutcomeDAOTest.scala @@ -39,17 +39,19 @@ class EventOutcomeDAOTest extends DLCOracleDAOFixture { def descriptor: EventDescriptorTLV = TLVGen.eventDescriptorTLV.sampleSome val dummyEventDb: EventDb = - EventDb(nonce, - publicKey, - 0, - eventName, - 1, - sigVersion, - time, - None, - None, - SchnorrDigitalSignature(nonce, FieldElement.one), - descriptor) + EventDb( + nonce, + publicKey, + 0, + eventName, + 1, + sigVersion, + time, + None, + None, + SchnorrDigitalSignature(nonce, FieldElement.one), + descriptor + ) it must "create an EventOutcomeDb and read it" in { daos => val rValDAO = daos.rValueDAO diff --git a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/DLCOracle.scala b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/DLCOracle.scala index 401f68d7dd..4d065bba81 100644 --- a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/DLCOracle.scala +++ b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/DLCOracle.scala @@ -60,10 +60,12 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) /** The root private key for this oracle */ private[this] val extPrivateKey: ExtPrivateKeyHardened = { - WalletStorage.getPrivateKeyFromDisk(conf.kmConf.seedPath, - SegWitTestNet3Priv, - conf.aesPasswordOpt, - conf.bip39PasswordOpt) + WalletStorage.getPrivateKeyFromDisk( + conf.kmConf.seedPath, + SegWitTestNet3Priv, + conf.aesPasswordOpt, + conf.bip39PasswordOpt + ) } def getRootXpub: ExtPublicKey = extPrivateKey.extPublicKey @@ -76,7 +78,8 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) val index = 0 val path = BIP32Path.fromHardenedString( - s"m/${purpose.constant}'/${coin.coinType.toInt}'/${account.index}'/${chain.index}'/$index'") + s"m/${purpose.constant}'/${coin.coinType.toInt}'/${account.index}'/${chain.index}'/$index'" + ) extPrivateKey.deriveChildPrivKey(path).key } @@ -107,20 +110,25 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) val purpose = coin.purpose BIP32Path.fromString( - s"m/${purpose.constant}'/${coin.coinType.toInt}'/$accountIndex'/$rValueChainIndex'/$keyIndex'") + s"m/${purpose.constant}'/${coin.coinType.toInt}'/$accountIndex'/$rValueChainIndex'/$keyIndex'" + ) } private def getKValue( rValDb: RValueDb, - signingVersion: SigningVersion): ECPrivateKey = + signingVersion: SigningVersion + ): ECPrivateKey = getKValue(rValDb.eventName, rValDb.path, signingVersion) private def getKValue( label: String, path: BIP32Path, - signingVersion: SigningVersion): ECPrivateKey = { - require(path.forall(_.hardened), - s"Cannot use a BIP32Path with unhardened nodes, got $path") + signingVersion: SigningVersion + ): ECPrivateKey = { + require( + path.forall(_.hardened), + s"Cannot use a BIP32Path with unhardened nodes, got $path" + ) val priv = extPrivateKey.deriveChildPrivKey(path).key val tweakBytes = signingVersion.calcNonceTweak(priv.schnorrNonce, label) val tweak = ECPrivateKey(tweakBytes) @@ -158,7 +166,8 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) } override def findEvent( - oracleEventTLV: OracleEventTLV): Future[Option[OracleEvent]] = { + oracleEventTLV: OracleEventTLV + ): Future[Option[OracleEvent]] = { eventDAO.findByOracleEventTLV(oracleEventTLV).map { dbs => if (dbs.isEmpty) { None @@ -181,19 +190,25 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) isSigned: Boolean, numDigits: Int, unit: String, - precision: Int32): Future[OracleAnnouncementTLV] = { - require(base > UInt16.zero, - s"base cannot be less than 1, got ${base.toInt}") + precision: Int32 + ): Future[OracleAnnouncementTLV] = { + require( + base > UInt16.zero, + s"base cannot be less than 1, got ${base.toInt}" + ) require(numDigits > 0, s"numDigits cannot be less than 1, got $numDigits") logger.info( - s"Create new digit decomp event with eventId=$eventName base=$base numDigits=$numDigits unit=$unit") + s"Create new digit decomp event with eventId=$eventName base=$base numDigits=$numDigits unit=$unit" + ) - val descriptorTLV = DigitDecompositionEventDescriptorV0TLV(base, - isSigned, - numDigits, - unit, - precision) + val descriptorTLV = DigitDecompositionEventDescriptorV0TLV( + base, + isSigned, + numDigits, + unit, + precision + ) createNewAnnouncement(eventName, maturationTime, descriptorTLV) } @@ -201,13 +216,17 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) override def createNewEnumAnnouncement( eventName: String, maturationTime: Instant, - outcomes: Vector[String]): Future[OracleAnnouncementTLV] = { + outcomes: Vector[String] + ): Future[OracleAnnouncementTLV] = { require(outcomes.nonEmpty, "Cannot make an event with no outcomes") - require(outcomes.distinct.size == outcomes.size, - s"Cannot have duplicate outcomes, got $outcomes") + require( + outcomes.distinct.size == outcomes.size, + s"Cannot have duplicate outcomes, got $outcomes" + ) logger.info( - s"Creating new enum announcement eventName=$eventName outcomes=$outcomes") + s"Creating new enum announcement eventName=$eventName outcomes=$outcomes" + ) val descriptorTLV = EnumEventDescriptorV0TLV(outcomes) createNewAnnouncement(eventName, maturationTime, descriptorTLV) @@ -217,10 +236,12 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) eventName: String, maturationTime: Instant, descriptor: EventDescriptorTLV, - signingVersion: SigningVersion = SigningVersion.latest): Future[ - OracleAnnouncementTLV] = { - require(maturationTime.isAfter(TimeUtil.now), - s"Event cannot mature in the past, got $maturationTime") + signingVersion: SigningVersion = SigningVersion.latest + ): Future[OracleAnnouncementTLV] = { + require( + maturationTime.isAfter(TimeUtil.now), + s"Event cannot mature in the past, got $maturationTime" + ) for { dbs <- eventDAO.findByEventName(eventName) @@ -236,11 +257,13 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) val path = getPath(index) val nonce = getKValue(eventName, path, signingVersion).schnorrNonce - RValueDbHelper(nonce = nonce, - eventName = eventName, - account = rValAccount, - chainType = rValueChainIndex, - keyIndex = index) + RValueDbHelper( + nonce = nonce, + eventName = eventName, + account = rValAccount, + chainType = rValueChainIndex, + keyIndex = index + ) } .toVector @@ -248,27 +271,32 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) nonces = rValueDbs.map(_.nonce) - eventTLV = OracleEventV0TLV(OrderedNonces.fromUnsorted(nonces).toVector, - epoch, - descriptor, - eventName) + eventTLV = OracleEventV0TLV( + OrderedNonces.fromUnsorted(nonces).toVector, + epoch, + descriptor, + eventName + ) announcementBytes = signingVersion.calcAnnouncementHash(eventTLV) announcementSignature = signingKey.schnorrSign(announcementBytes) - oracleAnnouncement = OracleAnnouncementV0TLV(announcementSignature = - announcementSignature, - publicKey = publicKey, - eventTLV = eventTLV) + oracleAnnouncement = OracleAnnouncementV0TLV( + announcementSignature = announcementSignature, + publicKey = publicKey, + eventTLV = eventTLV + ) eventOutcomeDbs = EventDbUtil.toEventOutcomeDbs( oracleAnnouncementV0TLV = oracleAnnouncement, - signingVersion = signingVersion) + signingVersion = signingVersion + ) - eventDbs = EventDbUtil.toEventDbs(oracleAnnouncementV0TLV = - oracleAnnouncement, - eventName = eventName, - signingVersion = signingVersion) + eventDbs = EventDbUtil.toEventDbs( + oracleAnnouncementV0TLV = oracleAnnouncement, + eventName = eventName, + signingVersion = signingVersion + ) rValueA = rValueDAO.createAllAction(rValueDbs) eventDbsA = eventDAO.createAllAction(eventDbs) @@ -282,12 +310,15 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) override def signEnum( eventName: String, - outcome: EnumAttestation): Future[EventDb] = { + outcome: EnumAttestation + ): Future[EventDb] = { logger.info(s"Signing enum eventName=$eventName outcome=$outcome") for { eventDbs <- eventDAO.findByEventName(eventName) - _ = require(eventDbs.size == 1, - "Use signLargeRange for signing multi nonce outcomes") + _ = require( + eventDbs.size == 1, + "Use signLargeRange for signing multi nonce outcomes" + ) sign <- createAttestation(eventDbs.head.nonce, outcome) } yield sign @@ -295,13 +326,17 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) override def signEnum( oracleEventTLV: OracleEventTLV, - outcome: EnumAttestation): Future[EventDb] = { + outcome: EnumAttestation + ): Future[EventDb] = { logger.info( - s"Signing enum eventName=${oracleEventTLV.eventId} outcome=$outcome") + s"Signing enum eventName=${oracleEventTLV.eventId} outcome=$outcome" + ) for { eventDbs <- eventDAO.findByOracleEventTLV(oracleEventTLV) - _ = require(eventDbs.size == 1, - "Use signLargeRange for signing multi nonce outcomes") + _ = require( + eventDbs.size == 1, + "Use signLargeRange for signing multi nonce outcomes" + ) sign <- createAttestation(eventDbs.head.nonce, outcome) } yield sign @@ -309,8 +344,8 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) private def createAttestationActionF( nonce: SchnorrNonce, - outcome: DLCAttestationType): Future[ - DBIOAction[EventDb, NoStream, Effect.Write]] = { + outcome: DLCAttestationType + ): Future[DBIOAction[EventDb, NoStream, Effect.Write]] = { for { rValDbOpt <- rValueDAO.read(nonce) rValDb <- rValDbOpt match { @@ -318,7 +353,9 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) case None => Future.failed( new IllegalArgumentException( - s"Nonce not found from this oracle ${nonce.hex}")) + s"Nonce not found from this oracle ${nonce.hex}" + ) + ) } eventOpt <- eventDAO.read(nonce) @@ -326,12 +363,15 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) case Some(value) => require( value.attestationOpt.isEmpty, - s"Event already has been signed, attestation: ${value.sigOpt.get.hex}") + s"Event already has been signed, attestation: ${value.sigOpt.get.hex}" + ) Future.successful(value) case None => Future.failed( new IllegalArgumentException( - s"No event saved with nonce ${nonce.hex} $outcome")) + s"No event saved with nonce ${nonce.hex} $outcome" + ) + ) } hash = eventDb.signingVersion @@ -340,8 +380,11 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) eventOutcomeDb <- eventOutcomeOpt match { case Some(value) => Future.successful(value) case None => - Future.failed(new IllegalArgumentException( - s"No event outcome saved with nonce and message ${nonce.hex} ${outcome.outcomeString}")) + Future.failed( + new IllegalArgumentException( + s"No event outcome saved with nonce and message ${nonce.hex} ${outcome.outcomeString}" + ) + ) } sigVersion = eventDb.signingVersion @@ -355,18 +398,21 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) hashBytes = eventOutcomeDb.hashedMessage sig = signingKey.schnorrSignWithNonce(hashBytes, kVal) - updated = eventDb.copy(attestationOpt = Some(sig.sig), - outcomeOpt = Some(outcome.outcomeString)) + updated = eventDb.copy( + attestationOpt = Some(sig.sig), + outcomeOpt = Some(outcome.outcomeString) + ) eventUpdateA = eventDAO.updateAction(updated) } yield eventUpdateA } - /** Signs the event for the single nonce - * This will be called multiple times by signDigits for each nonce + /** Signs the event for the single nonce This will be called multiple times by + * signDigits for each nonce */ override def createAttestation( nonce: SchnorrNonce, - outcome: DLCAttestationType): Future[EventDb] = { + outcome: DLCAttestationType + ): Future[EventDb] = { val actionF = createAttestationActionF(nonce, outcome) actionF.flatMap(action => safeDatabase.run(action)) } @@ -374,22 +420,27 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) override def signDigits(eventName: String, num: Long): Future[OracleEvent] = { for { eventOpt <- findEvent(eventName) - _ = require(eventOpt.isDefined, - s"No event found by event name $eventName") + _ = require( + eventOpt.isDefined, + s"No event found by event name $eventName" + ) res <- signDigits(eventOpt.get.announcementTLV.eventTLV, num) } yield res } override def signDigits( oracleEventTLV: OracleEventTLV, - num: Long): Future[OracleEvent] = { + num: Long + ): Future[OracleEvent] = { logger.info( - s"Signing digits for eventName=${oracleEventTLV.eventId} num=$num") + s"Signing digits for eventName=${oracleEventTLV.eventId} num=$num" + ) val eventDescriptorTLV: DigitDecompositionEventDescriptorV0TLV = { oracleEventTLV.eventDescriptor match { case _: EnumEventDescriptorV0TLV => throw new IllegalArgumentException( - "Must have a DigitDecomposition event descriptor use signEvent instead") + "Must have a DigitDecomposition event descriptor use signEvent instead" + ) case decomp: DigitDecompositionEventDescriptorV0TLV => decomp } @@ -410,17 +461,21 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) val boundedNum = if (num < eventDescriptorTLV.minNum) { logger.info( - s"Number given $num is less than the minimum, signing minimum instead") + s"Number given $num is less than the minimum, signing minimum instead" + ) eventDescriptorTLV.minNum.toLong } else if (num > eventDescriptorTLV.maxNum) { logger.info( - s"Number given $num is greater than the maximum, signing maximum instead") + s"Number given $num is greater than the maximum, signing maximum instead" + ) eventDescriptorTLV.maxNum.toLong } else num - val decomposed = NumberUtil.decompose(Math.abs(boundedNum), - eventDescriptorTLV.base.toInt, - eventDescriptorTLV.numDigits.toInt) + val decomposed = NumberUtil.decompose( + Math.abs(boundedNum), + eventDescriptorTLV.base.toInt, + eventDescriptorTLV.numDigits.toInt + ) val oracleEventNonces = oracleEventTLV match { case v0: OracleEventV0TLV => @@ -433,15 +488,16 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) oracleEventNonces.tail } - val digitSigAVecF: Future[ - Vector[DBIOAction[EventDb, NoStream, Effect.Write]]] = Future.sequence { - nonces.zipWithIndex.map { case (nonce, index) => - val digit = decomposed(index) - createAttestationActionF(nonce, DigitDecompositionAttestation(digit)) - }.toVector - } - val digitSigAF: Future[ - DBIOAction[Vector[EventDb], NoStream, Effect.Write]] = { + val digitSigAVecF + : Future[Vector[DBIOAction[EventDb, NoStream, Effect.Write]]] = + Future.sequence { + nonces.zipWithIndex.map { case (nonce, index) => + val digit = decomposed(index) + createAttestationActionF(nonce, DigitDecompositionAttestation(digit)) + }.toVector + } + val digitSigAF + : Future[DBIOAction[Vector[EventDb], NoStream, Effect.Write]] = { digitSigAVecF.map(digitSigs => DBIO.sequence(digitSigs)) } @@ -460,17 +516,21 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) /** @inheritdoc */ override def deleteAnnouncement( - eventName: String): Future[OracleAnnouncementTLV] = { + eventName: String + ): Future[OracleAnnouncementTLV] = { logger.warn(s"Deleting announcement with name=$eventName") for { eventOpt <- findEvent(eventName) - _ = require(eventOpt.isDefined, - s"No announcement found by event name $eventName") + _ = require( + eventOpt.isDefined, + s"No announcement found by event name $eventName" + ) event = eventOpt.get eventDbs <- eventDAO.findByOracleEventTLV(event.eventTLV) _ = require( eventDbs.forall(_.attestationOpt.isEmpty), - s"Cannot have attesations defined when deleting an announcement, name=$eventName") + s"Cannot have attesations defined when deleting an announcement, name=$eventName" + ) nonces = eventDbs.map(_.nonce) rVals <- rValueDAO.findByNonces(nonces) outcomeDbs <- eventOutcomeDAO.findByNonces(nonces) @@ -482,35 +542,41 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) /** @inheritdoc */ override def deleteAnnouncement( - announcementTLV: OracleAnnouncementTLV): Future[OracleAnnouncementTLV] = { + announcementTLV: OracleAnnouncementTLV + ): Future[OracleAnnouncementTLV] = { deleteAnnouncement(announcementTLV.eventTLV.eventId.toString) } /** Deletes attestations for the given event * - * WARNING: if previous signatures have been made public - * the oracle private key will be revealed. + * WARNING: if previous signatures have been made public the oracle private + * key will be revealed. */ override def deleteAttestation(eventName: String): Future[OracleEvent] = { for { eventOpt <- findEvent(eventName) - _ = require(eventOpt.isDefined, - s"No event found by event name $eventName") + _ = require( + eventOpt.isDefined, + s"No event found by event name $eventName" + ) res <- deleteAttestation(eventOpt.get.eventTLV) } yield res } /** Deletes attestations for the given event * - * WARNING: if previous signatures have been made public - * the oracle private key will be revealed. + * WARNING: if previous signatures have been made public the oracle private + * key will be revealed. */ override def deleteAttestation( - oracleEventTLV: OracleEventTLV): Future[OracleEvent] = { + oracleEventTLV: OracleEventTLV + ): Future[OracleEvent] = { for { eventDbs <- eventDAO.findByOracleEventTLV(oracleEventTLV) - _ = require(eventDbs.exists(_.attestationOpt.isDefined), - s"Event given is unsigned") + _ = require( + eventDbs.exists(_.attestationOpt.isDefined), + s"Event given is unsigned" + ) updated = eventDbs.map(_.copy(outcomeOpt = None, attestationOpt = None)) _ <- eventDAO.updateAll(updated) @@ -526,8 +592,10 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig) } override def exportSigningKeyWIF: String = { - ECPrivateKeyUtil.toWIF(privKey = signingKey.toPrivateKeyBytes(false), - network = MainNet) + ECPrivateKeyUtil.toWIF( + privKey = signingKey.toPrivateKeyBytes(false), + network = MainNet + ) } } @@ -538,7 +606,8 @@ object DLCOracle { /** Gets the DLC oracle from the given datadir */ def fromDatadir(path: Path, configs: Vector[Config])(implicit - ec: ExecutionContext): Future[DLCOracle] = { + ec: ExecutionContext + ): Future[DLCOracle] = { implicit val appConfig = DLCOracleAppConfig.fromDatadir(datadir = path, configs) val masterXpubDAO: MasterXPubDAO = MasterXPubDAO()(ec, appConfig) @@ -548,7 +617,8 @@ object DLCOracle { _ <- appConfig.start() _ <- MasterXPubUtil.checkMasterXPub(oracle.getRootXpub, masterXpubDAO) differentKeyDbs <- oracle.eventDAO.findDifferentPublicKey( - oracle.publicKey) + oracle.publicKey + ) fixedDbs = differentKeyDbs.map(_.copy(pubkey = oracle.publicKey)) _ <- oracle.eventDAO.updateAll(fixedDbs) } yield oracle diff --git a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfig.scala b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfig.scala index 07e029b092..8a69c98080 100644 --- a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfig.scala +++ b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/config/DLCOracleAppConfig.scala @@ -26,7 +26,8 @@ import scala.concurrent.{ExecutionContext, Future} case class DLCOracleAppConfig( baseDatadir: Path, - configOverrides: Vector[Config])(implicit val ec: ExecutionContext) + configOverrides: Vector[Config] +)(implicit val ec: ExecutionContext) extends DbAppConfig with DbManagement with JdbcProfileComponent[DLCOracleAppConfig] @@ -41,7 +42,9 @@ case class DLCOracleAppConfig( override def newConfigOfType(configs: Vector[Config]): DLCOracleAppConfig = DLCOracleAppConfig(baseDatadir, configs) - /** DLC oracles are not network specific, so just hard code the testnet chain params */ + /** DLC oracles are not network specific, so just hard code the testnet chain + * params + */ final override lazy val chain: BitcoinChainParams = TestNetChainParams /** DLC oracles are not network specific, so just hard code the network */ @@ -100,7 +103,7 @@ case class DLCOracleAppConfig( _ <- migrationWorkAroundF } yield { if (isHikariLoggingEnabled) { - //.get is safe because hikari logging is enabled + // .get is safe because hikari logging is enabled startHikariLogger(hikariLoggingInterval.get) () } else { @@ -123,9 +126,11 @@ case class DLCOracleAppConfig( def rpcPassword: String = config.getString("bitcoin-s.oracle.password") lazy val kmParams: KeyManagerParams = - KeyManagerParams(kmConf.seedPath, - HDPurpose(DLCOracle.R_VALUE_PURPOSE), - network) + KeyManagerParams( + kmConf.seedPath, + HDPurpose(DLCOracle.R_VALUE_PURPOSE), + network + ) lazy val aesPasswordOpt: Option[AesPassword] = kmConf.aesPasswordOpt lazy val bip39PasswordOpt: Option[String] = kmConf.bip39PasswordOpt @@ -142,9 +147,11 @@ case class DLCOracleAppConfig( private def initializeKeyManager(): Future[Unit] = { val initF = seedExists().flatMap { bool => if (!bool) { - BIP39KeyManager.fromParams(kmParams = kmParams, - passwordOpt = aesPasswordOpt, - bip39PasswordOpt = bip39PasswordOpt) match { + BIP39KeyManager.fromParams( + kmParams = kmParams, + passwordOpt = aesPasswordOpt, + bip39PasswordOpt = bip39PasswordOpt + ) match { case Left(err) => sys.error(err.toString) case Right(km) => logger.info("Successfully generated a seed and key manager") @@ -219,6 +226,7 @@ object DLCOracleAppConfig extends AppConfigFactory[DLCOracleAppConfig] { override val moduleName: String = "oracle" override def fromDatadir(datadir: Path, confs: Vector[Config])(implicit - ec: ExecutionContext): DLCOracleAppConfig = + ec: ExecutionContext + ): DLCOracleAppConfig = DLCOracleAppConfig(datadir, confs) } diff --git a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/EventDAO.scala b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/EventDAO.scala index 1b50ad5fdd..30371fa2c4 100644 --- a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/EventDAO.scala +++ b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/EventDAO.scala @@ -17,8 +17,8 @@ import scala.concurrent.{ExecutionContext, Future} case class EventDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCOracleAppConfig) - extends CRUD[EventDb, SchnorrNonce] + override val appConfig: DLCOracleAppConfig +) extends CRUD[EventDb, SchnorrNonce] with SlickUtil[EventDb, SchnorrNonce] { import profile.api._ @@ -36,11 +36,13 @@ case class EventDAO()(implicit createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - ids: Vector[SchnorrNonce]): Query[EventTable, EventDb, Seq] = + ids: Vector[SchnorrNonce] + ): Query[EventTable, EventDb, Seq] = table.filter(_.nonce.inSet(ids)) override protected def findAll( - ts: Vector[EventDb]): Query[EventTable, EventDb, Seq] = + ts: Vector[EventDb] + ): Query[EventTable, EventDb, Seq] = findByPrimaryKeys(ts.map(_.nonce)) def getPendingEvents: Future[Vector[EventDb]] = { @@ -62,14 +64,16 @@ case class EventDAO()(implicit } def findByEventDescriptor( - descriptorTLV: EventDescriptorTLV): Future[Vector[EventDb]] = { + descriptorTLV: EventDescriptorTLV + ): Future[Vector[EventDb]] = { val query = table.filter(_.eventDescriptorTLV === descriptorTLV) safeDatabase.runVec(query.result) } def findByOracleEventTLV( - oracleEvent: OracleEventTLV): Future[Vector[EventDb]] = { + oracleEvent: OracleEventTLV + ): Future[Vector[EventDb]] = { val query = oracleEvent match { case v0: OracleEventV0TLV => table.filter(_.nonce.inSet(v0.nonces)) @@ -111,28 +115,34 @@ case class EventDAO()(implicit column("event_descriptor_tlv") def * : ProvenShape[EventDb] = - (nonce, - pubkey, - nonceIndex, - eventName, - numOutcomes, - signingVersion, - maturationTime, - attestationOpt, - outcomeOpt, - announcementSignature, - eventDescriptorTLV).<>(EventDb.tupled, EventDb.unapply) + ( + nonce, + pubkey, + nonceIndex, + eventName, + numOutcomes, + signingVersion, + maturationTime, + attestationOpt, + outcomeOpt, + announcementSignature, + eventDescriptorTLV + ).<>(EventDb.tupled, EventDb.unapply) def fk: ForeignKeyQuery[_, RValueDb] = { - foreignKey("fk_nonce", - sourceColumns = nonce, - targetTableQuery = rValueTable)(_.nonce) + foreignKey( + "fk_nonce", + sourceColumns = nonce, + targetTableQuery = rValueTable + )(_.nonce) } def fkLabel: ForeignKeyQuery[_, RValueDb] = { - foreignKey("fk_label", - sourceColumns = eventName, - targetTableQuery = rValueTable)(_.eventName) + foreignKey( + "fk_label", + sourceColumns = eventName, + targetTableQuery = rValueTable + )(_.eventName) } } } diff --git a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/EventOutcomeDAO.scala b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/EventOutcomeDAO.scala index d4ac10440d..cbdf4e7b73 100644 --- a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/EventOutcomeDAO.scala +++ b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/EventOutcomeDAO.scala @@ -11,8 +11,8 @@ import scala.concurrent.{ExecutionContext, Future} case class EventOutcomeDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCOracleAppConfig) - extends CRUD[EventOutcomeDb, (SchnorrNonce, String)] + override val appConfig: DLCOracleAppConfig +) extends CRUD[EventOutcomeDb, (SchnorrNonce, String)] with SlickUtil[EventOutcomeDb, (SchnorrNonce, String)] { import profile.api._ @@ -28,19 +28,20 @@ case class EventOutcomeDAO()(implicit EventDAO().table override def createAll( - ts: Vector[EventOutcomeDb]): Future[Vector[EventOutcomeDb]] = + ts: Vector[EventOutcomeDb] + ): Future[Vector[EventOutcomeDb]] = createAllNoAutoInc(ts, safeDatabase) - override protected def findByPrimaryKeys(ids: Vector[ - (SchnorrNonce, String)]): Query[EventOutcomeTable, EventOutcomeDb, Seq] = + override protected def findByPrimaryKeys( + ids: Vector[(SchnorrNonce, String)] + ): Query[EventOutcomeTable, EventOutcomeDb, Seq] = table .filter(_.nonce.inSet(ids.map(_._1))) .filter(_.message.inSet(ids.map(_._2))) - override protected def findAll(ts: Vector[EventOutcomeDb]): Query[ - EventOutcomeTable, - EventOutcomeDb, - Seq] = { + override protected def findAll( + ts: Vector[EventOutcomeDb] + ): Query[EventOutcomeTable, EventOutcomeDb, Seq] = { val ids = ts.map(t => (t.nonce, t.message)) findByPrimaryKeys(ids) } @@ -50,14 +51,16 @@ case class EventOutcomeDAO()(implicit } def findByNonces( - nonces: Vector[SchnorrNonce]): Future[Vector[EventOutcomeDb]] = { + nonces: Vector[SchnorrNonce] + ): Future[Vector[EventOutcomeDb]] = { val action = table.filter(_.nonce.inSet(nonces)).result safeDatabase.runVec(action) } def find( nonce: SchnorrNonce, - hash: ByteVector): Future[Option[EventOutcomeDb]] = { + hash: ByteVector + ): Future[Option[EventOutcomeDb]] = { val query = table.filter(item => item.nonce === nonce && item.hashedMessage === hash) @@ -74,13 +77,17 @@ case class EventOutcomeDAO()(implicit def hashedMessage: Rep[ByteVector] = column("hashed_message") def * : ProvenShape[EventOutcomeDb] = - (nonce, message, hashedMessage).<>(EventOutcomeDb.tupled, - EventOutcomeDb.unapply) + (nonce, message, hashedMessage).<>( + EventOutcomeDb.tupled, + EventOutcomeDb.unapply + ) def fk: ForeignKeyQuery[_, EventDb] = { - foreignKey("fk_nonce", - sourceColumns = nonce, - targetTableQuery = eventTable)(_.nonce) + foreignKey( + "fk_nonce", + sourceColumns = nonce, + targetTableQuery = eventTable + )(_.nonce) } } } diff --git a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/RValueDAO.scala b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/RValueDAO.scala index 2a43372e33..6a1bf8b04b 100644 --- a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/RValueDAO.scala +++ b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/storage/RValueDAO.scala @@ -11,8 +11,8 @@ import scala.concurrent.{ExecutionContext, Future} case class RValueDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCOracleAppConfig) - extends CRUD[RValueDb, SchnorrNonce] + override val appConfig: DLCOracleAppConfig +) extends CRUD[RValueDb, SchnorrNonce] with SlickUtil[RValueDb, SchnorrNonce] { import profile.api._ @@ -27,11 +27,13 @@ case class RValueDAO()(implicit createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - ids: Vector[SchnorrNonce]): Query[RValueTable, RValueDb, Seq] = + ids: Vector[SchnorrNonce] + ): Query[RValueTable, RValueDb, Seq] = table.filter(_.nonce.inSet(ids)) override protected def findAll( - ts: Vector[RValueDb]): Query[RValueTable, RValueDb, Seq] = + ts: Vector[RValueDb] + ): Query[RValueTable, RValueDb, Seq] = findByPrimaryKeys(ts.map(_.nonce)) def findByNonce(nonce: SchnorrNonce): Future[Option[RValueDb]] = { diff --git a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/util/EventDbUtil.scala b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/util/EventDbUtil.scala index 3f4f4a7dde..f7275099b0 100644 --- a/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/util/EventDbUtil.scala +++ b/dlc-oracle/src/main/scala/org/bitcoins/dlc/oracle/util/EventDbUtil.scala @@ -8,15 +8,16 @@ import org.bitcoins.core.protocol.dlc.compute.SigningVersion trait EventDbUtil { - /** Takes in a [[EventDescriptorTLV]] and nonces and creates [[EventOutcomeDb]] from them - * that can be inserted into the database. + /** Takes in a [[EventDescriptorTLV]] and nonces and creates + * [[EventOutcomeDb]] from them that can be inserted into the database. */ def toEventOutcomeDbs( descriptor: EventDescriptorTLV, nonces: Vector[ SchnorrNonce - ], //ugh, can we enforce some sort of invariant here? can i make this method private? - signingVersion: SigningVersion): Vector[EventOutcomeDb] = { + ], // ugh, can we enforce some sort of invariant here? can i make this method private? + signingVersion: SigningVersion + ): Vector[EventOutcomeDb] = { descriptor match { case enum: EnumEventDescriptorV0TLV => require(nonces.size == 1, "Enum events should only have one R value") @@ -32,8 +33,10 @@ trait EventDbUtil { case _: SignedDigitDecompositionEventDescriptor => val plusHash = signingVersion.calcOutcomeHash("+") val minusHash = signingVersion.calcOutcomeHash("-") - Vector(EventOutcomeDb(nonces.head, "+", plusHash), - EventOutcomeDb(nonces.head, "-", minusHash)) + Vector( + EventOutcomeDb(nonces.head, "+", plusHash), + EventOutcomeDb(nonces.head, "-", minusHash) + ) case _: UnsignedDigitDecompositionEventDescriptor => Vector.empty } @@ -59,22 +62,23 @@ trait EventDbUtil { def toEventOutcomeDbs( oracleAnnouncementV0TLV: OracleAnnouncementV0TLV, - signingVersion: SigningVersion = SigningVersion.latest): Vector[ - EventOutcomeDb] = { + signingVersion: SigningVersion = SigningVersion.latest + ): Vector[EventOutcomeDb] = { val oracleEventV0 = oracleAnnouncementV0TLV.eventTLV match { case v0: OracleEventV0TLV => v0 } - toEventOutcomeDbs(descriptor = - oracleAnnouncementV0TLV.eventTLV.eventDescriptor, - nonces = oracleEventV0.nonces, - signingVersion = signingVersion) + toEventOutcomeDbs( + descriptor = oracleAnnouncementV0TLV.eventTLV.eventDescriptor, + nonces = oracleEventV0.nonces, + signingVersion = signingVersion + ) } def toEventDbs( oracleAnnouncementV0TLV: OracleAnnouncementV0TLV, eventName: String, - signingVersion: SigningVersion = SigningVersion.latest): Vector[ - EventDb] = { + signingVersion: SigningVersion = SigningVersion.latest + ): Vector[EventDb] = { val nonces = oracleAnnouncementV0TLV.eventTLV.nonces.toVector nonces.zipWithIndex.map { case (nonce, index) => EventDb( diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/integration/DLCClientIntegrationTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/integration/DLCClientIntegrationTest.scala index 39ab72f7cd..4f9e455c78 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/integration/DLCClientIntegrationTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/integration/DLCClientIntegrationTest.scala @@ -50,16 +50,19 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { for { client <- clientF addressForMining <- addressForMiningF - _ <- BitcoindRpcTestUtil.waitUntilBlock(blockHeight, - client, - addressForMining) + _ <- BitcoindRpcTestUtil.waitUntilBlock( + blockHeight, + client, + addressForMining + ) } yield () } behavior of "AdaptorDLCClient" - def constructDLC(numOutcomes: Int): Future[ - (TestDLCClient, TestDLCClient, Vector[EnumOutcome])] = { + def constructDLC( + numOutcomes: Int + ): Future[(TestDLCClient, TestDLCClient, Vector[EnumOutcome])] = { def fundingInput(input: CurrencyUnit): Bitcoins = { Bitcoins((input + Satoshis(200)).satoshis) } @@ -86,7 +89,8 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { output.scriptPubKey match { case p2wpkh: P2WPKHWitnessSPKV0 => p2wpkh.pubKeyHash == P2WPKHWitnessSPKV0( - inputPubKeyOffer).pubKeyHash + inputPubKeyOffer + ).pubKeyHash case _ => false } } @@ -107,7 +111,8 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { output.scriptPubKey match { case p2wpkh: P2WPKHWitnessSPKV0 => p2wpkh.pubKeyHash == P2WPKHWitnessSPKV0( - inputPubKeyAccept).pubKeyHash + inputPubKeyAccept + ).pubKeyHash case _ => false } } @@ -118,7 +123,8 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { output.scriptPubKey match { case p2sh: P2SHScriptPubKey => p2sh.scriptHash == P2SHScriptPubKey( - P2WSHWitnessSPKV0(acceptNestedSPK)).scriptHash + P2WSHWitnessSPKV0(acceptNestedSPK) + ).scriptHash case _ => false } } @@ -130,12 +136,14 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { assert(remoteOutputIndex.isDefined) assert(remoteOutputIndex2.isDefined) - (tx, - localOutputIndex.get, - localOutputIndex2.get, - remoteOutputIndex.get, - remoteOutputIndex2.get, - signedTxResult.hex) + ( + tx, + localOutputIndex.get, + localOutputIndex2.get, + remoteOutputIndex.get, + remoteOutputIndex2.get, + signedTxResult.hex + ) } val localFundingUtxosF = fundedInputsTxidF.map { @@ -193,8 +201,10 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { SpendingInfoWithSerialId( ScriptSignatureParams( P2SHNestedSegwitV0InputInfo( - outPoint = TransactionOutPoint(prevTx.txIdBE, - UInt32(remoteOutputIndex2)), + outPoint = TransactionOutPoint( + prevTx.txIdBE, + UInt32(remoteOutputIndex2) + ), amount = tx.outputs(remoteOutputIndex2).value, scriptWitness = P2WSHWitnessV0(acceptNestedSPK), ConditionalPath.NoCondition @@ -274,7 +284,8 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { def validateOutcome( outcome: DLCOutcome, - builder: DLCTxBuilder): Future[Assertion] = { + builder: DLCTxBuilder + ): Future[Assertion] = { val fundingTx = outcome.fundingTx val closingTx = outcome match { case ExecutedDLCOutcome(_, cet, _, _) => cet @@ -286,10 +297,12 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { regtestFundingTx <- client.getRawTransaction(fundingTx.txIdBE) regtestClosingTx <- client.getRawTransaction(closingTx.txIdBE) } yield { - DLCFeeTestUtil.validateFees(builder, - fundingTx, - closingTx, - fundingTxSigs = 5) + DLCFeeTestUtil.validateFees( + builder, + fundingTx, + closingTx, + fundingTxSigs = 5 + ) assert(noEmptySPKOutputs(fundingTx)) assert(regtestFundingTx.hex == fundingTx) assert(regtestFundingTx.confirmations.isDefined) @@ -304,7 +317,8 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { def setupDLC( dlcOffer: TestDLCClient, - dlcAccept: TestDLCClient): Future[(SetupDLC, SetupDLC)] = { + dlcAccept: TestDLCClient + ): Future[(SetupDLC, SetupDLC)] = { val fundingTxF = { val fundingTxP = Promise[Transaction]() @@ -334,7 +348,8 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { val cancelOnFundingFound = system.scheduler.scheduleWithFixedDelay( initialDelay = 100.milliseconds, - delay = 1.second)(runnable = watchForFundingTx) + delay = 1.second + )(runnable = watchForFundingTx) fundingTxP.future.foreach(_ => cancelOnFundingFound.cancel()) @@ -345,7 +360,8 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { } def constructAndSetupDLC(numOutcomes: Int): Future[ - (TestDLCClient, SetupDLC, TestDLCClient, SetupDLC, Vector[EnumOutcome])] = { + (TestDLCClient, SetupDLC, TestDLCClient, SetupDLC, Vector[EnumOutcome]) + ] = { for { (offerDLC, acceptDLC, outcomes) <- constructDLC(numOutcomes) (offerSetup, acceptSetup) <- setupDLC(offerDLC, acceptDLC) @@ -355,14 +371,16 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { def executeForCase( outcomeIndex: Int, numOutcomes: Int, - local: Boolean): Future[Assertion] = { + local: Boolean + ): Future[Assertion] = { for { (offerDLC, offerSetup, acceptDLC, acceptSetup, outcomes) <- constructAndSetupDLC(numOutcomes) oracleSig = genEnumOracleSignature( offerDLC.offer.oracleInfos.head.asInstanceOf[EnumSingleOracleInfo], - outcomes(outcomeIndex).outcome) + outcomes(outcomeIndex).outcome + ) (unilateralDLC, unilateralSetup, otherDLC, otherSetup) = { if (local) { @@ -374,18 +392,23 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { unilateralOutcome <- unilateralDLC.executeDLC( unilateralSetup, - Future.successful(Vector(oracleSig))) + Future.successful(Vector(oracleSig)) + ) otherOutcome <- otherDLC.executeDLC(otherSetup, Future.successful(Vector(oracleSig))) _ <- recoverToSucceededIf[BitcoindException]( - publishTransaction(unilateralOutcome.cet)) + publishTransaction(unilateralOutcome.cet) + ) _ <- waitUntilBlock( - unilateralDLC.timeouts.contractMaturity.toUInt32.toInt - 1) + unilateralDLC.timeouts.contractMaturity.toUInt32.toInt - 1 + ) _ <- recoverToSucceededIf[BitcoindException]( - publishTransaction(unilateralOutcome.cet)) + publishTransaction(unilateralOutcome.cet) + ) _ <- waitUntilBlock( - unilateralDLC.timeouts.contractMaturity.toUInt32.toInt) + unilateralDLC.timeouts.contractMaturity.toUInt32.toInt + ) _ <- publishTransaction(unilateralOutcome.cet) _ <- validateOutcome(unilateralOutcome, offerDLC.dlcTxBuilder) } yield { @@ -397,7 +420,8 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { def executeForRefundCase(numOutcomes: Int): Future[Assertion] = { for { (offerDLC, offerSetup, acceptDLC, acceptSetup, _) <- constructAndSetupDLC( - numOutcomes) + numOutcomes + ) acceptOutcome = acceptDLC.executeRefundDLC(acceptSetup) offerOutcome = offerDLC.executeRefundDLC(offerSetup) @@ -430,7 +454,8 @@ class DLCClientIntegrationTest extends BitcoindRpcTest with DLCTest { def runTests( exec: (Int, Int, Boolean) => Future[Assertion], - local: Boolean): Future[Assertion] = { + local: Boolean + ): Future[Assertion] = { runTestsForParam(numOutcomesToTest) { numOutcomes => runTestsForParam(indicesToTest(numOutcomes)) { outcomeIndex => exec(outcomeIndex, numOutcomes, local) diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCDAOTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCDAOTest.scala index 50972b30d6..a4015d5ee3 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCDAOTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCDAOTest.scala @@ -35,10 +35,11 @@ class DLCDAOTest extends BitcoinSWalletTest with DLCDAOFixture { element: ElementType, key: KeyType, dao: CRUD[ElementType, KeyType], - dlcDAO: DLCDAO): Future[Assertion] = { + dlcDAO: DLCDAO + ): Future[Assertion] = { for { _ <- dlcDAO.create(dlcDb) - _ <- dao.upsert(element) //upsert in case we are testing the dlcDAO + _ <- dao.upsert(element) // upsert in case we are testing the dlcDAO read <- dao.read(key) } yield { @@ -160,10 +161,12 @@ class DLCDAOTest extends BitcoinSWalletTest with DLCDAOFixture { initiatorSig = None ) - verifyDatabaseInsertion(sig, - DLCCETSignaturesPrimaryKey(sig.dlcId, sig.index), - sigsDAO, - dlcDAO) + verifyDatabaseInsertion( + sig, + DLCCETSignaturesPrimaryKey(sig.dlcId, sig.index), + sigsDAO, + dlcDAO + ) } it should "correctly insert unsigned numeric outcome CET signatures into the database" in { @@ -179,10 +182,12 @@ class DLCDAOTest extends BitcoinSWalletTest with DLCDAOFixture { initiatorSig = None ) - verifyDatabaseInsertion(sig, - DLCCETSignaturesPrimaryKey(sig.dlcId, sig.index), - sigsDAO, - dlcDAO) + verifyDatabaseInsertion( + sig, + DLCCETSignaturesPrimaryKey(sig.dlcId, sig.index), + sigsDAO, + dlcDAO + ) } it should "correctly find CET signatures by dlcId" in { daos => @@ -237,15 +242,18 @@ class DLCDAOTest extends BitcoinSWalletTest with DLCDAOFixture { for { // no contact _ <- recoverToSucceededIf[SQLException]( - daos.dlcDAO.updateDLCContactMapping(dlcId, contact.address)) + daos.dlcDAO.updateDLCContactMapping(dlcId, contact.address) + ) _ <- daos.contactDAO.create(contact) // no dlc _ <- recoverToSucceededIf[SQLException]( - daos.dlcDAO.updateDLCContactMapping(dlcId, contact.address)) + daos.dlcDAO.updateDLCContactMapping(dlcId, contact.address) + ) _ <- recoverToSucceededIf[SQLException]( - daos.dlcDAO.deleteDLCContactMapping(dlcId)) + daos.dlcDAO.deleteDLCContactMapping(dlcId) + ) created <- daos.dlcDAO.create(dlcDb) @@ -269,7 +277,8 @@ class DLCDAOTest extends BitcoinSWalletTest with DLCDAOFixture { for { _ <- daos.dlcDAO.create(alphaDLCDb) foundOpt <- daos.dlcDAO.findByDLCSerializationVersion( - DLCSerializationVersion.Alpha) + DLCSerializationVersion.Alpha + ) } yield { assert(foundOpt.nonEmpty) } diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCExecutionBitcoindBackendTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCExecutionBitcoindBackendTest.scala index 17f7f113e8..eceb3d032e 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCExecutionBitcoindBackendTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCExecutionBitcoindBackendTest.scala @@ -22,10 +22,11 @@ class DLCExecutionBitcoindBackendTest override def withFixture(test: OneArgAsyncTest): FutureOutcome = { val outcomeF = for { bitcoind <- cachedBitcoindWithFundsF - outcome = withDualDLCWallets(test = test, - contractOraclePair = - DLCWalletUtil.sampleContractOraclePair, - bitcoind = bitcoind) + outcome = withDualDLCWallets( + test = test, + contractOraclePair = DLCWalletUtil.sampleContractOraclePair, + bitcoind = bitcoind + ) fut <- outcome.toFuture } yield fut @@ -54,7 +55,7 @@ class DLCExecutionBitcoindBackendTest bitcoind <- cachedBitcoindWithFundsF result <- bitcoind.getRawTransaction(broadcastB.fundingTxId) } yield { - //make sure no confirmations on the funding tx + // make sure no confirmations on the funding tx assert(result.confirmations.isEmpty) } @@ -71,11 +72,12 @@ class DLCExecutionBitcoindBackendTest DLCWalletUtil.getSigs(single) case disjoint: DisjointUnionContractInfo => sys.error( - s"Cannot retrieve sigs for disjoint union contract, got=$disjoint") + s"Cannot retrieve sigs for disjoint union contract, got=$disjoint" + ) } } closingTx <- dlcB.executeDLC(contractId, oracleSigs).map(_.get) - //broadcast the closing tx + // broadcast the closing tx _ <- dlcB.broadcastTransaction(closingTx) dlcs <- dlcB .listDLCs() @@ -85,9 +87,9 @@ class DLCExecutionBitcoindBackendTest _ = assert(dlc.state == DLCState.Claimed) claimed = dlc.asInstanceOf[DLCStatus.Claimed] - //make sure funding tx still doesn't have confs + // make sure funding tx still doesn't have confs fundingTxResult <- bitcoind.getRawTransaction(claimed.fundingTxId) - //make sure bitcoind sees it + // make sure bitcoind sees it closingTxResult <- bitcoind.getRawTransaction(claimed.closingTxId) } yield { assert(fundingTxResult.confirmations.isEmpty) diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCExecutionTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCExecutionTest.scala index c34680bb43..9012aad7fb 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCExecutionTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCExecutionTest.scala @@ -75,10 +75,14 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { assert(fundingTx.outputs.size == 3) assert( fundingTx.outputs.exists( - _.scriptPubKey == offer.changeAddress.scriptPubKey)) + _.scriptPubKey == offer.changeAddress.scriptPubKey + ) + ) assert( fundingTx.outputs.exists( - _.scriptPubKey == accept.changeAddress.scriptPubKey)) + _.scriptPubKey == accept.changeAddress.scriptPubKey + ) + ) assert(ScriptInterpreter.checkTransaction(fundingTx)) val fundingTxPrevOutputRefs = inputsA.map(_.toOutputReference) ++ inputsB @@ -86,7 +90,8 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { val prevOutputMap = PreviousOutputMap( - fundingTxPrevOutputRefs.map(ref => ref.outPoint -> ref.output).toMap) + fundingTxPrevOutputRefs.map(ref => ref.outPoint -> ref.output).toMap + ) val fundingTxVerify = fundingTx.inputs.zipWithIndex.forall { case (input, index) => @@ -110,16 +115,19 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { DLCWalletUtil.getSigs(single) case disjoint: DisjointUnionContractInfo => sys.error( - s"Cannot retrieve sigs for disjoint union contract, got=$disjoint") + s"Cannot retrieve sigs for disjoint union contract, got=$disjoint" + ) } } func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = true, + func = func, + expectedOutputs = 1 + ) _ = assert(result) dlcDbAOpt <- wallets._1.wallet.dlcDAO.findByContractId(contractId) @@ -156,16 +164,19 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { DLCWalletUtil.getSigs(single) case disjoint: DisjointUnionContractInfo => sys.error( - s"Cannot retrieve sigs for disjoint union contract, got=$disjoint") + s"Cannot retrieve sigs for disjoint union contract, got=$disjoint" + ) } } func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = false, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = false, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -206,7 +217,8 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { DLCWalletUtil.getSigs(single) case disjoint: DisjointUnionContractInfo => sys.error( - s"Cannot retrieve sigs for disjoint union contract, got=$disjoint") + s"Cannot retrieve sigs for disjoint union contract, got=$disjoint" + ) } } @@ -228,17 +240,20 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { DLCWalletUtil.getSigs(single) case disjoint: DisjointUnionContractInfo => sys.error( - s"Cannot retrieve sigs for disjoint union contract, got=$disjoint") + s"Cannot retrieve sigs for disjoint union contract, got=$disjoint" + ) } } func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = true, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -274,10 +289,12 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { status <- getDLCStatus(wallets._1.wallet) func = (wallet: DLCWallet) => wallet.executeDLCRefund(contractId) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = true, - func = func, - expectedOutputs = 2) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = true, + func = func, + expectedOutputs = 2 + ) _ = assert(result) @@ -312,10 +329,12 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { status <- getDLCStatus(wallets._1.wallet) func = (wallet: DLCWallet) => wallet.executeDLCRefund(contractId) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = false, - func = func, - expectedOutputs = 2) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = false, + func = func, + expectedOutputs = 2 + ) _ = assert(result) @@ -357,18 +376,19 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { } it must "create 2 offers with the same contract info" in { wallets => - //test for: https://github.com/bitcoin-s/bitcoin-s/issues/3127 + // test for: https://github.com/bitcoin-s/bitcoin-s/issues/3127 val walletA = wallets._1.wallet - //https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/12fb3e5f091086329ed0d2a12c3fcfa80111a36ef3fc1ac9c2567076a57d6a73 + // https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/12fb3e5f091086329ed0d2a12c3fcfa80111a36ef3fc1ac9c2567076a57d6a73 val contractInfo = ContractInfoV0TLV.fromHex( - "fdd82eeb00000000000186a0fda71026030359455300000000000186a0024e4f0000000000000000056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342") + "fdd82eeb00000000000186a0fda71026030359455300000000000186a0024e4f0000000000000000056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342" + ) val announcement = contractInfo.oracleInfo.asInstanceOf[OracleInfoV0TLV].announcement val feeRateOpt = Some(SatoshisPerVirtualByte(Satoshis.one)) val totalCollateral = Satoshis(50000) - //helper method to make an offer + // helper method to make an offer def makeOffer(): Future[DLCOffer] = { walletA.createDLCOffer( contractInfoTLV = contractInfo, @@ -382,19 +402,25 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { ) } - //simply try to make 2 offers with the same contract info - //if this works, we are good + // simply try to make 2 offers with the same contract info + // if this works, we are good for { _ <- makeOffer() announcementVec1 <- walletA.announcementDAO.findByAnnouncementSignatures( - Vector(announcement.announcementSignature)) - _ = assert(announcementVec1.length == 1, - s"Got length=${announcementVec1.length}") + Vector(announcement.announcementSignature) + ) + _ = assert( + announcementVec1.length == 1, + s"Got length=${announcementVec1.length}" + ) _ <- makeOffer() announcementVec2 <- walletA.announcementDAO.findByAnnouncementSignatures( - Vector(announcement.announcementSignature)) - _ = assert(announcementVec2.length == 1, - s"Got length=${announcementVec2.length}") + Vector(announcement.announcementSignature) + ) + _ = assert( + announcementVec2.length == 1, + s"Got length=${announcementVec2.length}" + ) } yield succeed } @@ -412,26 +438,31 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { DLCWalletUtil.getSigs(single) case disjoint: DisjointUnionContractInfo => sys.error( - s"Cannot retrieve sigs for disjoint union contract, got=$disjoint") + s"Cannot retrieve sigs for disjoint union contract, got=$disjoint" + ) } } func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = true, + func = func, + expectedOutputs = 1 + ) _ = assert(result) - _ <- walletA.createDLCOffer(status.contractInfo, - status.localCollateral.satoshis, - None, - UInt32.zero, - UInt32.one, - None, - None, - None) + _ <- walletA.createDLCOffer( + status.contractInfo, + status.localCollateral.satoshis, + None, + UInt32.zero, + UInt32.one, + None, + None, + None + ) _ <- walletA.listDLCs() } yield succeed @@ -449,27 +480,30 @@ class DLCExecutionTest extends BitcoinSDualWalletTest { DLCWalletUtil.getSigs(single) case disjoint: DisjointUnionContractInfo => sys.error( - s"Cannot retrieve sigs for disjoint union contract, got=$disjoint") + s"Cannot retrieve sigs for disjoint union contract, got=$disjoint" + ) } } - //purposefully drop these - //we cannot drop just a sig, or just an outcome because - //of invariants in OracleAttestmentV0TLV + // purposefully drop these + // we cannot drop just a sig, or just an outcome because + // of invariants in OracleAttestmentV0TLV badSigs = goodAttestment.sigs.dropRight(1) badOutcomes = goodAttestment.outcomes.dropRight(1) - badAttestment = OracleAttestmentV0TLV(eventId = goodAttestment.eventId, - publicKey = - goodAttestment.publicKey, - unsortedSignatures = - badSigs.toVector, - outcomes = badOutcomes) + badAttestment = OracleAttestmentV0TLV( + eventId = goodAttestment.eventId, + publicKey = goodAttestment.publicKey, + unsortedSignatures = badSigs.toVector, + outcomes = badOutcomes + ) func = (wallet: DLCWallet) => wallet.executeDLC(contractId, badAttestment).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = true, + func = func, + expectedOutputs = 1 + ) } yield assert(result) recoverToSucceededIf[IllegalArgumentException](resultF) diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleEnumExecutionTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleEnumExecutionTest.scala index 9cce733eac..f32c5ebea0 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleEnumExecutionTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleEnumExecutionTest.scala @@ -36,9 +36,11 @@ class DLCMultiOracleEnumExecutionTest extends BitcoinSDualWalletTest { val announcements: Vector[OracleAnnouncementTLV] = privateKeys.zip(kValues).map { case (priv, kValue) => OracleAnnouncementV0TLV - .dummyForEventsAndKeys(priv, - kValue.schnorrNonce, - outcomes.map(EnumOutcome)) + .dummyForEventsAndKeys( + priv, + kValue.schnorrNonce, + outcomes.map(EnumOutcome) + ) } val threshold = 3 @@ -78,10 +80,12 @@ class DLCMultiOracleEnumExecutionTest extends BitcoinSDualWalletTest { val hash = CryptoUtil.sha256DLCAttestation(initiatorWinStr).bytes val initiatorWinSig = priv.schnorrSignWithNonce(hash, kValue) - OracleAttestmentV0TLV(eventId, - priv.schnorrPublicKey, - OrderedSchnorrSignatures(initiatorWinSig).toVector, - Vector(initiatorWinStr)) + OracleAttestmentV0TLV( + eventId, + priv.schnorrPublicKey, + OrderedSchnorrSignatures(initiatorWinSig).toVector, + Vector(initiatorWinStr) + ) } val recipientWinSigs = privateKeys.zip(kValues).map { case (priv, kValue) => @@ -99,15 +103,19 @@ class DLCMultiOracleEnumExecutionTest extends BitcoinSDualWalletTest { val hash = CryptoUtil.sha256DLCAttestation(recipientWinStr).bytes val recipientWinSig = priv.schnorrSignWithNonce(hash, kValue) - OracleAttestmentV0TLV(eventId, - priv.schnorrPublicKey, - OrderedSchnorrSignatures(recipientWinSig).toVector, - Vector(recipientWinStr)) + OracleAttestmentV0TLV( + eventId, + priv.schnorrPublicKey, + OrderedSchnorrSignatures(recipientWinSig).toVector, + Vector(recipientWinStr) + ) } // Shuffle to make sure ordering doesn't matter - (Random.shuffle(initiatorWinSigs).take(sigsToTake), - Random.shuffle(recipientWinSigs).take(sigsToTake)) + ( + Random.shuffle(initiatorWinSigs).take(sigsToTake), + Random.shuffle(recipientWinSigs).take(sigsToTake) + ) } it must "execute as the initiator" in { wallets => @@ -118,10 +126,12 @@ class DLCMultiOracleEnumExecutionTest extends BitcoinSDualWalletTest { func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = true, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -158,10 +168,12 @@ class DLCMultiOracleEnumExecutionTest extends BitcoinSDualWalletTest { func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = false, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = false, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -192,7 +204,8 @@ class DLCMultiOracleEnumExecutionTest extends BitcoinSDualWalletTest { private def verifyingMatchingOracleSigs( statusA: Claimed, - statusB: RemoteClaimed): Boolean = { + statusB: RemoteClaimed + ): Boolean = { val aggR = statusA.oracleSigs .map(_.rx.publicKey) .reduce(_.add(_)) diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleExactNumericExecutionTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleExactNumericExecutionTest.scala index 5366c8293e..cac708dd06 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleExactNumericExecutionTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleExactNumericExecutionTest.scala @@ -62,9 +62,9 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest { withDualDLCWallets(test, contractOraclePair) } - def getSigs(contractInfo: ContractInfo): ( - Vector[OracleAttestmentTLV], - Vector[OracleAttestmentTLV]) = { + def getSigs( + contractInfo: ContractInfo + ): (Vector[OracleAttestmentTLV], Vector[OracleAttestmentTLV]) = { contractInfo.contractDescriptors.head match { case _: NumericContractDescriptor => () case _: EnumContractDescriptor => @@ -89,7 +89,8 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest { initChosenOracles, contractInfo, initiatorWinVec, - None) + None + ) val initiatorWinSigs = buildAttestments(initWinOutcomes) val recipientChosenOracles = @@ -109,7 +110,8 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest { recipientChosenOracles, contractInfo, recipientWinVec, - None) + None + ) val recipientWinSigs = buildAttestments(recipientWinOutcomes) @@ -125,10 +127,12 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest { func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sigs).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = true, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -165,10 +169,12 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest { func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sigs).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = false, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = false, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -199,7 +205,8 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest { private def verifyingMatchingOracleSigs( statusA: Claimed, - statusB: RemoteClaimed): Boolean = { + statusB: RemoteClaimed + ): Boolean = { val outcome = statusB.oracleOutcome outcome match { case _: EnumOracleOutcome => @@ -225,7 +232,8 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest { /** Builds an attestment for the given numeric oracle outcome */ private def buildAttestments( - outcome: NumericOracleOutcome): Vector[OracleAttestmentTLV] = { + outcome: NumericOracleOutcome + ): Vector[OracleAttestmentTLV] = { privateKeys.zip(kValues).flatMap { case (priv, kValues) => val outcomeOpt = outcome.oraclesAndOutcomes.find(_._1.publicKey == priv.schnorrPublicKey) @@ -241,13 +249,16 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest { case v0: OracleEventV0TLV => v0.eventId } - require(kValues.length == sigs.length, - s"kValues.length=${kValues.length} sigs.length=${sigs.length}") + require( + kValues.length == sigs.length, + s"kValues.length=${kValues.length} sigs.length=${sigs.length}" + ) OracleAttestmentV0TLV( eventId, priv.schnorrPublicKey, OrderedSchnorrSignatures.fromUnsorted(sigs).toVector, - digitsPadded.map(_.toString)) + digitsPadded.map(_.toString) + ) } } } diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleNumericExecutionTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleNumericExecutionTest.scala index b8d086a738..ee0a530d57 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleNumericExecutionTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCMultiOracleNumericExecutionTest.scala @@ -59,9 +59,11 @@ class DLCMultiOracleNumericExecutionTest OracleParamsV0TLV(maxErrorExp = 4, minFailExp = 2, maximizeCoverage = false) val oracleInfo: NumericMultiOracleInfo = - NumericMultiOracleInfo(threshold = threshold, - announcements = OrderedAnnouncements(announcements), - params = params) + NumericMultiOracleInfo( + threshold = threshold, + announcements = OrderedAnnouncements(announcements), + params = params + ) val contractOraclePair: ContractOraclePair.NumericPair = ContractOraclePair.NumericPair(contractDescriptor, oracleInfo) @@ -70,9 +72,9 @@ class DLCMultiOracleNumericExecutionTest withDualDLCWallets(test, contractOraclePair) } - def getSigs(contractInfo: ContractInfo): ( - Vector[OracleAttestmentTLV], - Vector[OracleAttestmentTLV]) = { + def getSigs( + contractInfo: ContractInfo + ): (Vector[OracleAttestmentTLV], Vector[OracleAttestmentTLV]) = { contractInfo.contractDescriptors.head match { case _: NumericContractDescriptor => () case _: EnumContractDescriptor => @@ -97,7 +99,8 @@ class DLCMultiOracleNumericExecutionTest initChosenOracles, contractInfo, initiatorWinVec, - Some(params)) + Some(params) + ) val initiatorWinSigs = buildAttestments(initWinOutcomes) @@ -118,10 +121,12 @@ class DLCMultiOracleNumericExecutionTest recipientChosenOracles, contractInfo, recipientWinVec, - Some(params)) + Some(params) + ) val recipientWinSigs: Vector[OracleAttestmentTLV] = buildAttestments( - recipientWinOutcomes) + recipientWinOutcomes + ) // Shuffle to make sure ordering doesn't matter (Random.shuffle(initiatorWinSigs), Random.shuffle(recipientWinSigs)) @@ -135,10 +140,12 @@ class DLCMultiOracleNumericExecutionTest func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sigs).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = true, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -175,10 +182,12 @@ class DLCMultiOracleNumericExecutionTest func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sigs).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = false, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = false, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -209,7 +218,8 @@ class DLCMultiOracleNumericExecutionTest private def verifyingMatchingOracleSigs( statusA: Claimed, - statusB: RemoteClaimed): Boolean = { + statusB: RemoteClaimed + ): Boolean = { val outcome = statusB.oracleOutcome outcome match { case _: EnumOracleOutcome => @@ -235,7 +245,8 @@ class DLCMultiOracleNumericExecutionTest /** Builds an attestment for the given numeric oracle outcome */ private def buildAttestments( - outcome: NumericOracleOutcome): Vector[OracleAttestmentTLV] = { + outcome: NumericOracleOutcome + ): Vector[OracleAttestmentTLV] = { privateKeys.zip(kValues).flatMap { case (priv, kValues) => val outcomeOpt = outcome.oraclesAndOutcomes.find(_._1.publicKey == priv.schnorrPublicKey) @@ -251,13 +262,16 @@ class DLCMultiOracleNumericExecutionTest case v0: OracleEventV0TLV => v0.eventId } - require(kValues.length == sigs.length, - s"kValues.length=${kValues.length} sigs.length=${sigs.length}") + require( + kValues.length == sigs.length, + s"kValues.length=${kValues.length} sigs.length=${sigs.length}" + ) OracleAttestmentV0TLV( eventId, priv.schnorrPublicKey, OrderedSchnorrSignatures.fromUnsorted(sigs).toVector, - digitsPadded.map(_.toString)) + digitsPadded.map(_.toString) + ) } } } diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCNumericExecutionTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCNumericExecutionTest.scala index 656e192653..8a0cd88f79 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCNumericExecutionTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCNumericExecutionTest.scala @@ -19,9 +19,9 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest { behavior of "DLCWallet" - def getSigs(contractInfo: ContractInfo): ( - OracleAttestmentTLV, - OracleAttestmentTLV) = { + def getSigs( + contractInfo: ContractInfo + ): (OracleAttestmentTLV, OracleAttestmentTLV) = { contractInfo.contractDescriptors.head match { case _: NumericContractDescriptor => () case _: EnumContractDescriptor => @@ -45,10 +45,12 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest { val initiatorWinSigs = initiatorWinVec.zip(kValues).map { case (num, kValue) => DLCWalletUtil.oraclePrivKey - .schnorrSignWithNonce(CryptoUtil - .sha256DLCAttestation(num.toString) - .bytes, - kValue) + .schnorrSignWithNonce( + CryptoUtil + .sha256DLCAttestation(num.toString) + .bytes, + kValue + ) } val recipientWinVec = @@ -66,10 +68,12 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest { val recipientWinSigs = recipientWinVec.zip(kValues2).map { case (num, kValue) => DLCWalletUtil.oraclePrivKey - .schnorrSignWithNonce(CryptoUtil - .sha256DLCAttestation(num.toString) - .bytes, - kValue) + .schnorrSignWithNonce( + CryptoUtil + .sha256DLCAttestation(num.toString) + .bytes, + kValue + ) } val publicKey = DLCWalletUtil.oraclePrivKey.schnorrPublicKey @@ -77,14 +81,20 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest { case v0: OracleEventV0TLV => v0.eventId } - (OracleAttestmentV0TLV(eventId, - publicKey, - OrderedSchnorrSignatures(initiatorWinSigs).toVector, - initiatorWinVec.map(_.toString)), - OracleAttestmentV0TLV(eventId, - publicKey, - OrderedSchnorrSignatures(recipientWinSigs).toVector, - recipientWinVec.map(_.toString))) + ( + OracleAttestmentV0TLV( + eventId, + publicKey, + OrderedSchnorrSignatures(initiatorWinSigs).toVector, + initiatorWinVec.map(_.toString) + ), + OracleAttestmentV0TLV( + eventId, + publicKey, + OrderedSchnorrSignatures(recipientWinSigs).toVector, + recipientWinVec.map(_.toString) + ) + ) } it must "execute as the initiator" in { wallets => @@ -95,10 +105,12 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest { func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sigs).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = true, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -135,10 +147,12 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest { func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sigs).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = false, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = false, + func = func, + expectedOutputs = 1 + ) _ = assert(result) @@ -173,25 +187,28 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest { contractId <- getContractId(wallets._1.wallet) status <- getDLCStatus(wallets._2.wallet) (_, goodAttestment) = getSigs(status.contractInfo) - //purposefully drop these - //we cannot drop just a sig, or just an outcome because - //of invariants in OracleAttestmentV0TLV + // purposefully drop these + // we cannot drop just a sig, or just an outcome because + // of invariants in OracleAttestmentV0TLV badSigs = OrderedSchnorrSignatures.fromUnsorted( - goodAttestment.sigs.dropRight(1).toVector) + goodAttestment.sigs.dropRight(1).toVector + ) badOutcomes = goodAttestment.outcomes.dropRight(1) - badAttestment = OracleAttestmentV0TLV(eventId = goodAttestment.eventId, - publicKey = - goodAttestment.publicKey, - unsortedSignatures = - badSigs.toVector, - outcomes = badOutcomes) + badAttestment = OracleAttestmentV0TLV( + eventId = goodAttestment.eventId, + publicKey = goodAttestment.publicKey, + unsortedSignatures = badSigs.toVector, + outcomes = badOutcomes + ) func = (wallet: DLCWallet) => wallet.executeDLC(contractId, badAttestment).map(_.get) - result <- dlcExecutionTest(wallets = wallets, - asInitiator = false, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = wallets, + asInitiator = false, + func = func, + expectedOutputs = 1 + ) } yield assert(result) recoverToSucceededIf[IllegalArgumentException](resultF) @@ -199,7 +216,8 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest { private def verifyingMatchingOracleSigs( statusA: Claimed, - statusB: RemoteClaimed): Boolean = { + statusB: RemoteClaimed + ): Boolean = { val outcome = statusB.oracleOutcome outcome match { case _: EnumOracleOutcome => diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCWalletCallbackTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCWalletCallbackTest.scala index e1f2c1b60a..e93efa247d 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCWalletCallbackTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/DLCWalletCallbackTest.scala @@ -50,7 +50,7 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { case DLCState.Claimed => Future.successful(claimedP.success(status)) case DLCState.Broadcasted => - //ignore broadcast from this wallet + // ignore broadcast from this wallet Future.unit case x @ (DLCState.Accepted | DLCState.AcceptComputingAdaptorSigs | DLCState.RemoteClaimed | DLCState.Refunded) => @@ -73,7 +73,7 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { DLCState.SignComputingAdaptorSigs) => sys.error(s"Shouldn't receive state=$x for callback") case DLCState.Confirmed | DLCState.Claimed | DLCState.Refunded => - //do nothing, we are doing assertions for these on walletACallback + // do nothing, we are doing assertions for these on walletACallback Future.unit } } @@ -85,18 +85,21 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { walletA.dlcConfig.addCallbacks(walletACallbacks) walletB.dlcConfig.addCallbacks(walletBCallbacks) - //run init DLC and make sure we get the callback hit + // run init DLC and make sure we get the callback hit - val initF = DLCWalletUtil.initDLC(wallets._1, - wallets._2, - DLCWalletUtil.sampleContractInfo) + val initF = DLCWalletUtil.initDLC( + wallets._1, + wallets._2, + DLCWalletUtil.sampleContractInfo + ) def executeF = for { _ <- initF contractId <- DLCWalletUtil.getContractId(wallets._1.wallet) fundingTx <- walletA.getDLCFundingTx(contractId) _ <- walletA.processTransaction( transaction = fundingTx, - blockHashOpt = Some(CryptoGenerators.doubleSha256DigestBE.sample.get)) + blockHashOpt = Some(CryptoGenerators.doubleSha256DigestBE.sample.get) + ) sigs = { DLCWalletUtil.sampleContractInfo match { case single: SingleContractInfo => @@ -122,10 +125,12 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { } yield { assert(offer.state == DLCState.Offered) assert( - acceptedComputingAdaptorSigs.state == DLCState.AcceptComputingAdaptorSigs) + acceptedComputingAdaptorSigs.state == DLCState.AcceptComputingAdaptorSigs + ) assert(accept.state == DLCState.Accepted) assert( - signComputingAdaptorSigs.state == DLCState.SignComputingAdaptorSigs) + signComputingAdaptorSigs.state == DLCState.SignComputingAdaptorSigs + ) assert(sign.state == DLCState.Signed) assert(broadcast.state == DLCState.Broadcasted) assert(confirmed.state == DLCState.Confirmed) @@ -154,7 +159,7 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { case DLCState.Signed => Future.successful(signedP.success(status)) case DLCState.Broadcasted | DLCState.Confirmed => - //ignore them from this wallet + // ignore them from this wallet Future.unit case DLCState.Refunded => Future.successful(refundedP.success(status)) @@ -177,7 +182,7 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { DLCState.SignComputingAdaptorSigs | DLCState.Signed) => sys.error(s"Shouldn't receive state=$x for callback") case DLCState.Confirmed | DLCState.Claimed | DLCState.RemoteClaimed => - //do nothing, we are doing assertions for these on walletACallback + // do nothing, we are doing assertions for these on walletACallback Future.unit } @@ -190,11 +195,13 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { walletA.dlcConfig.addCallbacks(walletACallbacks) walletB.dlcConfig.addCallbacks(walletBCallbacks) - //run init DLC and make sure we get the callback hit + // run init DLC and make sure we get the callback hit - val initF = DLCWalletUtil.initDLC(wallets._1, - wallets._2, - DLCWalletUtil.sampleContractInfo) + val initF = DLCWalletUtil.initDLC( + wallets._1, + wallets._2, + DLCWalletUtil.sampleContractInfo + ) def refundF = for { _ <- initF @@ -202,7 +209,8 @@ class DLCWalletCallbackTest extends BitcoinSDualWalletTest { fundingTx <- walletA.getDLCFundingTx(contractId) _ <- walletA.processTransaction( transaction = fundingTx, - blockHashOpt = Some(CryptoGenerators.doubleSha256DigestBE.sample.get)) + blockHashOpt = Some(CryptoGenerators.doubleSha256DigestBE.sample.get) + ) transaction <- walletA.executeDLCRefund(contractId) _ <- walletB.processTransaction(transaction, None) } yield () diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/IncomingDLCOfferDAOTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/IncomingDLCOfferDAOTest.scala index 5d018f5d36..21052db7be 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/IncomingDLCOfferDAOTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/IncomingDLCOfferDAOTest.scala @@ -12,11 +12,12 @@ class IncomingDLCOfferDAOTest extends BitcoinSWalletTest with DLCDAOFixture { it should "write and read incoming offers" in { daos => val expected = - IncomingDLCOfferDbHelper.fromTLV(offerTLV = - DLCWalletUtil.sampleDLCOffer.toTLV, - message = Some("msg"), - peer = Some("peer"), - receivedAt = Instant.ofEpochSecond(0)) + IncomingDLCOfferDbHelper.fromTLV( + offerTLV = DLCWalletUtil.sampleDLCOffer.toTLV, + message = Some("msg"), + peer = Some("peer"), + receivedAt = Instant.ofEpochSecond(0) + ) for { _ <- daos.incomingDLCOfferDAO.create(expected) @@ -29,16 +30,18 @@ class IncomingDLCOfferDAOTest extends BitcoinSWalletTest with DLCDAOFixture { it should "select incoming offers in reverse chronological order" in { daos => val offer1 = - IncomingDLCOfferDbHelper.fromTLV(offerTLV = - DLCWalletUtil.sampleDLCOffer.toTLV, - message = Some("msg"), - peer = Some("peer"), - receivedAt = Instant.ofEpochSecond(0)) + IncomingDLCOfferDbHelper.fromTLV( + offerTLV = DLCWalletUtil.sampleDLCOffer.toTLV, + message = Some("msg"), + peer = Some("peer"), + receivedAt = Instant.ofEpochSecond(0) + ) val offer2 = IncomingDLCOfferDbHelper.fromTLV( offerTLV = DLCWalletUtil.sampleMultiNonceDLCOffer.toTLV, message = Some("msg"), peer = Some("peer"), - receivedAt = Instant.ofEpochSecond(1)) + receivedAt = Instant.ofEpochSecond(1) + ) val offers = Vector(offer1, offer2) for { diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/MultiWalletDLCTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/MultiWalletDLCTest.scala index b7eec49ff5..feb9126e0f 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/MultiWalletDLCTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/MultiWalletDLCTest.scala @@ -41,7 +41,8 @@ class MultiWalletDLCTest extends BitcoinSWalletTest { val walletBF = BitcoinSWalletTest.createDLCWallet2Accounts( MockNodeApi, - MockChainQueryApi)(configB, system) + MockChainQueryApi + )(configB, system) for { accountA <- walletA.getDefaultAccount() @@ -51,14 +52,16 @@ class MultiWalletDLCTest extends BitcoinSWalletTest { _ = assert(accountA.xpub != accountB.xpub) - _ <- walletA.createDLCOffer(sampleContractInfo, - half, - Some(SatoshisPerVirtualByte.one), - UInt32.zero, - UInt32.one, - None, - None, - None) + _ <- walletA.createDLCOffer( + sampleContractInfo, + half, + Some(SatoshisPerVirtualByte.one), + UInt32.zero, + UInt32.one, + None, + None, + None + ) dlcsA <- walletA.listDLCs() dlcsB <- walletB.listDLCs() @@ -73,7 +76,7 @@ class MultiWalletDLCTest extends BitcoinSWalletTest { it must "create an offer, out of band unreserve the utxo, and then cancel the offer" in { fundedWallet: FundedDLCWallet => - //see: https://github.com/bitcoin-s/bitcoin-s/issues/3813#issue-1051117559 + // see: https://github.com/bitcoin-s/bitcoin-s/issues/3813#issue-1051117559 val wallet = fundedWallet.wallet val offerF = wallet.createDLCOffer( contractInfo = sampleContractInfo, @@ -86,14 +89,14 @@ class MultiWalletDLCTest extends BitcoinSWalletTest { externalChangeAddressOpt = None ) - //now unreserve the utxo + // now unreserve the utxo val reservedUtxoF = for { _ <- offerF utxos <- wallet.listUtxos(TxoState.Reserved) _ <- wallet.unmarkUTXOsAsReserved(utxos) } yield () - //now cancel the offer + // now cancel the offer for { offer <- offerF _ <- reservedUtxoF diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/RescanDLCTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/RescanDLCTest.scala index bea6631c03..3864f731c8 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/RescanDLCTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/RescanDLCTest.scala @@ -37,26 +37,31 @@ class RescanDLCTest extends DualWalletTestCachedBitcoind { DLCWalletUtil.getSigs(single) case disjoint: DisjointUnionContractInfo => sys.error( - s"Cannot retrieve sigs for disjoint union contract, got=$disjoint") + s"Cannot retrieve sigs for disjoint union contract, got=$disjoint" + ) } } func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig).map(_.get) - result <- dlcExecutionTest(wallets = (walletA, walletB), - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = (walletA, walletB), + asInitiator = true, + func = func, + expectedOutputs = 1 + ) _ = assert(result) Vector(hash) <- bitcoind.generate(1) - _ <- wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = Some(BlockHash(hash)), - addressBatchSize = 20, - useCreationTime = false, - force = false) + _ <- wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = Some(BlockHash(hash)), + addressBatchSize = 20, + useCreationTime = false, + force = false + ) postStatus <- getDLCStatus(wallet) } yield assert(postStatus.state == DLCState.Claimed) @@ -77,26 +82,31 @@ class RescanDLCTest extends DualWalletTestCachedBitcoind { DLCWalletUtil.getSigs(single) case disjoint: DisjointUnionContractInfo => sys.error( - s"Cannot retrieve sigs for disjoint union contract, got=$disjoint") + s"Cannot retrieve sigs for disjoint union contract, got=$disjoint" + ) } } func = (wallet: DLCWallet) => wallet.executeDLC(contractId, sig).map(_.get) - result <- dlcExecutionTest(wallets = (walletA, walletB), - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + wallets = (walletA, walletB), + asInitiator = true, + func = func, + expectedOutputs = 1 + ) _ = assert(result) Vector(hash) <- bitcoind.generate(1) - _ <- wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = Some(BlockHash(hash)), - addressBatchSize = 20, - useCreationTime = false, - force = false) + _ <- wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = Some(BlockHash(hash)), + addressBatchSize = 20, + useCreationTime = false, + force = false + ) postStatus <- getDLCStatus(wallet) } yield assert(postStatus.state == DLCState.RemoteClaimed) diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/WalletDLCSetupTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/WalletDLCSetupTest.scala index 651069f4fc..b49ac3100e 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/WalletDLCSetupTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/WalletDLCSetupTest.scala @@ -35,7 +35,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { def testNegotiate( fundedDLCWallets: (FundedDLCWallet, FundedDLCWallet), - offerData: DLCOffer): Future[Assertion] = { + offerData: DLCOffer + ): Future[Assertion] = { val walletA = fundedDLCWallets._1.wallet val walletB = fundedDLCWallets._2.wallet val walletADLCManagement = DLCDataManagement(walletA.dlcWalletDAOs) @@ -75,9 +76,11 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { assert( accept.fundingInputs .map(_.output.value) - .sum >= accept.collateral) + .sum >= accept.collateral + ) assert( - accept.collateral == offer.contractInfo.totalCollateral - offer.collateral) + accept.collateral == offer.contractInfo.totalCollateral - offer.collateral + ) assert(accept.changeAddress.value.nonEmpty) } @@ -107,14 +110,16 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { announcementTLVsA = walletADLCManagement.getOracleAnnouncements( announcementsA, announcementDataA, - nonceDbsA) + nonceDbsA + ) (announcementsB, announcementDataB, nonceDbsB) <- walletBDLCManagement .getDLCAnnouncementDbs(dlcDb.dlcId) announcementTLVsB = walletBDLCManagement.getOracleAnnouncements( announcementsB, announcementDataB, - nonceDbsB) + nonceDbsB + ) } yield { assert(dlcDb.contractIdOpt.get == sign.contractId) @@ -146,8 +151,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { it must "correctly negotiate a non winner take all dlc" in { fundedDLCWallets: (FundedDLCWallet, FundedDLCWallet) => - testNegotiate(fundedDLCWallets, - DLCWalletUtil.sampleDLCOfferNonWinnerTakeAll) + testNegotiate( + fundedDLCWallets, + DLCWalletUtil.sampleDLCOfferNonWinnerTakeAll + ) } it must "correctly negotiate a dlc with a multi-nonce oracle info" in { @@ -164,25 +171,32 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { val col = totalCol / Satoshis.two val outcomes: Vector[(EnumOutcome, Satoshis)] = - Vector(EnumOutcome(winStr) -> totalCol, - EnumOutcome(loseStr) -> Satoshis.zero) + Vector( + EnumOutcome(winStr) -> totalCol, + EnumOutcome(loseStr) -> Satoshis.zero + ) val oraclePair: ContractOraclePair.EnumPair = - ContractOraclePair.EnumPair(EnumContractDescriptor(outcomes), - sampleOracleInfo) + ContractOraclePair.EnumPair( + EnumContractDescriptor(outcomes), + sampleOracleInfo + ) val contractInfo: ContractInfo = SingleContractInfo(totalCol, oraclePair) val offerData = - sampleDLCOffer.copy(contractInfo = contractInfo, - collateral = col.satoshis) + sampleDLCOffer.copy( + contractInfo = contractInfo, + collateral = col.satoshis + ) val walletA = fundedDLCWallets._1.wallet val walletB = fundedDLCWallets._2.wallet def reorderInputDbs( wallet: DLCWallet, - dlcId: Sha256Digest): Future[Unit] = { + dlcId: Sha256Digest + ): Future[Unit] = { for { inputDbs <- wallet.dlcInputsDAO.findByDLCId(dlcId) _ <- wallet.dlcInputsDAO.deleteByDLCId(dlcId) @@ -224,25 +238,32 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { val col = totalCol / Satoshis(2) val outcomes: Vector[(EnumOutcome, Satoshis)] = - Vector(EnumOutcome(winStr) -> totalCol, - EnumOutcome(loseStr) -> Satoshis.zero) + Vector( + EnumOutcome(winStr) -> totalCol, + EnumOutcome(loseStr) -> Satoshis.zero + ) val oraclePair: ContractOraclePair.EnumPair = - ContractOraclePair.EnumPair(EnumContractDescriptor(outcomes), - sampleOracleInfo) + ContractOraclePair.EnumPair( + EnumContractDescriptor(outcomes), + sampleOracleInfo + ) val contractInfo: ContractInfo = SingleContractInfo(totalCol, oraclePair) val offerData = - sampleDLCOffer.copy(contractInfo = contractInfo, - collateral = col.satoshis) + sampleDLCOffer.copy( + contractInfo = contractInfo, + collateral = col.satoshis + ) val walletA = fundedDLCWallets._1.wallet val walletB = fundedDLCWallets._2.wallet def reorderInputDbs( wallet: DLCWallet, - dlcId: Sha256Digest): Future[Unit] = { + dlcId: Sha256Digest + ): Future[Unit] = { for { inputDbs <- wallet.dlcInputsDAO.findByDLCId(dlcId) _ <- wallet.dlcInputsDAO.deleteByDLCId(dlcId) @@ -316,9 +337,11 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { assert( accept.fundingInputs .map(_.output.value) - .sum >= accept.collateral) + .sum >= accept.collateral + ) assert( - accept.collateral == offer.contractInfo.totalCollateral - offer.collateral) + accept.collateral == offer.contractInfo.totalCollateral - offer.collateral + ) assert(accept.changeAddress.value.nonEmpty) } @@ -368,7 +391,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { def getDLCReadyToAddSigs( walletA: DLCWallet, walletB: DLCWallet, - offerData: DLCOffer = DLCWalletUtil.sampleDLCOffer): Future[DLCSign] = { + offerData: DLCOffer = DLCWalletUtil.sampleDLCOffer + ): Future[DLCSign] = { for { accept <- getDLCReadyToSign(walletA, walletB, offerData) sign <- walletA.signDLC(accept) @@ -378,7 +402,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { def getDLCReadyToSign( walletA: DLCWallet, walletB: DLCWallet, - offerData: DLCOffer = DLCWalletUtil.sampleDLCOffer): Future[DLCAccept] = { + offerData: DLCOffer = DLCWalletUtil.sampleDLCOffer + ): Future[DLCAccept] = { for { offer <- walletA.createDLCOffer( offerData.contractInfo, @@ -398,8 +423,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { def testDLCSignVerification[E <: Exception]( walletA: DLCWallet, walletB: DLCWallet, - makeDLCSignInvalid: DLCSign => DLCSign)(implicit - classTag: ClassTag[E]): Future[Assertion] = { + makeDLCSignInvalid: DLCSign => DLCSign + )(implicit classTag: ClassTag[E]): Future[Assertion] = { val failedAddSigsF = for { sign <- getDLCReadyToAddSigs(walletA, walletB) invalidSign = makeDLCSignInvalid(sign) @@ -412,7 +437,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { def testDLCAcceptVerification( walletA: DLCWallet, walletB: DLCWallet, - makeDLCAcceptInvalid: DLCAccept => DLCAccept): Future[Assertion] = { + makeDLCAcceptInvalid: DLCAccept => DLCAccept + ): Future[Assertion] = { val failedAddSigsF = for { accept <- getDLCReadyToSign(walletA, walletB) invalidSign = makeDLCAcceptInvalid(accept) @@ -430,7 +456,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { for { sign <- getDLCReadyToAddSigs(walletA, walletB) _ <- recoverToSucceededIf[IllegalArgumentException]( - walletA.addDLCSigs(sign)) + walletA.addDLCSigs(sign) + ) } yield succeed } @@ -459,7 +486,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { sign.copy(fundingSigs = FundingSignatures( sign.fundingSigs .map(_.copy(_2 = P2WPKHWitnessV0(ECPublicKey.freshPublicKey))) - .toVector)) + .toVector + )) ) } @@ -472,7 +500,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { walletA, walletB, (sign: DLCSign) => - sign.copy(cetSigs = CETSignatures(DLCWalletUtil.dummyOutcomeSigs))) + sign.copy(cetSigs = CETSignatures(DLCWalletUtil.dummyOutcomeSigs)) + ) } it must "fail to add an invalid dlc refund sig" in { @@ -483,7 +512,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { testDLCSignVerification[IllegalArgumentException]( walletA, walletB, - (sign: DLCSign) => sign.copy(refundSig = DLCWalletUtil.dummyPartialSig)) + (sign: DLCSign) => sign.copy(refundSig = DLCWalletUtil.dummyPartialSig) + ) } it must "fail to sign dlc with cet sigs that are invalid" in { @@ -495,7 +525,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { walletA, walletB, (accept: DLCAccept) => - accept.copy(cetSigs = CETSignatures(DLCWalletUtil.dummyOutcomeSigs))) + accept.copy(cetSigs = CETSignatures(DLCWalletUtil.dummyOutcomeSigs)) + ) } it must "fail to sign dlc with an invalid refund sig" in { @@ -507,7 +538,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { walletA, walletB, (accept: DLCAccept) => - accept.copy(refundSig = DLCWalletUtil.dummyPartialSig)) + accept.copy(refundSig = DLCWalletUtil.dummyPartialSig) + ) } it must "cancel an offered DLC" in { @@ -543,9 +575,11 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { _ <- walletA.cancelDLC(dlcId) announcementData <- walletA.announcementDAO.findByPublicKey( - announcementTLV.publicKey) + announcementTLV.publicKey + ) nonceDbs <- walletA.oracleNonceDAO.findByAnnouncementIds( - announcementData.map(_.id.get)) + announcementData.map(_.id.get) + ) balance <- walletA.getBalance() reserved <- walletA.spendingInfoDAO.findByTxoState(TxoState.Reserved) @@ -609,12 +643,14 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { for { oldBalanceA <- walletA.getBalance() oldReservedA <- walletA.spendingInfoDAO.findByTxoState( - TxoState.Reserved) + TxoState.Reserved + ) _ = assert(oldReservedA.isEmpty) oldBalanceB <- walletB.getBalance() oldReservedB <- walletB.spendingInfoDAO.findByTxoState( - TxoState.Reserved) + TxoState.Reserved + ) _ = assert(oldReservedB.isEmpty) offer <- walletA.createDLCOffer( @@ -683,10 +719,12 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint)) _ <- recoverToSucceededIf[IllegalArgumentException]( - walletA.cancelDLC(dlcId)) + walletA.cancelDLC(dlcId) + ) _ <- recoverToSucceededIf[IllegalArgumentException]( - walletB.cancelDLC(dlcId)) + walletB.cancelDLC(dlcId) + ) } yield succeed } @@ -719,10 +757,12 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint)) _ <- recoverToSucceededIf[IllegalArgumentException]( - walletA.executeDLCRefund(sign.contractId)) + walletA.executeDLCRefund(sign.contractId) + ) _ <- recoverToSucceededIf[IllegalArgumentException]( - walletB.executeDLCRefund(sign.contractId)) + walletB.executeDLCRefund(sign.contractId) + ) } yield succeed } @@ -739,12 +779,18 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { val contractDescriptor: EnumContractDescriptor = EnumContractDescriptor.fromStringVec( - Vector(winStr -> Satoshis(betSize), - loseStr -> Satoshis.zero, - drawStr -> Satoshis(betSize / 2))) + Vector( + winStr -> Satoshis(betSize), + loseStr -> Satoshis.zero, + drawStr -> Satoshis(betSize / 2) + ) + ) - val oracleInfo = EnumSingleOracleInfo(OracleAnnouncementTLV( - "fdd824b4caaec7479cc9d37003f5add6504d035054ffeac8637a990305a45cfecc1062044c3f68b45318f57e41c4544a4a950c0744e2a80854349a3426b00ad86da5090b9e942dc6df2ae87f007b45b0ccd63e6c354d92c4545fc099ea3e137e54492d1efdd822500001a6a09c7c83c50b34f9db560a2e14fef2eab5224c15b18c7114331756364bfce65ffe3800fdd8062400030c44656d6f637261745f77696e0e52657075626c6963616e5f77696e056f746865720161")) + val oracleInfo = EnumSingleOracleInfo( + OracleAnnouncementTLV( + "fdd824b4caaec7479cc9d37003f5add6504d035054ffeac8637a990305a45cfecc1062044c3f68b45318f57e41c4544a4a950c0744e2a80854349a3426b00ad86da5090b9e942dc6df2ae87f007b45b0ccd63e6c354d92c4545fc099ea3e137e54492d1efdd822500001a6a09c7c83c50b34f9db560a2e14fef2eab5224c15b18c7114331756364bfce65ffe3800fdd8062400030c44656d6f637261745f77696e0e52657075626c6963616e5f77696e056f746865720161" + ) + ) val offerData = DLCOffer( DLCOfferTLV.currentVersionOpt, @@ -761,7 +807,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { ) val oracleSig = SchnorrDigitalSignature( - "a6a09c7c83c50b34f9db560a2e14fef2eab5224c15b18c7114331756364bfce6c59736cdcfe1e0a89064f846d5dbde0902f82688dde34dc1833965a60240f287") + "a6a09c7c83c50b34f9db560a2e14fef2eab5224c15b18c7114331756364bfce6c59736cdcfe1e0a89064f846d5dbde0902f82688dde34dc1833965a60240f287" + ) val sig = OracleSignatures(oracleInfo, Vector(oracleSig)) @@ -793,7 +840,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { _ = { assert(accept.fundingInputs.nonEmpty) assert( - accept.collateral == offer.contractInfo.maxOffererPayout - offer.collateral) + accept.collateral == offer.contractInfo.maxOffererPayout - offer.collateral + ) assert(accept.changeAddress.value.nonEmpty) } @@ -840,11 +888,13 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { func = (wallet: DLCWallet) => wallet.executeDLC(sign.contractId, sig).map(_.get) - result <- dlcExecutionTest(dlcA = walletA, - dlcB = walletB, - asInitiator = true, - func = func, - expectedOutputs = 1) + result <- dlcExecutionTest( + dlcA = walletA, + dlcB = walletB, + asInitiator = true, + func = func, + expectedOutputs = 1 + ) } yield { assert(result) } @@ -854,12 +904,14 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { val walletA = wallets._1.wallet val walletB = wallets._2.wallet - //https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/12fb3e5f091086329ed0d2a12c3fcfa80111a36ef3fc1ac9c2567076a57d6a73 + // https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/12fb3e5f091086329ed0d2a12c3fcfa80111a36ef3fc1ac9c2567076a57d6a73 val contractInfoA = ContractInfoV0TLV.fromHex( - "fdd82eeb00000000000186a0fda71026030359455300000000000186a0024e4f0000000000000000056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342") - //https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/e5fb1dd68e51f5d735a0dd83ff88795bd7c959003a01e16c1ad08df3758de057 + "fdd82eeb00000000000186a0fda71026030359455300000000000186a0024e4f0000000000000000056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342" + ) + // https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/e5fb1dd68e51f5d735a0dd83ff88795bd7c959003a01e16c1ad08df3758de057 val contractInfoB = ContractInfoV0TLV.fromHex( - "fdd82eeb0000000000002710fda7102603035945530000000000000000024e4f0000000000002710056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342") + "fdd82eeb0000000000002710fda7102603035945530000000000000000024e4f0000000000002710056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342" + ) assert(contractInfoA.oracleInfo == contractInfoB.oracleInfo) @@ -917,7 +969,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { accept1F = walletB.acceptDLCOffer(offer, None, None, None) accept2F = walletB.acceptDLCOffer(offer, None, None, None) _ <- recoverToSucceededIf[DuplicateOfferException]( - Future.sequence(Seq(accept1F, accept2F))) + Future.sequence(Seq(accept1F, accept2F)) + ) } yield { succeed } @@ -972,7 +1025,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { ) accept <- walletB.acceptDLCOffer(offer, None, None, None) res <- recoverToSucceededIf[IllegalArgumentException]( - walletB.signDLC(accept)) + walletB.signDLC(accept) + ) } yield res } @@ -996,7 +1050,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { externalChangeAddressOpt = None ) _ <- recoverToSucceededIf[RuntimeException]( - walletB.acceptDLCOffer(offer, None, None, None)) + walletB.acceptDLCOffer(offer, None, None, None) + ) } yield succeed } @@ -1017,7 +1072,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { None, None, None - )) + ) + ) } yield { res } @@ -1028,9 +1084,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { val walletA = wallets._1.wallet val walletB = wallets._2.wallet - //https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/12fb3e5f091086329ed0d2a12c3fcfa80111a36ef3fc1ac9c2567076a57d6a73 + // https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/12fb3e5f091086329ed0d2a12c3fcfa80111a36ef3fc1ac9c2567076a57d6a73 val contractInfo = ContractInfoV0TLV.fromHex( - "fdd82eeb00000000000186a0fda71026030359455300000000000186a0024e4f0000000000000000056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342") + "fdd82eeb00000000000186a0fda71026030359455300000000000186a0024e4f0000000000000000056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342" + ) val feeRateOpt = Some(SatoshisPerVirtualByte(Satoshis.one)) val totalCollateral = Satoshis(5000) @@ -1047,7 +1104,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { ) invalidOffer = offer.copy(contractInfo = invalidContractInfo) res <- recoverToSucceededIf[InvalidAnnouncementSignature]( - walletB.acceptDLCOffer(invalidOffer, None, None, None)) + walletB.acceptDLCOffer(invalidOffer, None, None, None) + ) } yield { res } @@ -1059,9 +1117,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { val walletA = wallets._1.wallet val walletB = wallets._2.wallet - //https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/12fb3e5f091086329ed0d2a12c3fcfa80111a36ef3fc1ac9c2567076a57d6a73 + // https://test.oracle.suredbits.com/contract/enum/75b08299654dca23b80cf359db6afb6cfd6e55bc898b5397d3c0fe796dfc13f0/12fb3e5f091086329ed0d2a12c3fcfa80111a36ef3fc1ac9c2567076a57d6a73 val contractInfo = ContractInfoV0TLV.fromHex( - "fdd82eeb00000000000186a0fda71026030359455300000000000186a0024e4f0000000000000000056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342") + "fdd82eeb00000000000186a0fda71026030359455300000000000186a0024e4f0000000000000000056f746865720000000000000000fda712b5fdd824b1596ec40d0dae3fdf54d9795ad51ec069970c6863a02d244663d39fd6bedadc0070349e1ba2e17583ee2d1cb3ae6fffaaa1c45039b61c5c4f1d0d864221c461745d1bcfab252c6dd9edd7aea4c5eeeef138f7ff7346061ea40143a9f5ae80baa9fdd8224d0001fa5b84283852400b21a840d5d5ca1cc31867c37326ad521aa50bebf3df4eea1a60b03280fdd8060f000303594553024e4f056f74686572135465746865722d52657365727665732d363342" + ) val contractInfo1 = DLCWalletUtil.sampleDLCOffer.contractInfo.toTLV val feeRateOpt = Some(SatoshisPerVirtualByte(Satoshis.one)) @@ -1071,9 +1130,11 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { // random testnet addresses val payoutAddressAOpt = Some( - BitcoinAddress.fromString("tb1qw98mrsxpqtz25xe332khnvlapvl09ejnzk7c3f")) + BitcoinAddress.fromString("tb1qw98mrsxpqtz25xe332khnvlapvl09ejnzk7c3f") + ) val changeAddressAOpt = Some( - BitcoinAddress.fromString("tb1qkfaglsvpcwe5pm9ktqs80u9d9jd0qzgqjqd240")) + BitcoinAddress.fromString("tb1qkfaglsvpcwe5pm9ktqs80u9d9jd0qzgqjqd240") + ) val payoutAddressBOpt = Some(BitcoinAddress.fromString("2MsM67NLa71fHvTUBqNENW15P68nHB2vVXb")) val changeAddressBOpt = @@ -1096,10 +1157,12 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { externalPayoutAddressOpt = payoutAddressAOpt, externalChangeAddressOpt = changeAddressAOpt ) - accept <- walletB.acceptDLCOffer(offer, - peerAddressOpt2, - payoutAddressBOpt, - changeAddressBOpt) + accept <- walletB.acceptDLCOffer( + offer, + peerAddressOpt2, + payoutAddressBOpt, + changeAddressBOpt + ) offer1 <- walletA.createDLCOffer( contractInfoTLV = contractInfo1, collateral = totalCollateral1, @@ -1128,9 +1191,10 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { val walletA = FundedDLCWallets._1.wallet val walletB = FundedDLCWallets._2.wallet val offerData: DLCOffer = - DLCWalletUtil.sampleDLCOffer.copy(contractInfo = - DLCWalletUtil.sampleContractInfo2, - collateral = DLCWalletUtil.amt2) + DLCWalletUtil.sampleDLCOffer.copy( + contractInfo = DLCWalletUtil.sampleContractInfo2, + collateral = DLCWalletUtil.amt2 + ) val amt2: Satoshis = Bitcoins(3).satoshis val offerCollateral2 = amt2 lazy val sampleContractInfo2: ContractInfo = @@ -1149,9 +1213,9 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest { None, None ) - //accept it for the first time using the inputs + // accept it for the first time using the inputs _ <- walletB.acceptDLCOffer(offer1.toTLV, None, None, None) - //cancel the offer + // cancel the offer _ <- walletA.cancelDLC(dlcId = offer1.dlcId) offer2 <- walletA.createDLCOffer( diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/internal/DLCDataManagementTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/internal/DLCDataManagementTest.scala index a8bb7844a0..99e54a2223 100644 --- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/internal/DLCDataManagementTest.scala +++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/internal/DLCDataManagementTest.scala @@ -40,7 +40,8 @@ class DLCDataManagementTest extends BitcoinSDualWalletTest { contractId = DLCUtil.calcContractId(offer1, accept) acceptDbStateOpt <- walletB.dlcDataManagement.getDLCFundingData( contractId, - walletA.transactionDAO) + walletA.transactionDAO + ) } yield { assert(acceptDbStateOpt.isDefined) assert(acceptDbStateOpt.get.isInstanceOf[AcceptDbState]) @@ -71,7 +72,8 @@ class DLCDataManagementTest extends BitcoinSDualWalletTest { sign <- walletA.signDLC(accept) signDbStateOpt <- walletA.dlcDataManagement.getDLCFundingData( sign.contractId, - walletA.transactionDAO) + walletA.transactionDAO + ) } yield { assert(signDbStateOpt.isDefined) assert(signDbStateOpt.get.isInstanceOf[SignDbState]) diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCAppConfig.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCAppConfig.scala index d535f9dd87..540ec98ccb 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCAppConfig.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCAppConfig.scala @@ -41,14 +41,16 @@ import scala.concurrent.{ExecutionContext, Future} /** Configuration for the Bitcoin-S wallet * - * @param directory The data directory of the wallet - * @param conf Optional sequence of configuration overrides + * @param directory + * The data directory of the wallet + * @param conf + * Optional sequence of configuration overrides */ case class DLCAppConfig( baseDatadir: Path, configOverrides: Vector[Config], - walletConfigOpt: Option[WalletAppConfig] = None)(implicit - val system: ActorSystem) + walletConfigOpt: Option[WalletAppConfig] = None +)(implicit val system: ActorSystem) extends DbAppConfig with DLCDbManagement with JdbcProfileComponent[DLCAppConfig] @@ -58,7 +60,8 @@ case class DLCAppConfig( override protected[bitcoins] type ConfigType = DLCAppConfig override protected[bitcoins] def newConfigOfType( - configs: Vector[Config]): DLCAppConfig = + configs: Vector[Config] + ): DLCAppConfig = DLCAppConfig(baseDatadir, configs) override def appConfig: DLCAppConfig = this @@ -70,7 +73,7 @@ case class DLCAppConfig( Files.createDirectories(datadir) } - //get migrations applied the last time the wallet was started + // get migrations applied the last time the wallet was started val initMigrations = migrationsApplied() val numMigrations = { @@ -78,20 +81,21 @@ case class DLCAppConfig( } val f = if (initMigrations != 0 && initMigrations <= 9) { - //means we have an old wallet that we need to migrate + // means we have an old wallet that we need to migrate serializationVersionMigration() .flatMap { _ => deleteAlphaVersionDLCs() } } else { - //the wallet is new enough where we cannot have any old - //DLCs in the database with a broken contractId + // the wallet is new enough where we cannot have any old + // DLCs in the database with a broken contractId Future.unit } logger.info( - s"Applied ${numMigrations.migrationsExecuted} to the dlc project. Started with initMigrations=$initMigrations") + s"Applied ${numMigrations.migrationsExecuted} to the dlc project. Started with initMigrations=$initMigrations" + ) f } @@ -128,8 +132,10 @@ case class DLCAppConfig( override lazy val schemaName: Option[String] = { driver match { case PostgreSQL => - val schema = PostgresUtil.getSchemaName(moduleName = moduleName, - walletName = walletName) + val schema = PostgresUtil.getSchemaName( + moduleName = moduleName, + walletName = walletName + ) Some(schema) case SQLite => None @@ -139,11 +145,13 @@ case class DLCAppConfig( def createDLCWallet( nodeApi: NodeApi, chainQueryApi: ChainQueryApi, - feeRateApi: FeeRateApi)(implicit - walletConf: WalletAppConfig): Future[DLCWallet] = { - DLCAppConfig.createDLCWallet(nodeApi = nodeApi, - chainQueryApi = chainQueryApi, - feeRateApi = feeRateApi)(walletConf, this) + feeRateApi: FeeRateApi + )(implicit walletConf: WalletAppConfig): Future[DLCWallet] = { + DLCAppConfig.createDLCWallet( + nodeApi = nodeApi, + chainQueryApi = chainQueryApi, + feeRateApi = feeRateApi + )(walletConf, this) } private val callbacks = new Mutable(DLCWalletCallbacks.empty) @@ -151,14 +159,17 @@ case class DLCAppConfig( def walletCallbacks: DLCWalletCallbacks = callbacks.atomicGet override def addCallbacks( - newCallbacks: DLCWalletCallbacks): DLCWalletCallbacks = { + newCallbacks: DLCWalletCallbacks + ): DLCWalletCallbacks = { callbacks.atomicUpdate(newCallbacks)(_ + _) } override lazy val callbackFactory: DLCWalletCallbacks.type = DLCWalletCallbacks - /** Delete alpha version DLCs, these are old protocol format DLCs that cannot be safely updated to the new protocol version of DLCs */ + /** Delete alpha version DLCs, these are old protocol format DLCs that cannot + * be safely updated to the new protocol version of DLCs + */ private def deleteAlphaVersionDLCs(): Future[Unit] = { logger.info(s"Deleting alpha version DLCs") val dlcManagement = DLCDataManagement.fromDbAppConfig()(this, ec) @@ -174,32 +185,34 @@ case class DLCAppConfig( case _: ClosedState | DLCState.Offered | DLCState.Accepted | _: AdaptorSigComputationState | DLCState.Signed => logger.info( - s"Deleting alpha version of a dlcId=${dlc.dlcId.hex} dlc=$dlc") + s"Deleting alpha version of a dlcId=${dlc.dlcId.hex} dlc=$dlc" + ) dlcManagement.deleteByDLCId(dlc.dlcId) case DLCState.Broadcasted | DLCState.Confirmed => sys.error( - s"Cannot upgrade our DLC wallet as we have DLCs in progress using an ancient format of DLCs, dlcId=${dlc.dlcId.hex}") + s"Cannot upgrade our DLC wallet as we have DLCs in progress using an ancient format of DLCs, dlcId=${dlc.dlcId.hex}" + ) } } } yield () } - /** Correctly populates the serialization version for existing DLCs - * in our wallet database + /** Correctly populates the serialization version for existing DLCs in our + * wallet database */ private def serializationVersionMigration(): Future[Unit] = { logger.info(s"Fixing serialization version for false positive Beta DLCs") val dlcManagement = DLCDataManagement.fromDbAppConfig()(this, ec) val dlcDAO = dlcManagement.dlcDAO - //read all existing DLCs + // read all existing DLCs val allDlcsF = dlcDAO.findAll() - //ugh, this is kinda nasty, idk how to make better though + // ugh, this is kinda nasty, idk how to make better though val walletAppConfig = WalletAppConfig(baseDatadir, configOverrides) val txDAO: TransactionDAO = TransactionDAO()(ec = ec, appConfig = walletAppConfig) - //get the offers so we can figure out what the serialization version is + // get the offers so we can figure out what the serialization version is val dlcDbContractInfoOfferF: Future[Vector[DLCSetupDbState]] = { for { allDlcs <- allDlcsF @@ -208,11 +221,13 @@ case class DLCAppConfig( dlcManagement.getDLCFundingData(a.dlcId, txDAO = txDAO) setupDbOptF.foreach { - case Some(_) => //happy path, do nothing + case Some(_) => // happy path, do nothing case None => - logger.warn(s"Corrupted dlcId=${a.dlcId.hex} state=${a.state}, " + - s"this is likely because of issue 4001 https://github.com/bitcoin-s/bitcoin-s/issues/4001 . " + - s"This DLC will not have its contractId migrated to DLSerializationVersion.Beta") + logger.warn( + s"Corrupted dlcId=${a.dlcId.hex} state=${a.state}, " + + s"this is likely because of issue 4001 https://github.com/bitcoin-s/bitcoin-s/issues/4001 . " + + s"This DLC will not have its contractId migrated to DLSerializationVersion.Beta" + ) } setupDbOptF } @@ -222,8 +237,8 @@ case class DLCAppConfig( } } - //now we need to insert the serialization type - //into global_dlc_data + // now we need to insert the serialization type + // into global_dlc_data val updatedDLCDbsF = for { dlcDbContractInfoOffer <- dlcDbContractInfoOfferF } yield setSerializationVersions(dlcDbContractInfoOffer) @@ -233,9 +248,12 @@ case class DLCAppConfig( updatedInDbF.map(_ => ()) } - /** Sets serialization versions on [[DLCDb]] based on the corresponding [[ContractInfo]] */ + /** Sets serialization versions on [[DLCDb]] based on the corresponding + * [[ContractInfo]] + */ private def setSerializationVersions( - vec: Vector[DLCSetupDbState]): Vector[DLCDb] = { + vec: Vector[DLCSetupDbState] + ): Vector[DLCDb] = { vec.map { case state: DLCSetupDbState => val updatedDlcDb: DLCDb = state match { case acceptDbState: SetupCompleteDLCDbState => @@ -243,35 +261,45 @@ case class DLCAppConfig( val dlcDb = acceptDbState.dlcDb offer.contractInfo.contractDescriptors.head match { case _: EnumContractDescriptor => - dlcDb.copy(tempContractId = offer.tempContractId, - serializationVersion = DLCSerializationVersion.Beta) + dlcDb.copy( + tempContractId = offer.tempContractId, + serializationVersion = DLCSerializationVersion.Beta + ) case numeric: NumericContractDescriptor => val version = numeric.outcomeValueFunc.serializationVersion if (version != dlcDb.serializationVersion) { logger.info( - s"Updating serializationVersion for dlcId=${dlcDb.dlcId.hex} old version=${dlcDb.serializationVersion} new version=${version}") - dlcDb.copy(tempContractId = offer.tempContractId, - serializationVersion = version) + s"Updating serializationVersion for dlcId=${dlcDb.dlcId.hex} old version=${dlcDb.serializationVersion} new version=${version}" + ) + dlcDb.copy( + tempContractId = offer.tempContractId, + serializationVersion = version + ) } else { dlcDb } } case offerDbState: OfferedDbState => - //if we don't have an accept message, we can only calculate tempContractId + // if we don't have an accept message, we can only calculate tempContractId val dlcDb = offerDbState.dlcDb val offer = offerDbState.offer offer.contractInfo.contractDescriptors.head match { case _: EnumContractDescriptor => - dlcDb.copy(tempContractId = offer.tempContractId, - serializationVersion = DLCSerializationVersion.Beta) + dlcDb.copy( + tempContractId = offer.tempContractId, + serializationVersion = DLCSerializationVersion.Beta + ) case numeric: NumericContractDescriptor => val version = numeric.outcomeValueFunc.serializationVersion if (version != dlcDb.serializationVersion) { logger.info( - s"Updating serializationVersion for dlcId=${dlcDb.dlcId.hex} old version=${dlcDb.serializationVersion} new version=${version}") - dlcDb.copy(tempContractId = offer.tempContractId, - serializationVersion = version) + s"Updating serializationVersion for dlcId=${dlcDb.dlcId.hex} old version=${dlcDb.serializationVersion} new version=${version}" + ) + dlcDb.copy( + tempContractId = offer.tempContractId, + serializationVersion = version + ) } else { dlcDb } @@ -288,20 +316,23 @@ object DLCAppConfig override val moduleName: String = "dlc" - /** Constructs a wallet configuration from the default Bitcoin-S - * data directory and given list of configuration overrides. + /** Constructs a wallet configuration from the default Bitcoin-S data + * directory and given list of configuration overrides. */ override def fromDatadir(datadir: Path, confs: Vector[Config])(implicit - system: ActorSystem): DLCAppConfig = + system: ActorSystem + ): DLCAppConfig = DLCAppConfig(datadir, confs) /** Creates a wallet based on the given [[WalletAppConfig]] */ def createDLCWallet( nodeApi: NodeApi, chainQueryApi: ChainQueryApi, - feeRateApi: FeeRateApi)(implicit + feeRateApi: FeeRateApi + )(implicit walletConf: WalletAppConfig, - dlcConf: DLCAppConfig): Future[DLCWallet] = { + dlcConf: DLCAppConfig + ): Future[DLCWallet] = { import dlcConf.ec val bip39PasswordOpt = walletConf.bip39PasswordOpt walletConf.hasWallet().flatMap { walletExists => @@ -316,8 +347,10 @@ object DLCAppConfig DLCWallet(nodeApi, chainQueryApi, feeRateApi) Wallet - .initialize(wallet = unInitializedWallet, - bip39PasswordOpt = bip39PasswordOpt) + .initialize( + wallet = unInitializedWallet, + bip39PasswordOpt = bip39PasswordOpt + ) .map(_.asInstanceOf[DLCWallet]) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala index 9bb4472d76..88cbee6b24 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala @@ -106,12 +106,17 @@ abstract class DLCWallet private lazy val safeDLCDatabase: SafeDatabase = dlcDAO.safeDatabase private lazy val walletDatabase: SafeDatabase = addressDAO.safeDatabase - /** Updates the contract Id in the wallet database for the given offer and accept */ + /** Updates the contract Id in the wallet database for the given offer and + * accept + */ private def updateDLCContractIds( offer: DLCOffer, - accept: DLCAccept): Future[DLCDb] = { - require(accept.tempContractId == offer.tempContractId, - "Offer and Accept have differing tempContractIds!") + accept: DLCAccept + ): Future[DLCDb] = { + require( + accept.tempContractId == offer.tempContractId, + "Offer and Accept have differing tempContractIds!" + ) val dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint)) for { dlcOpt <- dlcDAO.read(dlcId) @@ -120,7 +125,9 @@ abstract class DLCWallet case None => Future.failed( new IllegalArgumentException( - s"No DLCDb found with dlcId ${dlcId.hex}")) + s"No DLCDb found with dlcId ${dlcId.hex}" + ) + ) } contractId = DLCUtil.calcContractId(offer, accept) @@ -130,10 +137,13 @@ abstract class DLCWallet } yield updated } - /** Updates the [[DLCState]] of a DLC with the given contractId in the wallet's database */ + /** Updates the [[DLCState]] of a DLC with the given contractId in the + * wallet's database + */ private def updateDLCState( contractId: ByteVector, - state: DLCState): Future[DLCDb] = { + state: DLCState + ): Future[DLCDb] = { for { dlcOpt <- dlcDAO.findByContractId(contractId) dlcDb <- dlcOpt match { @@ -141,17 +151,22 @@ abstract class DLCWallet case None => Future.failed( new IllegalArgumentException( - s"No DLCDb found with contractId ${contractId.toHex}")) + s"No DLCDb found with contractId ${contractId.toHex}" + ) + ) } _ = logger.debug(s"Updating DLC (${contractId.toHex}) to state $state") updated <- dlcDAO.update(dlcDb.updateState(state)) } yield updated } - /** Updates the funding outpoint in the DLCDb corresponding to the given contractId */ + /** Updates the funding outpoint in the DLCDb corresponding to the given + * contractId + */ private def updateFundingOutPoint( contractId: ByteVector, - outPoint: TransactionOutPoint): Future[DLCDb] = { + outPoint: TransactionOutPoint + ): Future[DLCDb] = { for { dlcOpt <- dlcDAO.findByContractId(contractId) dlcDb <- dlcOpt match { @@ -159,18 +174,24 @@ abstract class DLCWallet case None => Future.failed( new IllegalArgumentException( - s"No DLCDb found with contractId ${contractId.toHex}")) + s"No DLCDb found with contractId ${contractId.toHex}" + ) + ) } _ = logger.debug( - s"Updating DLC (${contractId.toHex}) funding outpoint to ${outPoint.hex}") + s"Updating DLC (${contractId.toHex}) funding outpoint to ${outPoint.hex}" + ) updated <- dlcDAO.update(dlcDb.updateFundingOutPoint(outPoint)) } yield updated } - /** Updates the closing txId in the DLCDb corresponding to the given contractId */ + /** Updates the closing txId in the DLCDb corresponding to the given + * contractId + */ private def updateClosingTxId( contractId: ByteVector, - txId: DoubleSha256DigestBE): Future[DLCDb] = { + txId: DoubleSha256DigestBE + ): Future[DLCDb] = { for { dlcOpt <- dlcDAO.findByContractId(contractId) dlcDb <- dlcOpt match { @@ -178,18 +199,24 @@ abstract class DLCWallet case None => Future.failed( new IllegalArgumentException( - s"No DLCDb found with contractId ${contractId.toHex}")) + s"No DLCDb found with contractId ${contractId.toHex}" + ) + ) } _ = logger.info( - s"Updating DLC (${contractId.toHex}) closing txId to txIdBE=${txId.hex}") + s"Updating DLC (${contractId.toHex}) closing txId to txIdBE=${txId.hex}" + ) updated <- dlcDAO.update(dlcDb.updateClosingTxId(txId)) } yield updated } - /** Updates the aggregate signature in the DLCDb corresponding to the given contractId */ + /** Updates the aggregate signature in the DLCDb corresponding to the given + * contractId + */ private def updateAggregateSignature( contractId: ByteVector, - aggregateSignature: SchnorrDigitalSignature): Future[DLCDb] = { + aggregateSignature: SchnorrDigitalSignature + ): Future[DLCDb] = { for { dlcOpt <- dlcDAO.findByContractId(contractId) dlcDb <- dlcOpt match { @@ -197,18 +224,23 @@ abstract class DLCWallet case None => Future.failed( new IllegalArgumentException( - s"No DLCDb found with contractId ${contractId.toHex}")) + s"No DLCDb found with contractId ${contractId.toHex}" + ) + ) } _ = logger.debug( - s"Updating DLC (${contractId.toHex}) aggregate signature to ${aggregateSignature.hex}") + s"Updating DLC (${contractId.toHex}) aggregate signature to ${aggregateSignature.hex}" + ) updated <- dlcDAO.update( - dlcDb.updateAggregateSignature(aggregateSignature)) + dlcDb.updateAggregateSignature(aggregateSignature) + ) } yield updated } /** Updates the signatures in the oracle nonce database */ private def updateDLCOracleSigs( - sigs: Vector[OracleSignatures]): Future[Vector[OracleNonceDb]] = { + sigs: Vector[OracleSignatures] + ): Future[Vector[OracleNonceDb]] = { val outcomeAndSigByNonce = sigs.flatMap { case enum: EnumOracleSignature => Vector((enum.sig.rx, (enum.getOutcome.outcome, enum.sig))) @@ -219,8 +251,10 @@ abstract class DLCWallet nonces.zip(outcomeAndSigs) }.toMap - require(outcomeAndSigByNonce.forall(t => t._1 == t._2._2.rx), - "nonces out of order") + require( + outcomeAndSigByNonce.forall(t => t._1 == t._2._2.rx), + "nonces out of order" + ) val updateOracleSigsA = actionBuilder.updateDLCOracleSigsAction(outcomeAndSigByNonce) for { @@ -229,12 +263,14 @@ abstract class DLCWallet } /** Writes the addresses corresponding to wallet's keys in a DLC to the - * address database, this includes the address associated with the funding public key + * address database, this includes the address associated with the funding + * public key */ private def writeDLCKeysToAddressDb( account: AccountDb, chainType: HDChainType, - index: Int): Future[Vector[AddressDb]] = { + index: Int + ): Future[Vector[AddressDb]] = { for { zero <- getAddress(account, chainType, index) one <- getAddress(account, chainType, index + 1) @@ -244,9 +280,9 @@ abstract class DLCWallet } } - /** If the DLC has not reached the Signed state, it can be canceled. - * Canceling a DLC deletes all data about it from the database, - * as well as unreserves the utxos associated with it. + /** If the DLC has not reached the Signed state, it can be canceled. Canceling + * a DLC deletes all data about it from the database, as well as unreserves + * the utxos associated with it. */ override def cancelDLC(dlcId: Sha256Digest): Future[Unit] = { for { @@ -256,14 +292,17 @@ abstract class DLCWallet case Some(db) => require( DLCState.cancellableState.exists(_ == db.state), - s"Cannot cancel a DLC after it has been signed, state=${db.state}") + s"Cannot cancel a DLC after it has been signed, state=${db.state}" + ) db case None => throw new IllegalArgumentException( - s"No DLC Found with dlc id ${dlcId.hex}") + s"No DLC Found with dlc id ${dlcId.hex}" + ) } _ = logger.info( - s"Canceling DLC with tempContractId=${dlcDb.tempContractId.hex} dlcId=${dlcId.hex} contractId=${dlcDb.contractIdOpt}") + s"Canceling DLC with tempContractId=${dlcDb.tempContractId.hex} dlcId=${dlcId.hex} contractId=${dlcDb.contractIdOpt}" + ) inputs <- dlcInputsDAO.findByDLCId(dlcId, dlcDb.isInitiator) dbs <- spendingInfoDAO.findByOutPoints(inputs.map(_.outPoint)) // allow this to fail in the case they have already been unreserved @@ -282,21 +321,24 @@ abstract class DLCWallet refundLT: UInt32, peerAddressOpt: Option[java.net.InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] = { + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCOffer] = { chainQueryApi.getBestHashBlockHeight().flatMap { height => - createDLCOffer(contractInfo, - collateral, - feeRateOpt, - locktime = UInt32(height), - refundLT, - peerAddressOpt, - externalPayoutAddressOpt, - externalChangeAddressOpt) + createDLCOffer( + contractInfo, + collateral, + feeRateOpt, + locktime = UInt32(height), + refundLT, + peerAddressOpt, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) } } - /** Creates a DLCOffer, if one has already been created - * with the given parameters then that one will be returned instead. + /** Creates a DLCOffer, if one has already been created with the given + * parameters then that one will be returned instead. * * This is the first step of the initiator */ @@ -308,18 +350,22 @@ abstract class DLCWallet refundLocktime: UInt32, peerAddressOpt: Option[java.net.InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCOffer] = { + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCOffer] = { logger.info("Creating DLC Offer") if ( !walletConfig.allowExternalDLCAddresses && (externalPayoutAddressOpt.nonEmpty || externalChangeAddressOpt.nonEmpty) ) { return Future.failed( - new IllegalArgumentException("External DLC addresses are not allowed")) + new IllegalArgumentException("External DLC addresses are not allowed") + ) } if (!validateAnnouncementSignatures(contractInfo.oracleInfos)) { return Future.failed( InvalidAnnouncementSignature( - s"Contract info contains invalid announcement signature(s)")) + s"Contract info contains invalid announcement signature(s)" + ) + ) } val announcements = @@ -331,17 +377,19 @@ abstract class DLCWallet for { feeRate <- feeRateF - //hack for now to get around https://github.com/bitcoin-s/bitcoin-s/issues/3127 - //filter announcements that we already have in the db + // hack for now to get around https://github.com/bitcoin-s/bitcoin-s/issues/3127 + // filter announcements that we already have in the db groupedAnnouncements <- groupByExistingAnnouncements(announcements) announcementDataDbs <- announcementDAO.createAll( - groupedAnnouncements.newAnnouncements) + groupedAnnouncements.newAnnouncements + ) allAnnouncementDbs = announcementDataDbs ++ groupedAnnouncements.existingAnnouncements newAnnouncements = announcements.filter(a => groupedAnnouncements.newAnnouncements.exists( - _.announcementSignature == a.announcementSignature)) + _.announcementSignature == a.announcementSignature + )) newAnnouncementsWithId = newAnnouncements.map { tlv => val idOpt: Option[Long] = @@ -372,16 +420,19 @@ abstract class DLCWallet DLCFundingInput.fromInputSigningInfo( utxo, id, - TransactionConstants.enableRBFSequence) + TransactionConstants.enableRBFSequence + ) } dlcId = calcDLCId(utxos.map(_.outPoint)) dlcAnnouncementDbs = allAnnouncementDbs.zipWithIndex.map { case (a, index) => - DLCAnnouncementDb(dlcId = dlcId, - announcementId = a.id.get, - index = index, - used = false) + DLCAnnouncementDb( + dlcId = dlcId, + announcementId = a.id.get, + index = index, + used = false + ) } txBuilder = fundRawTxHelper.txBuilderWithFinalizer @@ -390,22 +441,26 @@ abstract class DLCWallet BitcoinAddress.fromScriptPubKey(changeSPK, networkParameters) } - dlcPubKeys = DLCUtil.calcDLCPubKeys(xpub = account.xpub, - chainType = chainType, - keyIndex = nextIndex, - networkParameters = networkParameters, - externalPayoutAddressOpt = - externalPayoutAddressOpt) + dlcPubKeys = DLCUtil.calcDLCPubKeys( + xpub = account.xpub, + chainType = chainType, + keyIndex = nextIndex, + networkParameters = networkParameters, + externalPayoutAddressOpt = externalPayoutAddressOpt + ) _ = logger.debug( - s"DLC Offer data collected, creating database entry, ${dlcId.hex}") + s"DLC Offer data collected, creating database entry, ${dlcId.hex}" + ) payoutSerialId = DLCMessage.genSerialId() changeSerialId = DLCMessage.genSerialId() fundOutputSerialId = DLCMessage.genSerialId(Vector(changeSerialId)) - timeouts = DLCTimeouts(BlockTimeStamp(locktime), - BlockTimeStamp(refundLocktime)) + timeouts = DLCTimeouts( + BlockTimeStamp(locktime), + BlockTimeStamp(refundLocktime) + ) isExternalAddress <- addressDAO .findAddress(dlcPubKeys.payoutAddress) @@ -427,7 +482,8 @@ abstract class DLCWallet ) oracleParamsOpt = OracleInfo.getOracleParamsOpt( - contractInfo.oracleInfos.head) + contractInfo.oracleInfos.head + ) dlcDb = DLCDb( dlcId = dlcId, @@ -477,14 +533,16 @@ abstract class DLCWallet ) } _ = logger.info( - s"Created offer with tempContractId ${offer.tempContractId.hex}") + s"Created offer with tempContractId ${offer.tempContractId.hex}" + ) offerActions = actionBuilder.buildCreateOfferAction( dlcDb = dlcDb, contractDataDb = contractDataDb, dlcAnnouncementDbs = dlcAnnouncementDbs, dlcInputs = dlcInputs, - dlcOfferDb = dlcOfferDb) + dlcOfferDb = dlcOfferDb + ) _ <- safeDLCDatabase.run(offerActions) status <- findDLC(dlcId) @@ -502,7 +560,8 @@ abstract class DLCWallet externalChangeAddressOpt: Option[BitcoinAddress] ): Future[InitializedAccept] = { logger.info( - s"Initializing DLC from received offer with tempContractId ${offer.tempContractId.hex}") + s"Initializing DLC from received offer with tempContractId ${offer.tempContractId.hex}" + ) val dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint)) val contractInfo = offer.contractInfo val dlcOfferDb = DLCOfferDbHelper.fromDLCOffer(dlcId, offer) @@ -518,10 +577,15 @@ abstract class DLCWallet case _: OfferedDbState => Future.failed( new RuntimeException( - s"We cannot accept a DLC we offered, dlcId=${dlcId.hex}")) + s"We cannot accept a DLC we offered, dlcId=${dlcId.hex}" + ) + ) case _: SignDbState => - Future.failed(new RuntimeException( - s"We cannot accept a DLC we have already signed, dlcId=${dlcId.hex}")) + Future.failed( + new RuntimeException( + s"We cannot accept a DLC we have already signed, dlcId=${dlcId.hex}" + ) + ) case a: AcceptDbState => val dlcPubKeys = DLCUtil.calcDLCPubKeys( xpub = account.xpub, @@ -544,22 +608,22 @@ abstract class DLCWallet } case None => val nextIndexF = getNextAvailableIndex(account, chainType) - val acceptWithoutSigsWithKeysF: Future[( - DLCAcceptWithoutSigs, - DLCPublicKeys)] = nextIndexF.map { nextIndex => - DLCAcceptUtil.buildAcceptWithoutSigs( - keyIndex = nextIndex, - chainType = chainType, - offer = offer, - fundRawTxHelper = fundRawTxHelper, - account = account, - fundingPrivKey = getFundingPrivKey(account, nextIndex), - collateral = collateral, - networkParameters = networkParameters, - externalPayoutAddressOpt = externalPayoutAddressOpt, - externalChangeAddressOpt = externalChangeAddressOpt - ) - } + val acceptWithoutSigsWithKeysF + : Future[(DLCAcceptWithoutSigs, DLCPublicKeys)] = + nextIndexF.map { nextIndex => + DLCAcceptUtil.buildAcceptWithoutSigs( + keyIndex = nextIndex, + chainType = chainType, + offer = offer, + fundRawTxHelper = fundRawTxHelper, + account = account, + fundingPrivKey = getFundingPrivKey(account, nextIndex), + collateral = collateral, + networkParameters = networkParameters, + externalPayoutAddressOpt = externalPayoutAddressOpt, + externalChangeAddressOpt = externalChangeAddressOpt + ) + } for { (dlcAcceptWithoutSigs, dlcPubKeys) <- acceptWithoutSigsWithKeysF @@ -573,13 +637,14 @@ abstract class DLCWallet chainType, nextIndex, contractInfo, - peerOpt = - peerAddressOpt.map(a => a.getHostString + ":" + a.getPort)) - acceptDb = DLCAcceptUtil.buildAcceptDb(dlc = dlc, - acceptWithoutSigs = - dlcAcceptWithoutSigs, - dlcPubKeys = dlcPubKeys, - collateral = collateral) + peerOpt = peerAddressOpt.map(a => a.getHostString + ":" + a.getPort) + ) + acceptDb = DLCAcceptUtil.buildAcceptDb( + dlc = dlc, + acceptWithoutSigs = dlcAcceptWithoutSigs, + dlcPubKeys = dlcPubKeys, + collateral = collateral + ) acceptInputs = fundRawTxHelper.scriptSigParams .zip(dlcAcceptWithoutSigs.fundingInputs) .zipWithIndex @@ -597,9 +662,8 @@ abstract class DLCWallet witnessScriptOpt = InputInfo.getScriptWitness(utxo.inputInfo) ) } - contractDataDb = DLCAcceptUtil.buildAcceptContractDataDb(contractInfo, - dlcId, - offer) + contractDataDb = DLCAcceptUtil + .buildAcceptContractDataDb(contractInfo, dlcId, offer) _ <- writeDLCKeysToAddressDb(account, chainType, nextIndex) groupedAnnouncements <- groupByExistingAnnouncements(announcements) dlcDbAction = dlcDAO.createAction(dlc) @@ -607,32 +671,34 @@ abstract class DLCWallet acceptAction = dlcAcceptDAO.createAction(acceptDb) inputsAction = dlcInputsDAO.upsertAllAction(acceptInputs) contractAction = contractDataDAO.createAction(contractDataDb) - createdAnnouncementsAction = announcementDAO.createAllAction( - groupedAnnouncements.newAnnouncements) + createdAnnouncementsAction = announcementDAO + .createAllAction(groupedAnnouncements.newAnnouncements) zipped = { for { dlcDb <- dlcDbAction ann <- createdAnnouncementsAction - //we don't need the contract data db, so don't return it + // we don't need the contract data db, so don't return it contractDataDb <- contractAction offer <- dlcOfferAction accept <- acceptAction inputs <- inputsAction } yield (dlcDb, ann, offer, accept, inputs, contractDataDb) } - (writtenDLC, - createdDbs, - offerDb, - acceptDb, - inputsDb, - contractDataDb) <- + ( + writtenDLC, + createdDbs, + offerDb, + acceptDb, + inputsDb, + contractDataDb + ) <- safeDLCDatabase.run(zipped) announcementDataDbs = createdDbs ++ groupedAnnouncements.existingAnnouncements newAnnouncements = announcements.filter(a => - groupedAnnouncements.newAnnouncements.exists( - _.announcementSignature == a.announcementSignature)) + groupedAnnouncements.newAnnouncements + .exists(_.announcementSignature == a.announcementSignature)) newAnnouncementsWithId = newAnnouncements.map { tlv => val idOpt = createdDbs @@ -640,22 +706,24 @@ abstract class DLCWallet .flatMap(_.id) (tlv, idOpt.get) } - nonceDbs = OracleNonceDbHelper.fromAnnouncements( - newAnnouncementsWithId) + nonceDbs = OracleNonceDbHelper + .fromAnnouncements(newAnnouncementsWithId) createNonceAction = oracleNonceDAO.createAllAction(nonceDbs) dlcAnnouncementDbs = announcementDataDbs.zipWithIndex.map { case (a, index) => - DLCAnnouncementDb(dlcId = dlcId, - announcementId = a.id.get, - index = index, - used = false) + DLCAnnouncementDb( + dlcId = dlcId, + announcementId = a.id.get, + index = index, + used = false + ) } - createAnnouncementAction = dlcAnnouncementDAO.createAllAction( - dlcAnnouncementDbs) + createAnnouncementAction = dlcAnnouncementDAO + .createAllAction(dlcAnnouncementDbs) - _ <- safeDLCDatabase.run( - DBIOAction.seq(createNonceAction, createAnnouncementAction)) + _ <- safeDLCDatabase + .run(DBIOAction.seq(createNonceAction, createAnnouncementAction)) } yield { InitializedAccept( dlc = writtenDLC, @@ -670,8 +738,9 @@ abstract class DLCWallet } } - /** Creates a DLCAccept from the default Segwit account from a given offer, if one has already been - * created with the given parameters then that one will be returned instead. + /** Creates a DLCAccept from the default Segwit account from a given offer, if + * one has already been created with the given parameters then that one will + * be returned instead. * * This is the first step of the recipient */ @@ -679,17 +748,22 @@ abstract class DLCWallet offer: DLCOffer, peerAddressOpt: Option[java.net.InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCAccept] = { + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCAccept] = { logger.debug("Calculating relevant wallet data for DLC Accept") if ( !walletConfig.allowExternalDLCAddresses && (externalPayoutAddressOpt.nonEmpty || externalChangeAddressOpt.nonEmpty) ) { return Future.failed( - new IllegalArgumentException("External DLC addresses are not allowed")) + new IllegalArgumentException("External DLC addresses are not allowed") + ) } if (!validateAnnouncementSignatures(offer.oracleInfos)) { - return Future.failed(InvalidAnnouncementSignature( - s"Offer ${offer.tempContractId.hex} contains invalid announcement signature(s)")) + return Future.failed( + InvalidAnnouncementSignature( + s"Offer ${offer.tempContractId.hex} contains invalid announcement signature(s)" + ) + ) } val dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint)) @@ -697,20 +771,23 @@ abstract class DLCWallet val collateral = offer.contractInfo.totalCollateral - offer.collateral logger.debug(s"Checking if Accept (${dlcId.hex}) has already been made") for { - dlcAcceptOpt <- DLCAcceptUtil.findDLCAccept(dlcId = dlcId, - offer = offer, - dlcWalletDAOs = dlcWalletDAOs, - transactionDAO = - transactionDAO) + dlcAcceptOpt <- DLCAcceptUtil.findDLCAccept( + dlcId = dlcId, + offer = offer, + dlcWalletDAOs = dlcWalletDAOs, + transactionDAO = transactionDAO + ) dlcAccept <- { dlcAcceptOpt match { case Some(accept) => Future.successful(accept) case None => - createNewDLCAccept(collateral, - offer, - peerAddressOpt, - externalPayoutAddressOpt, - externalChangeAddressOpt) + createNewDLCAccept( + collateral, + offer, + peerAddressOpt, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) } } status <- findDLC(dlcId) @@ -719,7 +796,8 @@ abstract class DLCWallet } private def validateAnnouncementSignatures( - oracleInfos: Vector[OracleInfo]): Boolean = { + oracleInfos: Vector[OracleInfo] + ): Boolean = { oracleInfos.forall(infos => infos.singleOracleInfos.forall(_.announcement.validateSignature)) } @@ -727,10 +805,10 @@ abstract class DLCWallet private def fundDLCAcceptMsg( offer: DLCOffer, collateral: CurrencyUnit, - account: AccountDb): Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { - val txBuilderAndSpendingInfosF: Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { + account: AccountDb + ): Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { + val txBuilderAndSpendingInfosF + : Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { for { fundRawTxHelper <- fundRawTransactionInternal( destinations = @@ -747,10 +825,14 @@ abstract class DLCWallet private def getFundingPrivKey( account: AccountDb, - keyIndex: Int): AdaptorSign = { + keyIndex: Int + ): AdaptorSign = { val bip32Path = BIP32Path( - account.hdAccount.path ++ Vector(BIP32Node(0, hardenedOpt = None), - BIP32Node(keyIndex, hardenedOpt = None))) + account.hdAccount.path ++ Vector( + BIP32Node(0, hardenedOpt = None), + BIP32Node(keyIndex, hardenedOpt = None) + ) + ) val privKeyPath = HDPath.fromString(bip32Path.toString) keyManager.toSign(privKeyPath) } @@ -760,16 +842,20 @@ abstract class DLCWallet offer: DLCOffer, peerAddressOpt: Option[java.net.InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[DLCAccept] = + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCAccept] = Future { DLCWallet.AcceptingOffersLatch.startAccepting(offer.tempContractId) logger.info( - s"Creating DLC Accept for tempContractId ${offer.tempContractId.hex}") + s"Creating DLC Accept for tempContractId ${offer.tempContractId.hex}" + ) val result = for { account <- getDefaultAccountForType(AddressType.SegWit) - fundRawTxHelper <- fundDLCAcceptMsg(offer = offer, - collateral = collateral, - account = account) + fundRawTxHelper <- fundDLCAcceptMsg( + offer = offer, + collateral = collateral, + account = account + ) initializedAccept <- initDLCForAccept( @@ -786,12 +872,16 @@ abstract class DLCWallet s"Offer and Accept have differing tempContractIds! offer=${offer.tempContractId} accept=${initializedAccept.acceptWithoutSigs.tempContractId}" ) offerPrevTxs = offer.fundingInputs.map(funding => - TransactionDbHelper.fromTransaction(funding.prevTx, - blockHashOpt = None)) + TransactionDbHelper.fromTransaction( + funding.prevTx, + blockHashOpt = None + )) _ <- remoteTxDAO.upsertAll(offerPrevTxs) - fundingPrivKey = getFundingPrivKey(account, - initializedAccept.dlc.keyIndex) + fundingPrivKey = getFundingPrivKey( + account, + initializedAccept.dlc.keyIndex + ) builder = DLCTxBuilder(offer, initializedAccept.acceptWithoutSigs) @@ -810,7 +900,7 @@ abstract class DLCWallet _ <- scriptPubKeyDAO.createIfNotExists(spkDb) _ = logger.info(s"Creating CET Sigs for ${contractId.toHex}") - //emit websocket event that we are now computing adaptor signatures + // emit websocket event that we are now computing adaptor signatures isExternalAddress <- addressDAO .findAddress(initializedAccept.pubKeys.payoutAddress) .map(_.isEmpty) @@ -820,15 +910,19 @@ abstract class DLCWallet contractData = initializedAccept.contractDataDb, offerDb = initializedAccept.offerDb, payoutAddress = Some( - PayoutAddress(initializedAccept.pubKeys.payoutAddress, - isExternalAddress)) + PayoutAddress( + initializedAccept.pubKeys.payoutAddress, + isExternalAddress + ) + ) ) _ = dlcConfig.walletCallbacks.executeOnDLCStateChange(status) cetSigs <- signer.createCETSigsAsync() refundSig = signer.signRefundTx dlc = initializedAccept.dlc _ = logger.debug( - s"DLC Accept data collected, creating database entry, ${dlc.dlcId.hex}") + s"DLC Accept data collected, creating database entry, ${dlc.dlcId.hex}" + ) sigsDbs = cetSigs.outcomeSigs.zipWithIndex.map { case (sig, index) => DLCCETSignaturesDb(dlc.dlcId, index = index, sig._1, sig._2, None) @@ -855,11 +949,12 @@ abstract class DLCWallet accept = initializedAccept.acceptDb - .toDLCAccept(tempContractId = dlc.tempContractId, - fundingInputs = - initializedAccept.acceptWithoutSigs.fundingInputs, - outcomeSigs = cetSigs.outcomeSigs, - refundSig = refundSig) + .toDLCAccept( + tempContractId = dlc.tempContractId, + fundingInputs = initializedAccept.acceptWithoutSigs.fundingInputs, + outcomeSigs = cetSigs.outcomeSigs, + refundSig = refundSig + ) .copy(isExternalAddress = status.payoutAddress.forall(_.isExternal)) actions = actionBuilder.buildCreateAcceptAction( @@ -871,11 +966,14 @@ abstract class DLCWallet _ <- safeDLCDatabase.run(actions) dlcDb <- updateDLCContractIds(offer, accept) _ = logger.info( - s"Created DLCAccept for tempContractId ${offer.tempContractId.hex} with contract Id ${contractId.toHex}") + s"Created DLCAccept for tempContractId ${offer.tempContractId.hex} with contract Id ${contractId.toHex}" + ) fundingTx = builder.buildFundingTx - outPoint = TransactionOutPoint(fundingTx.txId, - UInt32(builder.fundOutputIndex)) + outPoint = TransactionOutPoint( + fundingTx.txId, + UInt32(builder.fundOutputIndex) + ) _ <- updateFundingOutPoint(dlcDb.contractIdOpt.get, outPoint) } yield accept result.onComplete(_ => @@ -884,21 +982,28 @@ abstract class DLCWallet }.flatten def registerDLCAccept( - accept: DLCAccept): Future[(DLCDb, Vector[DLCCETSignaturesDb])] = { + accept: DLCAccept + ): Future[(DLCDb, Vector[DLCCETSignaturesDb])] = { logger.info( - s"Checking if DLC Accept with tempContractId ${accept.tempContractId.hex} has already been registered") + s"Checking if DLC Accept with tempContractId ${accept.tempContractId.hex} has already been registered" + ) val dbsF = for { dlcDbOpt <- dlcDAO.findByTempContractId(accept.tempContractId) (dlcDb, acceptDbOpt) <- dlcDbOpt match { case Some(db) => - require(db.isInitiator, - "Cannot call DLC Sign on our own DLC Accept message") + require( + db.isInitiator, + "Cannot call DLC Sign on our own DLC Accept message" + ) dlcAcceptDAO .findByDLCId(db.dlcId) .map(acceptDbOpt => (db, acceptDbOpt)) case None => - Future.failed(new RuntimeException( - s"No DLC Offer found with corresponding tempContractId ${accept.tempContractId.hex}, this wallet did not create the corresponding offer")) + Future.failed( + new RuntimeException( + s"No DLC Offer found with corresponding tempContractId ${accept.tempContractId.hex}, this wallet did not create the corresponding offer" + ) + ) } } yield (dlcDb, acceptDbOpt) @@ -906,10 +1011,12 @@ abstract class DLCWallet case (dlc, None) => require( dlc.isInitiator, - s"We cannot register a DLCAccept if we are not the initiator, got $dlc") + s"We cannot register a DLCAccept if we are not the initiator, got $dlc" + ) logger.info( - s"DLC Offer contractId=${dlc.contractIdOpt.map(_.toHex)} dlcId=(${dlc.dlcId.hex}) found, adding accept data") + s"DLC Offer contractId=${dlc.contractIdOpt.map(_.toHex)} dlcId=(${dlc.dlcId.hex}) found, adding accept data" + ) val dlcId = dlc.dlcId lazy val dlcAcceptDb = DLCAcceptDbHelper.fromDLCAccept(dlcId, accept) @@ -930,8 +1037,10 @@ abstract class DLCWallet } lazy val acceptPrevTxs = accept.fundingInputs.map { funding => - TransactionDbHelper.fromTransaction(funding.prevTx, - blockHashOpt = None) + TransactionDbHelper.fromTransaction( + funding.prevTx, + blockHashOpt = None + ) } lazy val sigsDbs = accept.cetSigs.outcomeSigs.zipWithIndex.map { @@ -943,19 +1052,23 @@ abstract class DLCWallet DLCRefundSigsDb(dlcId, accept.refundSig, None) logger.info( - s"Verifying ${accept.cetSigs.outcomeSigs.size} CET Signatures") + s"Verifying ${accept.cetSigs.outcomeSigs.size} CET Signatures" + ) for { isCETSigsValidOpt <- verifyCETSigs(accept) _ = if (!(isCETSigsValidOpt.getOrElse(false))) throw new IllegalArgumentException( - s"CET sigs provided are not valid! got ${accept.cetSigs.outcomeSigs}") + s"CET sigs provided are not valid! got ${accept.cetSigs.outcomeSigs}" + ) isRefundSigValid <- verifyRefundSig(accept) _ = if (!(isRefundSigValid.getOrElse(false))) throw new IllegalArgumentException( - s"Refund sig provided is not valid! got ${accept.refundSig}") + s"Refund sig provided is not valid! got ${accept.refundSig}" + ) _ = logger.debug( - s"CET Signatures for tempContractId ${accept.tempContractId.hex} were valid, adding to database") + s"CET Signatures for tempContractId ${accept.tempContractId.hex} were valid, adding to database" + ) remoteTxUpsertAction = remoteTxDAO.upsertAllAction(acceptPrevTxs) inputAction = dlcInputsDAO.upsertAllAction(acceptInputs) @@ -964,11 +1077,14 @@ abstract class DLCWallet acceptDbAction = dlcAcceptDAO.upsertAction(dlcAcceptDb) actions = DBIO.sequence( - Vector(remoteTxUpsertAction, - inputAction, - sigsAction, - refundSigAction, - acceptDbAction)) + Vector( + remoteTxUpsertAction, + inputAction, + sigsAction, + refundSigAction, + acceptDbAction + ) + ) _ <- safeDLCDatabase.run(actions) // .get is safe here because we must have an offer if we have a dlcDAO @@ -982,24 +1098,29 @@ abstract class DLCWallet (announcements, announcementData, nonceDbs) <- dlcDataManagement .getDLCAnnouncementDbs(dlcId) - contractInfo = dlcDataManagement.getContractInfo(contractData, - announcements, - announcementData, - nonceDbs) + contractInfo = dlcDataManagement.getContractInfo( + contractData, + announcements, + announcementData, + nonceDbs + ) offer = offerDb.toDLCOffer( contractInfo, DLCTxUtil.matchPrevTxsWithInputs(offerInputs, prevTxs), dlc, - contractData) + contractData + ) dlcDb <- updateDLCContractIds(offer, accept) builder = DLCTxBuilder(offer, accept.withoutSigs) fundingTx = builder.buildFundingTx - outPoint = TransactionOutPoint(fundingTx.txId, - UInt32(builder.fundOutputIndex)) + outPoint = TransactionOutPoint( + fundingTx.txId, + UInt32(builder.fundOutputIndex) + ) spkDb = ScriptPubKeyDb(builder.fundingSPK) // only update spk db if we don't have it @@ -1012,11 +1133,13 @@ abstract class DLCWallet updatedDLCDb <- dlcDAO.update( dlcDb .updateState(DLCState.Accepted) - .updateFundingOutPoint(outPoint)) + .updateFundingOutPoint(outPoint) + ) } yield (updatedDLCDb, sigsDbs) case (dlc, Some(_)) => logger.info( - s"DLC Accept contractId=(${dlc.contractIdOpt.get.toHex}) dlcId=${dlc.dlcId.hex} has already been registered") + s"DLC Accept contractId=(${dlc.contractIdOpt.get.toHex}) dlcId=${dlc.dlcId.hex} has already been registered" + ) dlcSigsDAO .findByDLCId(dlc.dlcId) .map(sigOpt => (dlc, sigOpt)) @@ -1031,8 +1154,11 @@ abstract class DLCWallet dlcDb <- dlcDbOpt match { case Some(db) => Future.successful(db) case None => - Future.failed(new RuntimeException( - s"No DLC found with corresponding tempContractId ${tempId.hex}, this wallet did not create the corresponding offer")) + Future.failed( + new RuntimeException( + s"No DLC found with corresponding tempContractId ${tempId.hex}, this wallet did not create the corresponding offer" + ) + ) } contractInfo <- dlcDataManagement.getContractInfo(dlcDb.dlcId) @@ -1048,7 +1174,8 @@ abstract class DLCWallet */ override def signDLC(accept: DLCAccept): Future[DLCSign] = { logger.info( - s"Received accept message, tempContractId=${accept.tempContractId.hex}") + s"Received accept message, tempContractId=${accept.tempContractId.hex}" + ) for { (dlc, cetSigsDbs) <- registerDLCAccept(accept) // .get should be safe now @@ -1060,18 +1187,21 @@ abstract class DLCWallet dlcId = dlc.dlcId, transactionDAO = transactionDAO, fundingUtxoScriptSigParams = scriptSigParams, - keyManager = keyManager) + keyManager = keyManager + ) mySigs <- dlcSigsDAO.findByDLCId(dlc.dlcId) refundSigsDb <- dlcRefundSigDAO.findByDLCId(dlc.dlcId).map(_.head) cetSigsOpt <- { signerOpt match { case Some(signer) => - val cetSigsF = getCetSigs(signer = signer, - dlcDb = dlc, - contractId = contractId, - cetSigsDbs = cetSigsDbs, - mySigs = mySigs) + val cetSigsF = getCetSigs( + signer = signer, + dlcDb = dlc, + contractId = contractId, + cetSigsDbs = cetSigsDbs, + mySigs = mySigs + ) cetSigsF.map(Some(_)) case None => Future.successful(None) @@ -1096,7 +1226,8 @@ abstract class DLCWallet _ = require( fundingSigsOpt.isDefined, - s"Cannot sign a DLC message when we cannot generate funding signatures, dlcId=${dlcId}") + s"Cannot sign a DLC message when we cannot generate funding signatures, dlcId=${dlcId}" + ) fundingSigs = fundingSigsOpt.get cetSigs = cetSigsOpt.get sortedSigVec = inputDbs.sortBy(_.index).map { db => @@ -1114,12 +1245,15 @@ abstract class DLCWallet _ <- dlcConfig.walletCallbacks.executeOnDLCStateChange(status.get) } yield { logger.info( - s"Done creating sign message with contractId=${contractId.toHex} tempContractId=${dlc.tempContractId.hex}") - //?? is signer.signRefundTx persisted anywhere ?? - DLCSign(cetSigs, - signerOpt.map(_.signRefundTx).get, - FundingSignatures(sortedSigVec), - contractId) + s"Done creating sign message with contractId=${contractId.toHex} tempContractId=${dlc.tempContractId.hex}" + ) + // ?? is signer.signRefundTx persisted anywhere ?? + DLCSign( + cetSigs, + signerOpt.map(_.signRefundTx).get, + FundingSignatures(sortedSigVec), + contractId + ) } } @@ -1128,7 +1262,8 @@ abstract class DLCWallet dlcDb: DLCDb, contractId: ByteVector, cetSigsDbs: Vector[DLCCETSignaturesDb], - mySigs: Vector[DLCCETSignaturesDb]): Future[CETSignatures] = { + mySigs: Vector[DLCCETSignaturesDb] + ): Future[CETSignatures] = { if (mySigs.forall(_.initiatorSig.isEmpty)) { logger.info(s"Creating CET Sigs for contract ${contractId.toHex}") val dlcDbSignComputingAdaptorSigs = @@ -1159,8 +1294,8 @@ abstract class DLCWallet } } - /** Verify CET sigs for the given accept message if it exists - * If it doesnt not exist, return None + /** Verify CET sigs for the given accept message if it exists If it doesnt not + * exist, return None */ def verifyCETSigs(accept: DLCAccept): Future[Option[Boolean]] = { val verifierAcceptOptF = @@ -1174,8 +1309,8 @@ abstract class DLCWallet } } - /** Verify CET sigs for the given sign message if it exists - * If it doesnt not exist, return None + /** Verify CET sigs for the given sign message if it exists If it doesnt not + * exist, return None */ def verifyCETSigs(sign: DLCSign): Future[Option[Boolean]] = { val verifierF = @@ -1203,7 +1338,8 @@ abstract class DLCWallet def verifyRefundSig(sign: DLCSign): Future[Option[Boolean]] = { val verifierOptF = dlcDataManagement.verifierFromDb( contractId = sign.contractId, - transactionDAO = transactionDAO) + transactionDAO = transactionDAO + ) verifierOptF.map { case Some(verifier) => val bool = verifier.verifyRefundSig(sign.refundSig) @@ -1215,11 +1351,13 @@ abstract class DLCWallet def verifyFundingSigs( inputs: Vector[DLCFundingInputDb], - sign: DLCSign): Future[Option[Boolean]] = { + sign: DLCSign + ): Future[Option[Boolean]] = { if (inputs.count(_.isInitiator) == sign.fundingSigs.length) { val verifierOptF = dlcDataManagement.verifierFromDb( contractId = sign.contractId, - transactionDAO = transactionDAO) + transactionDAO = transactionDAO + ) verifierOptF.map { case Some(verifier) => val bool = verifier.verifyRemoteFundingSigs(sign.fundingSigs) @@ -1229,13 +1367,14 @@ abstract class DLCWallet } } else { logger.info( - "Funding Signatures provided did not have the correct amount of inputs") + "Funding Signatures provided did not have the correct amount of inputs" + ) Future.successful(Some(false)) } } - /** Takes a DLCSign an inserts the funding signatures into the database - * This is the only way one should insert sigs to the database + /** Takes a DLCSign an inserts the funding signatures into the database This + * is the only way one should insert sigs to the database */ def addFundingSigs(sign: DLCSign): Future[Vector[DLCFundingInputDb]] = { for { @@ -1243,12 +1382,16 @@ abstract class DLCWallet inputs <- dlcInputsDAO.findByDLCId(dlc.dlcId).map(_.sortBy(_.index)) _ = logger.info( - s"Verifying ${sign.fundingSigs.length} funding sigs for contract ${sign.contractId.toHex}") + s"Verifying ${sign.fundingSigs.length} funding sigs for contract ${sign.contractId.toHex}" + ) isValidOpt <- verifyFundingSigs(inputs = inputs, sign = sign) _ <- { if (!(isValidOpt.getOrElse(false))) - Future.failed(new IllegalArgumentException( - s"Funding Signatures provided are not valid! got ${sign.fundingSigs}")) + Future.failed( + new IllegalArgumentException( + s"Funding Signatures provided are not valid! got ${sign.fundingSigs}" + ) + ) else FutureUtil.unit } @@ -1258,7 +1401,8 @@ abstract class DLCWallet inputDb.copy(witnessScriptOpt = Some(witness)) case None => throw new NoSuchElementException( - s"Received signature for outPoint (${outPoint.hex}) that does not correspond to this contractId (${sign.contractId.toHex})") + s"Received signature for outPoint (${outPoint.hex}) that does not correspond to this contractId (${sign.contractId.toHex})" + ) } } written <- dlcInputsDAO.upsertAll(updatedInputs.toVector) @@ -1275,8 +1419,11 @@ abstract class DLCWallet require(!db.isInitiator, "Cannot add DLC sigs as initiator") Future.successful(db) case None => - Future.failed(new RuntimeException( - s"No DLC found with corresponding contractId ${contractId.toHex}")) + Future.failed( + new RuntimeException( + s"No DLC found with corresponding contractId ${contractId.toHex}" + ) + ) } builderOpt <- dlcDataManagement.builderFromDbData( dlcDb = dlcDb, @@ -1285,7 +1432,8 @@ abstract class DLCWallet _ = require( builderOpt.isDefined, - s"Cannot add DLC sigs when the builder is not defined, dlcId=${dlcDb.dlcId.hex}") + s"Cannot add DLC sigs when the builder is not defined, dlcId=${dlcDb.dlcId.hex}" + ) builder = builderOpt.get sign = DLCSign.fromTLV(signTLV, builder.offer) result <- addDLCSigs(sign) @@ -1304,30 +1452,36 @@ abstract class DLCWallet case Offered => Future.failed( new RuntimeException( - "Cannot add sigs to a DLC before it has been accepted")) + "Cannot add sigs to a DLC before it has been accepted" + ) + ) case _: AdaptorSigComputationState => val err = new RuntimeException( - s"Cannot add sigs to a DLC while adaptor sigs are being computed, contractId=${sign.contractId.toHex}") + s"Cannot add sigs to a DLC while adaptor sigs are being computed, contractId=${sign.contractId.toHex}" + ) Future.failed(err) case Accepted => logger.info( - s"Verifying CET Signatures for contract ${sign.contractId.toHex}") + s"Verifying CET Signatures for contract ${sign.contractId.toHex}" + ) for { isRefundSigValid <- verifyRefundSig(sign) _ = if (!(isRefundSigValid.getOrElse(false))) throw new IllegalArgumentException( - s"Refund sig provided is not valid! got ${sign.refundSig}") + s"Refund sig provided is not valid! got ${sign.refundSig}" + ) isCETSigsValid <- verifyCETSigs(sign) _ = if (!(isCETSigsValid.getOrElse(false))) throw new IllegalArgumentException( - s"CET sigs provided are not valid! got ${sign.cetSigs.outcomeSigs}") + s"CET sigs provided are not valid! got ${sign.cetSigs.outcomeSigs}" + ) refundSigsDb <- dlcRefundSigDAO.findByDLCId(dlc.dlcId).map(_.head) sigsDbs <- dlcSigsDAO.findByDLCId(dlc.dlcId) - updatedRefund = refundSigsDb.copy(initiatorSig = - Some(sign.refundSig)) + updatedRefund = refundSigsDb + .copy(initiatorSig = Some(sign.refundSig)) updatedSigsDbs = sigsDbs .sortBy(_.index) .zip(sign.cetSigs.outcomeSigs) @@ -1336,38 +1490,46 @@ abstract class DLCWallet } _ = logger.info( - s"CET Signatures are valid for contract ${sign.contractId.toHex}") + s"CET Signatures are valid for contract ${sign.contractId.toHex}" + ) _ <- addFundingSigs(sign) _ <- dlcSigsDAO.updateAll(updatedSigsDbs) _ <- dlcRefundSigDAO.update(updatedRefund) updated <- dlcDAO.update(dlc.updateState(DLCState.Signed)) _ = logger.info( - s"DLC ${sign.contractId.toHex} sigs are verified and stored, ready to broadcast") + s"DLC ${sign.contractId.toHex} sigs are verified and stored, ready to broadcast" + ) } yield updated case _: DLCState.ClosedState | Broadcasted | Confirmed | Signed => logger.info( - s"DLC sigs already added for ${sign.contractId.toHex}, skipping..") + s"DLC sigs already added for ${sign.contractId.toHex}, skipping.." + ) Future.successful(dlc) } case None => - Future.failed(new NoSuchElementException( - s"No DLC found with corresponding contractId ${sign.contractId.toHex}")) + Future.failed( + new NoSuchElementException( + s"No DLC found with corresponding contractId ${sign.contractId.toHex}" + ) + ) } } private[wallet] def getScriptSigParams( dlcDb: DLCDb, - fundingInputs: Vector[DLCFundingInputDb]): Future[ - Vector[ScriptSignatureParams[InputInfo]]] = { + fundingInputs: Vector[DLCFundingInputDb] + ): Future[Vector[ScriptSignatureParams[InputInfo]]] = { val outPoints = fundingInputs.filter(_.isInitiator == dlcDb.isInitiator).map(_.outPoint) val utxosF = listUtxos(outPoints) for { utxos <- utxosF scriptSigParams <- - FutureUtil.foldLeftAsync(Vector.empty[ScriptSignatureParams[InputInfo]], - utxos) { (accum, utxo) => + FutureUtil.foldLeftAsync( + Vector.empty[ScriptSignatureParams[InputInfo]], + utxos + ) { (accum, utxo) => transactionDAO .findByOutPoint(utxo.outPoint) .map(txOpt => @@ -1378,19 +1540,21 @@ abstract class DLCWallet override def getDLCFundingTx(contractId: ByteVector): Future[Transaction] = { for { - setupStateOpt <- dlcDataManagement.getDLCFundingData(contractId, - txDAO = - transactionDAO) + setupStateOpt <- dlcDataManagement.getDLCFundingData( + contractId, + txDAO = transactionDAO + ) complete = { setupStateOpt.map { case _: OfferedDbState => sys.error( - s"Cannot retrieve funding transaction when DLC is in offered state") + s"Cannot retrieve funding transaction when DLC is in offered state" + ) case complete: SetupCompleteDLCDbState => complete - }.get //bad but going to have to save this refactor for future + }.get // bad but going to have to save this refactor for future } dlcDb = complete.dlcDb - //is this right? We don't have counterpart scriptSigParams + // is this right? We don't have counterpart scriptSigParams fundingInputs = complete.allFundingInputs scriptSigParams <- getScriptSigParams(dlcDb, fundingInputs) signerOpt <- dlcDataManagement.signerFromDb( @@ -1401,7 +1565,8 @@ abstract class DLCWallet ) _ = require( signerOpt.isDefined, - s"Cannot get dlc funding tx when signerOpt isn't defined, dlcId=${dlcDb.dlcId.hex}") + s"Cannot get dlc funding tx when signerOpt isn't defined, dlcId=${dlcDb.dlcId.hex}" + ) signer = signerOpt.get fundingTx <- if (dlcDb.isInitiator) { @@ -1420,11 +1585,13 @@ abstract class DLCWallet witnessScript match { case EmptyScriptWitness => throw new RuntimeException( - "Script witness cannot be empty") + "Script witness cannot be empty" + ) case witness: ScriptWitnessV0 => (input.outPoint, witness) case _: TaprootWitness => throw new UnsupportedOperationException( - s"Taproot not implemented") + s"Taproot not implemented" + ) } case None => throw new RuntimeException("") } @@ -1433,12 +1600,14 @@ abstract class DLCWallet } } _ = logger.info( - s"Created funding transaction ${fundingTx.txIdBE.hex} for contract ${contractId.toHex}") + s"Created funding transaction ${fundingTx.txIdBE.hex} for contract ${contractId.toHex}" + ) } yield fundingTx } override def broadcastDLCFundingTx( - contractId: ByteVector): Future[Transaction] = { + contractId: ByteVector + ): Future[Transaction] = { logger.info(s"broadcasting $contractId") val dlcDbOptF = dlcDAO.findByContractId(contractId) val fundingTxF = getDLCFundingTx(contractId) @@ -1447,25 +1616,27 @@ abstract class DLCWallet _ = dlcDbOpt match { case None => sys.error( - s"Cannot broadcast DLC when we don't know the contract, given contractId=${contractId}") + s"Cannot broadcast DLC when we don't know the contract, given contractId=${contractId}" + ) case Some(dlcDb) => isValidBroadcastState(dlcDb) } tx <- fundingTxF _ <- updateDLCState(contractId, DLCState.Broadcasted) _ = logger.info( - s"Broadcasting funding transaction ${tx.txIdBE.hex} for contract ${contractId.toHex}") + s"Broadcasting funding transaction ${tx.txIdBE.hex} for contract ${contractId.toHex}" + ) _ <- broadcastTransaction(tx) _ = logger.info(s"Done broadcast tx ${contractId}") } yield tx } - /** Checks if the DLC is in a valid state to broadcast the funding tx. - * This is particurarily useful for situations when users want to - * re-broadcast funding txs. You should only be able to re-broadcast - * a funding tx in two states, [[DLCState.Signed]] or [[DLCState.Broadcasted]] - * The reason accepted is needed is that is the state the DLC is in - * when a user gives us their sign message + /** Checks if the DLC is in a valid state to broadcast the funding tx. This is + * particurarily useful for situations when users want to re-broadcast + * funding txs. You should only be able to re-broadcast a funding tx in two + * states, [[DLCState.Signed]] or [[DLCState.Broadcasted]] The reason + * accepted is needed is that is the state the DLC is in when a user gives us + * their sign message */ private def isValidBroadcastState(dlcDb: DLCDb): DLCDb = { dlcDb.state match { @@ -1474,15 +1645,18 @@ abstract class DLCWallet DLCState.Claimed | DLCState.RemoteClaimed | DLCState.Refunded | _: DLCState.AdaptorSigComputationState) => sys.error( - s"Cannot broadcast the dlc when it is in the state=${state} contractId=${dlcDb.contractIdOpt}") + s"Cannot broadcast the dlc when it is in the state=${state} contractId=${dlcDb.contractIdOpt}" + ) } } override def executeDLC( contractId: ByteVector, - sigs: Seq[OracleAttestmentTLV]): Future[Option[Transaction]] = { + sigs: Seq[OracleAttestmentTLV] + ): Future[Option[Transaction]] = { logger.info( - s"Executing dlc with contractId=${contractId.toHex} sigs=${sigs.map(_.hex)}") + s"Executing dlc with contractId=${contractId.toHex} sigs=${sigs.map(_.hex)}" + ) require(sigs.nonEmpty, "Must provide at least one oracle signature") val dlcDbOpt = dlcDAO.findByContractId(contractId) for { @@ -1501,14 +1675,16 @@ abstract class DLCWallet def executeDLC( dlcDb: DLCDb, - sigs: Seq[OracleAttestmentTLV]): Future[Option[Transaction]] = { + sigs: Seq[OracleAttestmentTLV] + ): Future[Option[Transaction]] = { val _ = dlcDb.state match { case state @ (Offered | AcceptComputingAdaptorSigs | Accepted | SignComputingAdaptorSigs | Signed) => sys.error( - s"Cannot execute DLC before the DLC is broadcast to the blockchain, state=$state") + s"Cannot execute DLC before the DLC is broadcast to the blockchain, state=$state" + ) case Broadcasted | Confirmed | _: ClosedState => - //can continue executing, do nothing + // can continue executing, do nothing } for { (announcements, announcementData, nonceDbs) <- dlcDataManagement @@ -1517,11 +1693,13 @@ abstract class DLCWallet announcementTLVs = dlcDataManagement.getOracleAnnouncements( announcements, announcementData, - nonceDbs) + nonceDbs + ) oracleSigs = DLCUtil.buildOracleSignaturesNaive( announcements = announcementTLVs, - attestments = sigs.toVector) + attestments = sigs.toVector + ) tx <- executeDLC(dlcDb.contractIdOpt.get, oracleSigs) } yield tx @@ -1529,13 +1707,16 @@ abstract class DLCWallet override def executeDLC( contractId: ByteVector, - oracleSigs: Vector[OracleSignatures]): Future[Option[Transaction]] = { + oracleSigs: Vector[OracleSignatures] + ): Future[Option[Transaction]] = { require(oracleSigs.nonEmpty, "Must provide at least one oracle signature") dlcDAO.findByContractId(contractId).flatMap { case None => Future.failed( new IllegalArgumentException( - s"No DLC found with contractId $contractId")) + s"No DLC found with contractId $contractId" + ) + ) case Some(db) => db.closingTxIdOpt match { case Some(txId) => @@ -1549,13 +1730,14 @@ abstract class DLCWallet } } - /** Returns a execution transaction if we can build one. Returns None - * if the dlc db state is incorrect, or we have pruned CET signatures - * from the database + /** Returns a execution transaction if we can build one. Returns None if the + * dlc db state is incorrect, or we have pruned CET signatures from the + * database */ private def createDLCExecutionTx( contractId: ByteVector, - oracleSigs: Vector[OracleSignatures]): Future[Option[Transaction]] = { + oracleSigs: Vector[OracleSignatures] + ): Future[Option[Transaction]] = { require(oracleSigs.nonEmpty, "Must provide at least one oracle signature") val setupStateOptF = dlcDataManagement.getDLCFundingData(contractId, txDAO = transactionDAO) @@ -1565,7 +1747,8 @@ abstract class DLCWallet setupDbState match { case o: OfferedDbState => logger.info( - s"Cannot create execution tx for dlc in state=${o.state}") + s"Cannot create execution tx for dlc in state=${o.state}" + ) Future.successful(None) case c: SetupCompleteDLCDbState => val dlcDb = c.dlcDb @@ -1577,25 +1760,29 @@ abstract class DLCWallet contractId = contractId, txDAO = transactionDAO, fundingUtxoScriptSigParams = scriptSigParams, - keyManager = keyManager) + keyManager = keyManager + ) } executorWithSetupOptF.flatMap { case Some(executorWithSetup) => - buildExecutionTxWithExecutor(executorWithSetup, - oracleSigs, - contractId).map(Some(_)) + buildExecutionTxWithExecutor( + executorWithSetup, + oracleSigs, + contractId + ).map(Some(_)) case None => - //means we don't have cet sigs in the db anymore - //can we retrieve the CET some other way? + // means we don't have cet sigs in the db anymore + // can we retrieve the CET some other way? - //lets try to retrieve it from our transactionDAO + // lets try to retrieve it from our transactionDAO val dlcDbOptF = dlcDAO.findByContractId(contractId) for { dlcDbOpt <- dlcDbOptF _ = require( dlcDbOpt.isDefined, - s"Could not find dlc associated with this contractId=${contractId.toHex}") + s"Could not find dlc associated with this contractId=${contractId.toHex}" + ) dlcDb = dlcDbOpt.get _ = require( dlcDb.closingTxIdOpt.isDefined, @@ -1606,7 +1793,8 @@ abstract class DLCWallet } yield { require( closingTxOpt.isDefined, - s"Could not find closing tx for DLC in db, contactId=${contractId.toHex} closingTxId=${closingTxId.hex}") + s"Could not find closing tx for DLC in db, contactId=${contractId.toHex} closingTxId=${closingTxId.hex}" + ) Some(closingTxOpt.get.transaction) } } @@ -1617,14 +1805,16 @@ abstract class DLCWallet private def buildExecutionTxWithExecutor( executorWithSetup: DLCExecutorWithSetup, oracleSigs: Vector[OracleSignatures], - contractId: ByteVector): Future[Transaction] = { + contractId: ByteVector + ): Future[Transaction] = { val executor = executorWithSetup.executor val setup = executorWithSetup.setup val executed = executor.executeDLC(setup, oracleSigs) val (tx, outcome, sigsUsed) = (executed.cet, executed.outcome, executed.sigsUsed) logger.info( - s"Created DLC execution transaction ${tx.txIdBE.hex} for contract ${contractId.toHex}") + s"Created DLC execution transaction ${tx.txIdBE.hex} for contract ${contractId.toHex}" + ) for { _ <- updateDLCOracleSigs(sigsUsed) @@ -1633,8 +1823,10 @@ abstract class DLCWallet oracleSigSum = OracleSignatures.computeAggregateSignature(outcome, sigsUsed) - aggSig = SchnorrDigitalSignature(outcome.aggregateNonce, - oracleSigSum.fieldElement) + aggSig = SchnorrDigitalSignature( + outcome.aggregateNonce, + oracleSigSum.fieldElement + ) _ <- updateAggregateSignature(contractId, aggSig) _ <- processTransaction(tx, None) @@ -1648,8 +1840,10 @@ abstract class DLCWallet dlcDbOpt <- dlcDAO.findByContractId(contractId) dlcDb = dlcDbOpt.get offerDbOpt <- dlcOfferDAO.findByDLCId(dlcDb.dlcId) - _ = require(offerDbOpt.nonEmpty, - s"Invalid DLC $dlcDb.dlcId: no offer data") + _ = require( + offerDbOpt.nonEmpty, + s"Invalid DLC $dlcDb.dlcId: no offer data" + ) contractData <- contractDataDAO.read(dlcDb.dlcId).map(_.get) currentHeight <- chainQueryApi.getBestHashBlockHeight() @@ -1657,23 +1851,28 @@ abstract class DLCWallet case BlockStamp.BlockHeight(height) => require( currentHeight >= height, - s"Refund transaction is not valid yet, current height: $currentHeight, refund valid at height $height") + s"Refund transaction is not valid yet, current height: $currentHeight, refund valid at height $height" + ) case BlockStamp.BlockTime(time) => val currentTime = TimeUtil.currentEpochSecond require( currentTime >= time.toLong, - s"Refund transaction is not valid yet, current time: $currentTime, refund valid at time $time") + s"Refund transaction is not valid yet, current time: $currentTime, refund valid at time $time" + ) } fundingInputs <- dlcInputsDAO.findByDLCId(dlcDb.dlcId) scriptSigParams <- getScriptSigParams(dlcDb, fundingInputs) - executorOpt <- dlcDataManagement.executorFromDb(dlcDb.dlcId, - transactionDAO, - scriptSigParams, - keyManager) + executorOpt <- dlcDataManagement.executorFromDb( + dlcDb.dlcId, + transactionDAO, + scriptSigParams, + keyManager + ) _ = require( executorOpt.isDefined, - s"Cannot execute refund transaction when the executor isn't defined, dlcId=${dlcDb.dlcId.hex}") + s"Cannot execute refund transaction when the executor isn't defined, dlcId=${dlcDb.dlcId.hex}" + ) executor = executorOpt.get refundSigsDbOpt <- dlcRefundSigDAO.findByDLCId(dlcDb.dlcId) @@ -1683,7 +1882,8 @@ abstract class DLCWallet refundTx = executor.executeRefundDLC(refundSig).refundTx _ = logger.info( - s"Created DLC refund transaction ${refundTx.txIdBE.hex} for contract ${contractId.toHex}") + s"Created DLC refund transaction ${refundTx.txIdBE.hex} for contract ${contractId.toHex}" + ) _ <- updateDLCState(contractId, DLCState.Refunded) _ <- updateClosingTxId(contractId, refundTx.txIdBE) @@ -1700,7 +1900,7 @@ abstract class DLCWallet dlcs <- dlcsF closed = dlcs.collect { case c: ClaimedDLCStatus => c - } //only get claimed dlcs for accounting + } // only get claimed dlcs for accounting accountings = closed.map(_.accounting) walletAccounting = DLCWalletAccounting.fromDLCAccounting(accountings) } yield walletAccounting @@ -1725,34 +1925,38 @@ abstract class DLCWallet } override def listDLCsByContact( - contactId: InetSocketAddress): Future[Vector[DLCStatus]] = { + contactId: InetSocketAddress + ): Future[Vector[DLCStatus]] = { listDLCs(Some(contactId)) } private def listDLCs( - contactIdOpt: Option[InetSocketAddress]): Future[Vector[DLCStatus]] = { - val dlcAction: DBIOAction[ - Vector[IntermediaryDLCStatus], - NoStream, - Effect.Read] = for { - dlcs <- contactIdOpt match { - case Some(contactId) => - dlcDAO.findByContactIdAction( - contactId.getHostString + ":" + contactId.getPort) - case None => dlcDAO.findAllAction() + contactIdOpt: Option[InetSocketAddress] + ): Future[Vector[DLCStatus]] = { + val dlcAction + : DBIOAction[Vector[IntermediaryDLCStatus], NoStream, Effect.Read] = + for { + dlcs <- contactIdOpt match { + case Some(contactId) => + dlcDAO.findByContactIdAction( + contactId.getHostString + ":" + contactId.getPort + ) + case None => dlcDAO.findAllAction() + } + dlcsResult <- findDLCStatusesAction(dlcs) + } yield { + dlcsResult } - dlcsResult <- findDLCStatusesAction(dlcs) - } yield { - dlcsResult - } fetchWalletDbInfo(dlcAction) } private def fetchWalletDbInfo( - dlcAction: DBIOAction[ - Vector[IntermediaryDLCStatus], - NoStream, - Effect.Read]): Future[Vector[DLCStatus]] = { + dlcAction: DBIOAction[Vector[ + IntermediaryDLCStatus + ], + NoStream, + Effect.Read] + ): Future[Vector[DLCStatus]] = { safeDLCDatabase.run(dlcAction).flatMap { intermediaries => val actions = intermediaries.map { intermediary => getWalletDLCDbsAction(intermediary).map { @@ -1764,10 +1968,9 @@ abstract class DLCWallet } } - private def getClosingTxOptAction(dlcDb: DLCDb): DBIOAction[ - Option[TransactionDb], - NoStream, - Effect.Read] = { + private def getClosingTxOptAction( + dlcDb: DLCDb + ): DBIOAction[Option[TransactionDb], NoStream, Effect.Read] = { dlcDb.closingTxIdOpt match { case None => DBIOAction.successful(None) case Some(txid) => transactionDAO.findByTxIdAction(txid) @@ -1778,7 +1981,8 @@ abstract class DLCWallet dlcDataManagement.getOffer(dlcId, transactionDAO) override def findDLCByTemporaryContractId( - tempContractId: Sha256Digest): Future[Option[DLCStatus]] = { + tempContractId: Sha256Digest + ): Future[Option[DLCStatus]] = { val start = System.currentTimeMillis() val dlcOptF = for { @@ -1792,7 +1996,8 @@ abstract class DLCWallet dlcOptF.foreach(_ => logger.debug( s"Done finding tempContractId=$tempContractId, it took=${System - .currentTimeMillis() - start}ms")) + .currentTimeMillis() - start}ms" + )) dlcOptF } @@ -1814,23 +2019,23 @@ abstract class DLCWallet val dlcDb = intermediary.dlcDb for { closingTxOpt <- getClosingTxOptAction(dlcDb) - payoutAddress <- getPayoutAddressAction(dlcDb, - intermediary.offerDb, - intermediary.acceptDbOpt) + payoutAddress <- getPayoutAddressAction( + dlcDb, + intermediary.offerDb, + intermediary.acceptDbOpt + ) } yield (closingTxOpt, payoutAddress) } - private def findDLCAction(dlcDb: DLCDb): DBIOAction[ - Option[IntermediaryDLCStatus], - NoStream, - Effect.Read] = { + private def findDLCAction( + dlcDb: DLCDb + ): DBIOAction[Option[IntermediaryDLCStatus], NoStream, Effect.Read] = { findDLCStatusAction(dlcDb) } - private def findDLCAction(dlcId: Sha256Digest): DBIOAction[ - Option[IntermediaryDLCStatus], - NoStream, - Effect.Read] = { + private def findDLCAction( + dlcId: Sha256Digest + ): DBIOAction[Option[IntermediaryDLCStatus], NoStream, Effect.Read] = { val start = System.currentTimeMillis() val dlcOptA = for { @@ -1843,7 +2048,8 @@ abstract class DLCWallet dlcOptA.map { res => logger.debug( - s"Done finding dlc=$dlcId, it took=${System.currentTimeMillis() - start}ms") + s"Done finding dlc=$dlcId, it took=${System.currentTimeMillis() - start}ms" + ) res } } @@ -1853,29 +2059,29 @@ abstract class DLCWallet import mappers._ - private def findDLCStatusAction(dlcDb: DLCDb): DBIOAction[ - Option[IntermediaryDLCStatus], - NoStream, - Effect.Read] = { + private def findDLCStatusAction( + dlcDb: DLCDb + ): DBIOAction[Option[IntermediaryDLCStatus], NoStream, Effect.Read] = { findDLCStatusesAction(Vector(dlcDb)) .map(_.headOption) } - private def findDLCStatusesAction(dlcDbs: Vector[DLCDb]): DBIOAction[ - Vector[IntermediaryDLCStatus], - NoStream, - Effect.Read] = { + private def findDLCStatusesAction( + dlcDbs: Vector[DLCDb] + ): DBIOAction[Vector[IntermediaryDLCStatus], NoStream, Effect.Read] = { val dlcIds = dlcDbs.map(_.dlcId) val contractDbsQ = contractDataDAO.findByPrimaryKeys(dlcIds) val offerDbsQ = dlcOfferDAO.findByPrimaryKeys(dlcIds) val acceptDbsQ = dlcAcceptDAO.findByPrimaryKeys(dlcIds) - //optimization to use sql queries rather than action - //as this method gets called a lot. - val offerAndContractA: DBIOAction[ - Vector[((DLCOfferDb, DLCContractDataDb), Option[DLCAcceptDb])], - NoStream, - Effect.Read] = { + // optimization to use sql queries rather than action + // as this method gets called a lot. + val offerAndContractA + : DBIOAction[Vector[ + ((DLCOfferDb, DLCContractDataDb), Option[DLCAcceptDb]) + ], + NoStream, + Effect.Read] = { offerDbsQ .join(contractDbsQ) .on(_.dlcId === _.dlcId) @@ -1888,22 +2094,24 @@ abstract class DLCWallet val dlcDlbIds: Map[Sha256Digest, DLCDb] = dlcDbs.map(d => (d.dlcId, d)).toMap - val retval: DBIOAction[ - Vector[IntermediaryDLCStatus], - NoStream, - Effect.Read] = for { - offerAndContractDbs <- offerAndContractA - result = { - offerAndContractDbs.map { case ((offerDb, contractData), acceptDbOpt) => - val dlcId = offerDb.dlcId - buildDLCStatusAction(dlcDlbIds(dlcId), - contractData, - offerDb, - acceptDbOpt) + val retval + : DBIOAction[Vector[IntermediaryDLCStatus], NoStream, Effect.Read] = + for { + offerAndContractDbs <- offerAndContractA + result = { + offerAndContractDbs.map { + case ((offerDb, contractData), acceptDbOpt) => + val dlcId = offerDb.dlcId + buildDLCStatusAction( + dlcDlbIds(dlcId), + contractData, + offerDb, + acceptDbOpt + ) + } } - } - seq <- DBIOAction.sequence(result).map(_.flatten) - } yield seq + seq <- DBIOAction.sequence(result).map(_.flatten) + } yield seq retval } @@ -1913,24 +2121,26 @@ abstract class DLCWallet dlcDb: DLCDb, contractData: DLCContractDataDb, offerDb: DLCOfferDb, - acceptDbOpt: Option[DLCAcceptDb]): DBIOAction[ - Option[IntermediaryDLCStatus], - NoStream, - Effect.Read] = { + acceptDbOpt: Option[DLCAcceptDb] + ): DBIOAction[Option[IntermediaryDLCStatus], NoStream, Effect.Read] = { val dlcId = dlcDb.dlcId val aggregatedA = dlcDataManagement.getDLCAnnouncementDbsAction(dlcId) val contractInfoAndAnnouncementsA = { aggregatedA.map { case (announcements, announcementData, nonceDbs) => - val contractInfo = dlcDataManagement.getContractInfo(contractData, - announcements, - announcementData, - nonceDbs) + val contractInfo = dlcDataManagement.getContractInfo( + contractData, + announcements, + announcementData, + nonceDbs + ) val announcementsWithId = - dlcDataManagement.getOracleAnnouncementsWithId(announcements, - announcementData, - nonceDbs) + dlcDataManagement.getOracleAnnouncementsWithId( + announcements, + announcementData, + nonceDbs + ) (contractInfo, announcementsWithId) } } @@ -1938,14 +2148,16 @@ abstract class DLCWallet val statusA = for { (contractInfo, announcementsWithId) <- contractInfoAndAnnouncementsA (announcementIds, _, nonceDbs) <- aggregatedA - } yield IntermediaryDLCStatus(dlcDb, - contractInfo, - contractData, - offerDb, - acceptDbOpt, - nonceDbs, - announcementsWithId, - announcementIds) + } yield IntermediaryDLCStatus( + dlcDb, + contractInfo, + contractData, + offerDb, + acceptDbOpt, + nonceDbs, + announcementsWithId, + announcementIds + ) statusA.map(Some(_)) } @@ -1953,10 +2165,8 @@ abstract class DLCWallet private def getPayoutAddressAction( dlcDb: DLCDb, offerDb: DLCOfferDb, - acceptDbOpt: Option[DLCAcceptDb]): DBIOAction[ - Option[PayoutAddress], - NoStream, - Effect.Read] = { + acceptDbOpt: Option[DLCAcceptDb] + ): DBIOAction[Option[PayoutAddress], NoStream, Effect.Read] = { val addressOpt = if (dlcDb.isInitiator) { Some(offerDb.payoutAddress) } else { @@ -1971,27 +2181,33 @@ abstract class DLCWallet } } - /** @param newAnnouncements announcements we do not have in our db - * @param existingAnnouncements announcements we already have in our db + /** @param newAnnouncements + * announcements we do not have in our db + * @param existingAnnouncements + * announcements we already have in our db */ private case class AnnouncementGrouping( newAnnouncements: Vector[OracleAnnouncementDataDb], - existingAnnouncements: Vector[OracleAnnouncementDataDb]) { + existingAnnouncements: Vector[OracleAnnouncementDataDb] + ) { require(existingAnnouncements.forall(_.id.isDefined)) - require(newAnnouncements.forall(_.id.isEmpty), - s"announcmeent had id defined=${newAnnouncements.map(_.id)}") + require( + newAnnouncements.forall(_.id.isEmpty), + s"announcmeent had id defined=${newAnnouncements.map(_.id)}" + ) } - /** This is needed because our upserts do not work - * we need to filter announcements we already have in the database - * to avoid issues below - * @see https://github.com/bitcoin-s/bitcoin-s/issues/1623 - * @see https://github.com/bitcoin-s/bitcoin-s/issues/3127 + /** This is needed because our upserts do not work we need to filter + * announcements we already have in the database to avoid issues below + * @see + * https://github.com/bitcoin-s/bitcoin-s/issues/1623 + * @see + * https://github.com/bitcoin-s/bitcoin-s/issues/3127 * @param announcementDataDbs */ private def groupByExistingAnnouncements( - announcementTLVs: Vector[OracleAnnouncementTLV]): Future[ - AnnouncementGrouping] = { + announcementTLVs: Vector[OracleAnnouncementTLV] + ): Future[AnnouncementGrouping] = { val announcementSignatures: Vector[SchnorrDigitalSignature] = { announcementTLVs.map(a => a.announcementSignature) @@ -2005,13 +2221,16 @@ abstract class DLCWallet existingAnnouncementsDb <- existingAnnouncementsInDbF newAnnouncements = announcementTLVs.filterNot(a => existingAnnouncementsDb.exists( - _.announcementSignature == a.announcementSignature)) + _.announcementSignature == a.announcementSignature + )) } yield { val newAnnouncementsDb = OracleAnnouncementDbHelper.fromAnnouncements(newAnnouncements) - AnnouncementGrouping(newAnnouncements = newAnnouncementsDb, - existingAnnouncements = existingAnnouncementsDb) + AnnouncementGrouping( + newAnnouncements = newAnnouncementsDb, + existingAnnouncements = existingAnnouncementsDb + ) } } } @@ -2036,9 +2255,8 @@ object DLCWallet extends WalletLogger { def apply( nodeApi: NodeApi, chainQueryApi: ChainQueryApi, - feeRateApi: FeeRateApi)(implicit - config: WalletAppConfig, - dlcConfig: DLCAppConfig): DLCWallet = { + feeRateApi: FeeRateApi + )(implicit config: WalletAppConfig, dlcConfig: DLCAppConfig): DLCWallet = { DLCWalletImpl(nodeApi, chainQueryApi, feeRateApi) } @@ -2050,7 +2268,8 @@ object DLCWallet extends WalletLogger { def startAccepting(tempContractId: Sha256Digest): Unit = { if (tempContractIds.putIfAbsent(tempContractId, tempContractId) != null) { throw DuplicateOfferException( - s"Offer with temporary contract ID ${tempContractId.hex} is already being accepted") + s"Offer with temporary contract ID ${tempContractId.hex} is already being accepted" + ) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/accounting/DLCAccountingDbs.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/accounting/DLCAccountingDbs.scala index c2825e5cd7..c475afced8 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/accounting/DLCAccountingDbs.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/accounting/DLCAccountingDbs.scala @@ -8,11 +8,14 @@ case class DLCAccountingDbs( dlcDb: DLCDb, offerDb: DLCOfferDb, acceptDb: DLCAcceptDb, - closingTx: Transaction) { + closingTx: Transaction +) { require( dlcDb.dlcId == offerDb.dlcId, - s"dlcDb.dlcId not equal to offerDb.dlcId, got dlcDb.dlcId=${dlcDb.dlcId} offerDb.dlcId=${offerDb.dlcId}") + s"dlcDb.dlcId not equal to offerDb.dlcId, got dlcDb.dlcId=${dlcDb.dlcId} offerDb.dlcId=${offerDb.dlcId}" + ) require( offerDb.dlcId == acceptDb.dlcId, - s"OfferDb and acceptDb not the same offerDb.dlcId=${offerDb.dlcId}, acceptDb.dlcId=${acceptDb.dlcId}") + s"OfferDb and acceptDb not the same offerDb.dlcId=${offerDb.dlcId}, acceptDb.dlcId=${acceptDb.dlcId}" + ) } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/callback/DLCWalletCallbackStreamManager.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/callback/DLCWalletCallbackStreamManager.scala index 86a8f55862..1b967c5ba9 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/callback/DLCWalletCallbackStreamManager.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/callback/DLCWalletCallbackStreamManager.scala @@ -22,16 +22,16 @@ import scala.concurrent.Future case class DLCWalletCallbackStreamManager( callbacks: DLCWalletCallbacks, overflowStrategy: OverflowStrategy = OverflowStrategy.backpressure, - maxBufferSize: Int = 16)(implicit system: ActorSystem) + maxBufferSize: Int = 16 +)(implicit system: ActorSystem) extends DLCWalletCallbacks with StartStopAsync[Unit] with BitcoinSLogger { import system.dispatcher - private val stateChangeSource: Source[ - DLCStatus, - SourceQueueWithComplete[DLCStatus]] = { + private val stateChangeSource + : Source[DLCStatus, SourceQueueWithComplete[DLCStatus]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -45,9 +45,10 @@ case class DLCWalletCallbackStreamManager( matSourceAndQueue(stateChangeSource, stateChangeSink) } - private val offerAddSource: Source[ - IncomingDLCOfferDb, - SourceQueueWithComplete[IncomingDLCOfferDb]] = { + private val offerAddSource: Source[IncomingDLCOfferDb, + SourceQueueWithComplete[ + IncomingDLCOfferDb + ]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -61,9 +62,8 @@ case class DLCWalletCallbackStreamManager( matSourceAndQueue(offerAddSource, offerAddSink) } - private val offerRemoveSource: Source[ - Sha256Digest, - SourceQueueWithComplete[Sha256Digest]] = { + private val offerRemoveSource + : Source[Sha256Digest, SourceQueueWithComplete[Sha256Digest]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -81,15 +81,13 @@ case class DLCWalletCallbackStreamManager( callbacks.onStateChange } - override def onOfferAdd: CallbackHandler[ - IncomingDLCOfferDb, - OnDLCOfferAdd] = { + override def onOfferAdd + : CallbackHandler[IncomingDLCOfferDb, OnDLCOfferAdd] = { callbacks.onOfferAdd } - override def onOfferRemove: CallbackHandler[ - Sha256Digest, - OnDLCOfferRemove] = { + override def onOfferRemove + : CallbackHandler[Sha256Digest, OnDLCOfferRemove] = { callbacks.onOfferRemove } @@ -106,16 +104,17 @@ case class DLCWalletCallbackStreamManager( override def stop(): Future[Unit] = { val start = System.currentTimeMillis() - //can't complete a stream twice + // can't complete a stream twice if (!isStopped.get()) { - //complete all queues + // complete all queues offerAddQueue.complete() offerRemoveQueue.complete() stateChangeQueue.complete() isStopped.set(true) } else { logger.warn( - s"Already stopped all queues associated with this DLCWalletCallbackManagerStream") + s"Already stopped all queues associated with this DLCWalletCallbackManagerStream" + ) } for { @@ -125,16 +124,16 @@ case class DLCWalletCallbackStreamManager( } yield { logger.info( s"Done draining akka streams for DLCWalletCallbackManagerStream, it took=${System - .currentTimeMillis() - start}ms") + .currentTimeMillis() - start}ms" + ) () } } private def matSourceAndQueue[T]( source: Source[T, SourceQueueWithComplete[T]], - sink: Sink[T, Future[Done]]): ( - SourceQueueWithComplete[T], - Future[Done]) = { + sink: Sink[T, Future[Done]] + ): (SourceQueueWithComplete[T], Future[Done]) = { source .toMat(sink)(Keep.both) .run() diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/callback/DLCWalletCallbacks.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/callback/DLCWalletCallbacks.scala index 68721b51f6..4486fe5025 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/callback/DLCWalletCallbacks.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/callback/DLCWalletCallbacks.scala @@ -19,31 +19,34 @@ trait DLCWalletCallbacks def onOfferRemove: CallbackHandler[Sha256Digest, OnDLCOfferRemove] - def executeOnDLCStateChange(status: DLCStatus)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnDLCStateChange( + status: DLCStatus + )(implicit ec: ExecutionContext): Future[Unit] = { onStateChange.execute( status, (err: Throwable) => - logger.error(s"${onStateChange.name} Callback failed with error: ", - err)) + logger.error(s"${onStateChange.name} Callback failed with error: ", err) + ) } - def executeOnDLCOfferAdd(offerDb: IncomingDLCOfferDb)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnDLCOfferAdd( + offerDb: IncomingDLCOfferDb + )(implicit ec: ExecutionContext): Future[Unit] = { onOfferAdd.execute( offerDb, (err: Throwable) => - logger.error(s"${onStateChange.name} Callback failed with error: ", - err)) + logger.error(s"${onStateChange.name} Callback failed with error: ", err) + ) } - def executeOnDLCOfferRemove(offerHash: Sha256Digest)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnDLCOfferRemove( + offerHash: Sha256Digest + )(implicit ec: ExecutionContext): Future[Unit] = { onOfferRemove.execute( offerHash, (err: Throwable) => - logger.error(s"${onStateChange.name} Callback failed with error: ", - err)) + logger.error(s"${onStateChange.name} Callback failed with error: ", err) + ) } } @@ -53,46 +56,60 @@ object DLCWalletCallbacks extends CallbackFactory[DLCWalletCallbacks] { private case class DLCWalletCallbacksImpl( onStateChange: CallbackHandler[DLCStatus, OnDLCStateChange], onOfferAdd: CallbackHandler[IncomingDLCOfferDb, OnDLCOfferAdd], - onOfferRemove: CallbackHandler[Sha256Digest, OnDLCOfferRemove]) - extends DLCWalletCallbacks { + onOfferRemove: CallbackHandler[Sha256Digest, OnDLCOfferRemove] + ) extends DLCWalletCallbacks { override def +(other: DLCWalletCallbacks): DLCWalletCallbacks = { - copy(onStateChange = onStateChange ++ other.onStateChange, - onOfferAdd = onOfferAdd ++ other.onOfferAdd, - onOfferRemove = onOfferRemove ++ other.onOfferRemove) + copy( + onStateChange = onStateChange ++ other.onStateChange, + onOfferAdd = onOfferAdd ++ other.onOfferAdd, + onOfferRemove = onOfferRemove ++ other.onOfferRemove + ) } } private val emptyImpl: DLCWalletCallbacksImpl = { DLCWalletCallbacksImpl( - CallbackHandler[DLCStatus, OnDLCStateChange]("onDLCStateChange", - Vector.empty), - CallbackHandler[IncomingDLCOfferDb, OnDLCOfferAdd]("onDLCOfferAdd", - Vector.empty), - CallbackHandler[Sha256Digest, OnDLCOfferRemove]("onDLCOfferRemove", - Vector.empty) + CallbackHandler[DLCStatus, OnDLCStateChange]( + "onDLCStateChange", + Vector.empty + ), + CallbackHandler[IncomingDLCOfferDb, OnDLCOfferAdd]( + "onDLCOfferAdd", + Vector.empty + ), + CallbackHandler[Sha256Digest, OnDLCOfferRemove]( + "onDLCOfferRemove", + Vector.empty + ) ) } val empty: DLCWalletCallbacks = emptyImpl def onDLCStateChange(f: OnDLCStateChange): DLCWalletCallbacks = { val handler = - CallbackHandler[DLCStatus, OnDLCStateChange]("onDLCStateChange", - Vector(f)) + CallbackHandler[DLCStatus, OnDLCStateChange]( + "onDLCStateChange", + Vector(f) + ) emptyImpl.copy(onStateChange = handler) } def onDLCOfferAdd(f: OnDLCOfferAdd): DLCWalletCallbacks = { val handler = - CallbackHandler[IncomingDLCOfferDb, OnDLCOfferAdd]("onDLCOfferAdd", - Vector(f)) + CallbackHandler[IncomingDLCOfferDb, OnDLCOfferAdd]( + "onDLCOfferAdd", + Vector(f) + ) emptyImpl.copy(onOfferAdd = handler) } def onDLCOfferRemove(f: OnDLCOfferRemove): DLCWalletCallbacks = { val handler = - CallbackHandler[Sha256Digest, OnDLCOfferRemove]("onDLCOfferRemove", - Vector(f)) + CallbackHandler[Sha256Digest, OnDLCOfferRemove]( + "onDLCOfferRemove", + Vector(f) + ) emptyImpl.copy(onOfferRemove = handler) } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCDataManagement.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCDataManagement.scala index dc08a5cc77..a36af01d30 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCDataManagement.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCDataManagement.scala @@ -27,14 +27,16 @@ import slick.dbio._ import scala.concurrent._ import scala.util.Try -/** Handles fetching and constructing different DLC datastructures from the database */ +/** Handles fetching and constructing different DLC datastructures from the + * database + */ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit - ec: ExecutionContext) - extends BitcoinSLogger { + ec: ExecutionContext +) extends BitcoinSLogger { val dlcDAO = dlcWalletDAOs.dlcDAO private val dlcAnnouncementDAO = dlcWalletDAOs.dlcAnnouncementDAO private val dlcInputsDAO = dlcWalletDAOs.dlcInputsDAO - //private val dlcOfferDAO = dlcWalletDAOs.dlcOfferDAO + // private val dlcOfferDAO = dlcWalletDAOs.dlcOfferDAO private val contractDataDAO = dlcWalletDAOs.contractDataDAO private val dlcAcceptDAO = dlcWalletDAOs.dlcAcceptDAO private val dlcSigsDAO: DLCCETSignaturesDAO = dlcWalletDAOs.dlcSigsDAO @@ -50,20 +52,23 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private[wallet] def getOffer( dlcId: Sha256Digest, - txDAO: TransactionDAO): Future[Option[DLCOffer]] = { + txDAO: TransactionDAO + ): Future[Option[DLCOffer]] = { val dataF = getDLCFundingData(dlcId, txDAO) dataF.map(data => data.map(_.offer)) } private[wallet] def getDLCAnnouncementDbsAction( - dlcId: Sha256Digest): DBIOAction[ + dlcId: Sha256Digest + ): DBIOAction[ ( Vector[DLCAnnouncementDb], Vector[OracleAnnouncementDataDb], Vector[OracleNonceDb] ), NoStream, - Effect.Read] = { + Effect.Read + ] = { val announcementsA = dlcAnnouncementDAO .findByDLCIdAction(dlcId) val announcementIdsA = announcementsA @@ -83,22 +88,26 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit } } - private[wallet] def getDLCAnnouncementDbs(dlcId: Sha256Digest)(implicit - ec: ExecutionContext): Future[( - Vector[DLCAnnouncementDb], - Vector[OracleAnnouncementDataDb], - Vector[OracleNonceDb])] = { + private[wallet] def getDLCAnnouncementDbs( + dlcId: Sha256Digest + )(implicit ec: ExecutionContext): Future[ + ( + Vector[DLCAnnouncementDb], + Vector[OracleAnnouncementDataDb], + Vector[OracleNonceDb] + ) + ] = { safeDatabase.run(getDLCAnnouncementDbsAction(dlcId)) } - /** Fetches the oracle announcements of the oracles - * that were used for execution in a DLC + /** Fetches the oracle announcements of the oracles that were used for + * execution in a DLC */ private[wallet] def getUsedOracleAnnouncements( dlcAnnouncementDbs: Vector[DLCAnnouncementDb], announcementData: Vector[OracleAnnouncementDataDb], - nonceDbs: Vector[OracleNonceDb]): Vector[ - (OracleAnnouncementV0TLV, Long)] = { + nonceDbs: Vector[OracleNonceDb] + ): Vector[(OracleAnnouncementV0TLV, Long)] = { val withIds = nonceDbs .groupBy(_.announcementId) .toVector @@ -111,15 +120,22 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit if (used) { val nonces = nonceDbs.sortBy(_.index).map(_.nonce) val eventTLV = - OracleEventV0TLV(nonces, - data.eventMaturity, - data.eventDescriptor, - data.eventId) + OracleEventV0TLV( + nonces, + data.eventMaturity, + data.eventDescriptor, + data.eventId + ) Some( - (OracleAnnouncementV0TLV(data.announcementSignature, - data.publicKey, - eventTLV), - data.id.get)) + ( + OracleAnnouncementV0TLV( + data.announcementSignature, + data.publicKey, + eventTLV + ), + data.id.get + ) + ) } else None case None => throw new RuntimeException(s"Error no data for announcement id $id") @@ -133,7 +149,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private[wallet] def getOracleAnnouncements( announcementIds: Vector[DLCAnnouncementDb], announcementData: Vector[OracleAnnouncementDataDb], - nonceDbs: Vector[OracleNonceDb]): OrderedAnnouncements = { + nonceDbs: Vector[OracleNonceDb] + ): OrderedAnnouncements = { val announcements = getOracleAnnouncementsWithId(announcementIds, announcementData, nonceDbs) .map(_._1) @@ -143,8 +160,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private[wallet] def getOracleAnnouncementsWithId( announcementIds: Vector[DLCAnnouncementDb], announcementData: Vector[OracleAnnouncementDataDb], - nonceDbs: Vector[OracleNonceDb]): Vector[ - (OracleAnnouncementV0TLV, Long)] = { + nonceDbs: Vector[OracleNonceDb] + ): Vector[(OracleAnnouncementV0TLV, Long)] = { val withIds: Vector[(OracleAnnouncementV0TLV, Long)] = { val idNonceVec: Vector[(Long, Vector[OracleNonceDb])] = nonceDbs.groupBy(_.announcementId).toVector @@ -152,14 +169,20 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit announcementData.find(_.id.contains(id)) match { case Some(data) => val nonces = nonceDbs.sortBy(_.index).map(_.nonce) - val eventTLV = OracleEventV0TLV(nonces, - data.eventMaturity, - data.eventDescriptor, - data.eventId) - (OracleAnnouncementV0TLV(data.announcementSignature, - data.publicKey, - eventTLV), - data.id.get) + val eventTLV = OracleEventV0TLV( + nonces, + data.eventMaturity, + data.eventDescriptor, + data.eventId + ) + ( + OracleAnnouncementV0TLV( + data.announcementSignature, + data.publicKey, + eventTLV + ), + data.id.get + ) case None => throw new RuntimeException(s"Error no data for announcement id $id") } @@ -171,22 +194,27 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit } private[wallet] def getContractInfo( - dlcId: Sha256Digest): Future[ContractInfo] = { + dlcId: Sha256Digest + ): Future[ContractInfo] = { for { contractData <- contractDataDAO.read(dlcId).map(_.get) (announcements, announcementData, nonceDbs) <- getDLCAnnouncementDbs( - dlcId) - } yield getContractInfo(contractData, - announcements, - announcementData, - nonceDbs) + dlcId + ) + } yield getContractInfo( + contractData, + announcements, + announcementData, + nonceDbs + ) } private[wallet] def getContractInfo( contractDataDb: DLCContractDataDb, announcementIds: Vector[DLCAnnouncementDb], announcementData: Vector[OracleAnnouncementDataDb], - nonceDbs: Vector[OracleNonceDb]): ContractInfo = { + nonceDbs: Vector[OracleNonceDb] + ): ContractInfo = { val announcementTLVs = getOracleAnnouncements(announcementIds, announcementData, nonceDbs) @@ -197,12 +225,16 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit if (announcementTLVs.size == 1) { EnumSingleOracleInfo(announcementTLVs.head) } else { - EnumMultiOracleInfo(contractDataDb.oracleThreshold, - announcementTLVs) + EnumMultiOracleInfo( + contractDataDb.oracleThreshold, + announcementTLVs + ) } - SingleContractInfo(contractDataDb.totalCollateral.satoshis, - enum, - oracleInfo) + SingleContractInfo( + contractDataDb.totalCollateral.satoshis, + enum, + oracleInfo + ) case numeric: NumericContractDescriptor => val oracleInfo = if (announcementTLVs.size == 1) { @@ -210,23 +242,30 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit } else { contractDataDb.oracleParamsTLVOpt match { case Some(params) => - NumericMultiOracleInfo(contractDataDb.oracleThreshold, - announcementTLVs, - params) + NumericMultiOracleInfo( + contractDataDb.oracleThreshold, + announcementTLVs, + params + ) case None => - NumericExactMultiOracleInfo(contractDataDb.oracleThreshold, - announcementTLVs) + NumericExactMultiOracleInfo( + contractDataDb.oracleThreshold, + announcementTLVs + ) } } - SingleContractInfo(contractDataDb.totalCollateral.satoshis, - numeric, - oracleInfo) + SingleContractInfo( + contractDataDb.totalCollateral.satoshis, + numeric, + oracleInfo + ) } } private[wallet] def getDLCOfferData( dlcId: Sha256Digest, - transactionDAO: TransactionDAO): Future[Option[OfferedDbState]] = { + transactionDAO: TransactionDAO + ): Future[Option[OfferedDbState]] = { val combined = actionBuilder.getDLCOfferDataAction(dlcId) val combinedF = safeDatabase.run(combined) @@ -236,10 +275,12 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit (announcements, announcementData, nonceDbs) <- announcementDataF contractInfoOpt = { contractDataDbOpt.map { case contractData => - getContractInfo(contractData, - announcements, - announcementData, - nonceDbs) + getContractInfo( + contractData, + announcements, + announcementData, + nonceDbs + ) } } @@ -254,12 +295,14 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit contractInfo <- contractInfoOpt } yield { offerPrevTxsF.map { offerPrevTxs => - OfferedDbState(dlcDb = dlcDb, - contractDataDb = contractDataDb, - contractInfo = contractInfo, - offerDb = offerDb, - offerFundingInputsDb = sortedInputs, - offerPrevTxs = offerPrevTxs) + OfferedDbState( + dlcDb = dlcDb, + contractDataDb = contractDataDb, + contractInfo = contractInfo, + offerDb = offerDb, + offerFundingInputsDb = sortedInputs, + offerPrevTxs = offerPrevTxs + ) } } } @@ -289,12 +332,13 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit acceptInputs: Vector[DLCFundingInputDb], cetSignatures: Vector[DLCCETSignaturesDb], refundSigDb: DLCRefundSigsDb, - txDAO: TransactionDAO): Future[AcceptDbState] = { + txDAO: TransactionDAO + ): Future[AcceptDbState] = { val signaturesOpt = { if (cetSignatures.isEmpty) { - //means we have pruned signatures from the database - //we have to return None + // means we have pruned signatures from the database + // we have to return None None } else { Some(cetSignatures) @@ -316,7 +360,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private[wallet] def getDLCFundingData( dlcId: Sha256Digest, - txDAO: TransactionDAO): Future[Option[DLCSetupDbState]] = { + txDAO: TransactionDAO + ): Future[Option[DLCSetupDbState]] = { val nestedF: Future[Option[Future[DLCSetupDbState]]] = for { offerDbStateOpt <- getDLCOfferData(dlcId, txDAO) dlcAcceptOpt <- dlcAcceptDAO.findByDLCId(dlcId) @@ -331,32 +376,36 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit case DLCState.Offered | DLCState.AcceptComputingAdaptorSigs => Future.successful(offerDbState) case DLCState.Accepted | DLCState.SignComputingAdaptorSigs => - //if the accept message is defined we must have refund sigs + // if the accept message is defined we must have refund sigs dlcAcceptOpt.zip(refundSigsOpt).headOption match { case Some((dlcAccept, refundSigDb)) => require( refundSigsOpt.isDefined, - s"Cannot have accept in the database if we do not have refund signatures, dlcId=${dlcId.hex}") + s"Cannot have accept in the database if we do not have refund signatures, dlcId=${dlcId.hex}" + ) - buildAcceptDbState(offerDbState = offerDbState, - dlcAccept = dlcAccept, - acceptInputs = acceptInputs, - cetSignatures = cetSignatures, - refundSigDb = refundSigDb, - txDAO = txDAO) + buildAcceptDbState( + offerDbState = offerDbState, + dlcAccept = dlcAccept, + acceptInputs = acceptInputs, + cetSignatures = cetSignatures, + refundSigDb = refundSigDb, + txDAO = txDAO + ) case None => - //just return the offerDbState if we don't have an accept + // just return the offerDbState if we don't have an accept Future.successful(offerDbState) } case DLCState.Signed | DLCState.Confirmed | DLCState.Broadcasted | _: DLCState.ClosedState => - //if the accept message is defined we must have refund sigs + // if the accept message is defined we must have refund sigs dlcAcceptOpt.zip(refundSigsOpt).headOption match { case Some((dlcAccept, refundSigDb)) => require( refundSigsOpt.isDefined, - s"Cannot have accept in the database if we do not have refund signatures, dlcId=${dlcId.hex}") + s"Cannot have accept in the database if we do not have refund signatures, dlcId=${dlcId.hex}" + ) val acceptDbStateF = buildAcceptDbState( offerDbState = offerDbState, @@ -364,7 +413,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit acceptInputs = acceptInputs, cetSignatures = cetSignatures, refundSigDb = refundSigDb, - txDAO = txDAO) + txDAO = txDAO + ) val signDbF = for { acceptDbState <- acceptDbStateF } yield { @@ -372,7 +422,7 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit } signDbF case None => - //just return the offerDbState if we don't have an accept + // just return the offerDbState if we don't have an accept Future.successful(offerDbState) } } @@ -389,7 +439,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private[wallet] def getAllDLCData( contractId: ByteVector, - txDAO: TransactionDAO): Future[Option[DLCDbState]] = { + txDAO: TransactionDAO + ): Future[Option[DLCDbState]] = { val resultF = for { dlcDbOpt <- dlcDAO.findByContractId(contractId) closedDbStateOptNested = dlcDbOpt.map(d => getAllDLCData(d.dlcId, txDAO)) @@ -404,14 +455,15 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private[wallet] def getAllDLCData( dlcId: Sha256Digest, - txDAO: TransactionDAO): Future[Option[DLCDbState]] = { + txDAO: TransactionDAO + ): Future[Option[DLCDbState]] = { val sigDLCsF = dlcSigsDAO.findByDLCId(dlcId) for { setupStateOpt <- getDLCFundingData(dlcId, txDAO) sigs <- sigDLCsF } yield { - //check if we have pruned signatures + // check if we have pruned signatures val sigsOpt = if (sigs.isEmpty) None else Some(sigs) val closedState = setupStateOpt.flatMap { case acceptState: AcceptDbState => @@ -441,12 +493,13 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit } } - /** Build a verifier from an accept message. - * Returns None if there is no DLC in the database associated with this accept message + /** Build a verifier from an accept message. Returns None if there is no DLC + * in the database associated with this accept message */ private[wallet] def verifierFromAccept( accept: DLCAccept, - txDAO: TransactionDAO): Future[Option[DLCSignatureVerifier]] = { + txDAO: TransactionDAO + ): Future[Option[DLCSignatureVerifier]] = { for { dlcDbOpt <- dlcDAO.findByTempContractId(accept.tempContractId) @@ -471,7 +524,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private[wallet] def verifierFromDb( contractId: ByteVector, - transactionDAO: TransactionDAO): Future[Option[DLCSignatureVerifier]] = { + transactionDAO: TransactionDAO + ): Future[Option[DLCSignatureVerifier]] = { dlcDAO.findByContractId(contractId).flatMap { case dlcDbOpt => val optF = dlcDbOpt.map(verifierFromDbData(_, transactionDAO)) optF match { @@ -483,7 +537,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit def getOfferAndAcceptWithoutSigs( dlcId: Sha256Digest, - txDAO: TransactionDAO): Future[Option[SetupCompleteDLCDbState]] = { + txDAO: TransactionDAO + ): Future[Option[SetupCompleteDLCDbState]] = { val dataF: Future[Option[DLCSetupDbState]] = getDLCFundingData(dlcId, txDAO) dataF.map { case Some(setupDbState) => @@ -498,14 +553,17 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private[wallet] def builderFromDbData( dlcDb: DLCDb, - transactionDAO: TransactionDAO): Future[Option[DLCTxBuilder]] = { + transactionDAO: TransactionDAO + ): Future[Option[DLCTxBuilder]] = { for { setupStateOpt <- getOfferAndAcceptWithoutSigs(dlcDb.dlcId, transactionDAO) } yield { setupStateOpt.map { completeSetupDLCDbState => val txBuilder = - DLCTxBuilder(offer = completeSetupDLCDbState.offer, - accept = completeSetupDLCDbState.acceptWithoutSigs) + DLCTxBuilder( + offer = completeSetupDLCDbState.offer, + accept = completeSetupDLCDbState.acceptWithoutSigs + ) txBuilder } } @@ -513,7 +571,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private[wallet] def verifierFromDbData( dlcDb: DLCDb, - transactionDAO: TransactionDAO): Future[Option[DLCSignatureVerifier]] = { + transactionDAO: TransactionDAO + ): Future[Option[DLCSignatureVerifier]] = { val builderOptF = builderFromDbData(dlcDb = dlcDb, transactionDAO = transactionDAO) @@ -529,7 +588,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit dlcId: Sha256Digest, transactionDAO: TransactionDAO, fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]], - keyManager: BIP39KeyManager): Future[Option[DLCTxSigner]] = { + keyManager: BIP39KeyManager + ): Future[Option[DLCTxSigner]] = { for { dlcDbOpt <- dlcDAO.findByDLCId(dlcId) signerOpt <- { @@ -553,7 +613,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit dlcDb: DLCDb, fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]], transactionDAO: TransactionDAO, - keyManager: BIP39KeyManager): Future[Option[DLCTxSigner]] = { + keyManager: BIP39KeyManager + ): Future[Option[DLCTxSigner]] = { for { builderOpt <- builderFromDbData( dlcDb = dlcDb, @@ -573,18 +634,22 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit val bip32Path = BIP32Path( dlcDb.account.path ++ Vector( BIP32Node(dlcDb.changeIndex.index, hardenedOpt = None), - BIP32Node(dlcDb.keyIndex, hardenedOpt = None))) + BIP32Node(dlcDb.keyIndex, hardenedOpt = None) + ) + ) val privKeyPath = HDPath.fromString(bip32Path.toString) val fundingPrivKey = keyManager.toSign(privKeyPath) require(fundingKey == fundingPrivKey.publicKey) - val signer = DLCTxSigner(builder = builder, - isInitiator = dlcDb.isInitiator, - fundingKey = fundingPrivKey, - finalAddress = payoutAddress, - fundingUtxos = fundingUtxoScriptSigParams) + val signer = DLCTxSigner( + builder = builder, + isInitiator = dlcDb.isInitiator, + fundingKey = fundingPrivKey, + finalAddress = payoutAddress, + fundingUtxos = fundingUtxoScriptSigParams + ) Some(signer) case None => None } @@ -595,7 +660,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit dlcDb: DLCDb, fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]], transactionDAO: TransactionDAO, - keyManager: BIP39KeyManager): Future[Option[DLCExecutor]] = { + keyManager: BIP39KeyManager + ): Future[Option[DLCExecutor]] = { val signerOptF = signerFromDb( dlcDb = dlcDb, fundingUtxoScriptSigParams = fundingUtxoScriptSigParams, @@ -614,12 +680,14 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit dlcId: Sha256Digest, transactionDAO: TransactionDAO, fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]], - keyManager: BIP39KeyManager): Future[Option[DLCExecutor]] = { - val signerOptF = signerFromDb(dlcId = dlcId, - transactionDAO = transactionDAO, - fundingUtxoScriptSigParams = - fundingUtxoScriptSigParams, - keyManager = keyManager) + keyManager: BIP39KeyManager + ): Future[Option[DLCExecutor]] = { + val signerOptF = signerFromDb( + dlcId = dlcId, + transactionDAO = transactionDAO, + fundingUtxoScriptSigParams = fundingUtxoScriptSigParams, + keyManager = keyManager + ) signerOptF.map { case Some(dlcTxSigner) => val e = DLCExecutor(dlcTxSigner) @@ -629,13 +697,15 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit } /** Builds an [[DLCExecutor]] and [[SetupDLC]] for a given contract id - * @return the executor and setup if we still have CET signatures else return None + * @return + * the executor and setup if we still have CET signatures else return None */ private[wallet] def executorAndSetupFromDb( contractId: ByteVector, txDAO: TransactionDAO, fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]], - keyManager: BIP39KeyManager): Future[Option[DLCExecutorWithSetup]] = { + keyManager: BIP39KeyManager + ): Future[Option[DLCExecutorWithSetup]] = { getAllDLCData(contractId, txDAO).flatMap { case Some(closedDbState) => closedDbState match { @@ -662,18 +732,18 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit keyManager = keyManager ) case None => - //we don't have cet signatures for the - //sign message any more + // we don't have cet signatures for the + // sign message any more Future.successful(None) } case _: ClosedDbStateNoCETSigs => - //means we cannot re-create messages because - //we don't have the cets in the database anymore + // means we cannot re-create messages because + // we don't have the cets in the database anymore Future.successful(None) case _: OfferedDbState => - //means we cannot recreate messages because - //we don't have an accept or sign message in the database + // means we cannot recreate messages because + // we don't have an accept or sign message in the database Future.successful(None) } case None => Future.successful(None) @@ -687,7 +757,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit outcomeSigsDbs: Vector[DLCCETSignaturesDb], transactionDAO: TransactionDAO, fundingUtxoScriptSigParams: Vector[ScriptSignatureParams[InputInfo]], - keyManager: BIP39KeyManager): Future[Option[DLCExecutorWithSetup]] = { + keyManager: BIP39KeyManager + ): Future[Option[DLCExecutorWithSetup]] = { val dlcExecutorOptF = executorFromDb( dlcDb = dlcDb, @@ -714,9 +785,9 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit refundSigsDb.accepterSig } else refundSigsDb.initiatorSig.get - //sometimes we do not have cet signatures, for instance - //if we have settled a DLC, we prune the cet signatures - //from the database + // sometimes we do not have cet signatures, for instance + // if we have settled a DLC, we prune the cet signatures + // from the database val cetSigs = CETSignatures(outcomeSigs) val setupF: Try[SetupDLC] = if (dlcDb.isInitiator) { @@ -732,19 +803,23 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit witnessScript match { case EmptyScriptWitness => throw new RuntimeException( - "Script witness cannot be empty") + "Script witness cannot be empty" + ) case taprootWitness: TaprootWitness => throw new UnsupportedOperationException( - s"Taproot not supported, got=$taprootWitness") + s"Taproot not supported, got=$taprootWitness" + ) case witness: ScriptWitnessV0 => (input.outPoint, witness) } case None => throw new RuntimeException("") } } - executor.setupDLCAccept(cetSigs, - refundSig, - FundingSignatures(fundingSigs), - None) + executor.setupDLCAccept( + cetSigs, + refundSig, + FundingSignatures(fundingSigs), + None + ) } val x: Try[DLCExecutorWithSetup] = @@ -760,7 +835,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit def getCetAndRefundSigsAction(dlcId: Sha256Digest): DBIOAction[ (Vector[DLCCETSignaturesDb], Option[DLCRefundSigsDb]), NoStream, - Effect.Read] = { + Effect.Read + ] = { val cetSigsAction = dlcSigsDAO.findByDLCIdAction(dlcId) val refundSigsAction = dlcRefundSigDAO.findByDLCIdAction(dlcId) for { @@ -769,8 +845,9 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit } yield (cetSigs, refundSigs) } - def getCetAndRefundSigs(dlcId: Sha256Digest): Future[ - (Vector[DLCCETSignaturesDb], Option[DLCRefundSigsDb])] = { + def getCetAndRefundSigs( + dlcId: Sha256Digest + ): Future[(Vector[DLCCETSignaturesDb], Option[DLCRefundSigsDb])] = { val action = getCetAndRefundSigsAction(dlcId) safeDatabase.run(action) } @@ -784,13 +861,14 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private def getOfferPrevTxs( dlcDb: DLCDb, fundingInputs: Vector[DLCFundingInputDb], - txDAO: TransactionDAO): Future[Vector[TransactionDb]] = { + txDAO: TransactionDAO + ): Future[Vector[TransactionDb]] = { val txIds = fundingInputs.map(_.outPoint.txIdBE) if (dlcDb.isInitiator) { - //query txDAO as we created the offer + // query txDAO as we created the offer txDAO.findByTxIdBEs(txIds) } else { - //query remote tx dao as we didn't create the offers + // query remote tx dao as we didn't create the offers remoteTxDAO.findByTxIdBEs(txIds) } } @@ -799,13 +877,14 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit private def getAcceptPrevTxs( dlcDb: DLCDb, fundingInputs: Vector[DLCFundingInputDb], - txDAO: TransactionDAO): Future[Vector[TransactionDb]] = { + txDAO: TransactionDAO + ): Future[Vector[TransactionDb]] = { val txIds = fundingInputs.map(_.outPoint.txIdBE) if (dlcDb.isInitiator) { - //if we are the initiator we need to query the remote tx dao + // if we are the initiator we need to query the remote tx dao remoteTxDAO.findByTxIdBEs(txIds) } else { - //else they are in our local tx dao + // else they are in our local tx dao txDAO.findByTxIdBEs(txIds) } } @@ -815,7 +894,8 @@ object DLCDataManagement { def fromDbAppConfig()(implicit dbAppConfig: DLCAppConfig, - ec: ExecutionContext): DLCDataManagement = { + ec: ExecutionContext + ): DLCDataManagement = { val announcementDAO: OracleAnnouncementDataDAO = OracleAnnouncementDataDAO() val oracleNonceDAO: OracleNonceDAO = OracleNonceDAO() diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala index be3d46b029..8f7d9c669d 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/DLCTransactionProcessing.scala @@ -27,8 +27,8 @@ import org.bitcoins.wallet.internal.TransactionProcessing import scala.concurrent._ -/** Overrides TransactionProcessing from Wallet to add extra logic to - * process transactions that could from our own DLC. +/** Overrides TransactionProcessing from Wallet to add extra logic to process + * transactions that could from our own DLC. */ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { self: DLCWallet => @@ -36,7 +36,9 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { /** Calculates the new state of the DLCDb based on the closing transaction, * will delete old CET sigs that are no longer needed after execution - * @return a DLCDb if we can calculate the state, else None if we cannot calculate the state + * @return + * a DLCDb if we can calculate the state, else None if we cannot calculate + * the state */ def calculateAndSetState(dlcDb: DLCDb): Future[Option[DLCDb]] = { (dlcDb.contractIdOpt, dlcDb.closingTxIdOpt) match { @@ -51,15 +53,18 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { id, transactionDAO, scriptSigParams, - keyManager) + keyManager + ) updatedDlcDb <- executorWithSetupOpt match { case Some(exeutorWithSetup) => - calculateAndSetStateWithSetupDLC(exeutorWithSetup.setup, - dlcDb, - txId) + calculateAndSetStateWithSetupDLC( + exeutorWithSetup.setup, + dlcDb, + txId + ) case None => - //this means we have already deleted the cet sigs - //just return the dlcdb given to us + // this means we have already deleted the cet sigs + // just return the dlcdb given to us Future.successful(Some(dlcDb)) } } yield { @@ -70,13 +75,14 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { } } - /** Calculates the new closing state for a DLC if we still - * have adaptor signatures available to us in the database + /** Calculates the new closing state for a DLC if we still have adaptor + * signatures available to us in the database */ private def calculateAndSetStateWithSetupDLC( setup: SetupDLC, dlcDb: DLCDb, - closingTxId: DoubleSha256DigestBE): Future[Option[DLCDb]] = { + closingTxId: DoubleSha256DigestBE + ): Future[Option[DLCDb]] = { val updatedOptF: Future[Option[DLCDb]] = { if (closingTxId == setup.refundTx.txIdBE) { val updatedOpt = Some(dlcDb.copy(state = DLCState.Refunded)) @@ -95,8 +101,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { withOutcomeOpt } } else { - //if the state is RemoteClaimed... we don't want to - //calculate and set outcome again + // if the state is RemoteClaimed... we don't want to + // calculate and set outcome again Future.successful(Some(dlcDb)) } } @@ -112,7 +118,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { DLCState.Refunded => val contractId = updated.contractIdOpt.get.toHex logger.info( - s"Deleting unneeded DLC signatures for contract $contractId") + s"Deleting unneeded DLC signatures for contract $contractId" + ) dlcSigsDAO .deleteByDLCId(updated.dlcId) @@ -132,27 +139,30 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { } yield updatedOpt } - /** Calculates the outcome used for execution - * based on the closing transaction. Returns None if we cannot calculate - * the outcome because we have pruned the cet signatures from the database + /** Calculates the outcome used for execution based on the closing + * transaction. Returns None if we cannot calculate the outcome because we + * have pruned the cet signatures from the database */ private def calculateAndSetOutcome(dlcDb: DLCDb): Future[Option[DLCDb]] = { if (dlcDb.state == DLCState.RemoteClaimed) { logger.info( s"Calculating RemotedClaimed outcome for dlcId=${dlcDb.dlcId.hex} closingTx=${dlcDb.closingTxIdOpt - .map(_.hex)}") + .map(_.hex)}" + ) val dlcId = dlcDb.dlcId for { - setupStateOpt <- dlcDataManagement.getDLCFundingData(dlcId, - txDAO = - transactionDAO) + setupStateOpt <- dlcDataManagement.getDLCFundingData( + dlcId, + txDAO = transactionDAO + ) completeDbState = { setupStateOpt.get match { case c: SetupCompleteDLCDbState => c case offered: OfferedDbState => sys.error( - s"Cannot calculate and set outcome of dlc that is only offered, id=${offered.dlcDb.dlcId.hex}") + s"Cannot calculate and set outcome of dlc that is only offered, id=${offered.dlcDb.dlcId.hex}" + ) } } (sigDbs, refundSigOpt) <- dlcDataManagement.getCetAndRefundSigs(dlcId) @@ -168,7 +178,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { completeDbState = completeDbState, cet = cet, sigDbs = sigDbs, - refundSigsDbOpt = refundSigOpt) + refundSigsDbOpt = refundSigOpt + ) sig = sigAndOutcome._1 outcome = sigAndOutcome._2 oracleInfos = getOutcomeDbInfo(outcome)._2 @@ -179,7 +190,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { announcementsWithId = dlcDataManagement.getOracleAnnouncementsWithId( announcements, announcementData, - nonceDbs) + nonceDbs + ) usedIds = { announcementsWithId @@ -211,11 +223,12 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { } } updatedDlcDbSig = dlcDb.copy(aggregateSignatureOpt = Some(sig)) - //updates the aggregateSignatureOpt along with the state to RemoteClaimed + // updates the aggregateSignatureOpt along with the state to RemoteClaimed updatedDlcDbA = dlcDAO.updateAction(updatedDlcDbSig) updateNonceA = oracleNonceDAO.updateAllAction(updatedNonces) updateAnnouncementA = dlcAnnouncementDAO.updateAllAction( - updatedAnnouncements) + updatedAnnouncements + ) actions = { for { updatedDlcDb <- updatedDlcDbA @@ -226,7 +239,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { updatedDlcDb <- safeDLCDatabase.run(actions) } yield { logger.info( - s"Done calculating RemoteClaimed outcome for dlcId=${dlcId.hex}") + s"Done calculating RemoteClaimed outcome for dlcId=${dlcId.hex}" + ) Some(updatedDlcDb) } } else { @@ -234,28 +248,33 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { } } - /** Process incoming utxos as normal, and then update the DLC states if applicable */ + /** Process incoming utxos as normal, and then update the DLC states if + * applicable + */ override protected def processReceivedUtxos( tx: Transaction, blockHashOpt: Option[DoubleSha256DigestBE], spendingInfoDbs: Vector[SpendingInfoDb], newTags: Vector[AddressTag], - relevantReceivedOutputs: Vector[OutputWithIndex]): Future[ - Vector[SpendingInfoDb]] = { + relevantReceivedOutputs: Vector[OutputWithIndex] + ): Future[Vector[SpendingInfoDb]] = { val dlcDbsF = dlcDAO.findByFundingTxId(tx.txIdBE) super - .processReceivedUtxos(tx, - blockHashOpt, - spendingInfoDbs, - newTags, - relevantReceivedOutputs) + .processReceivedUtxos( + tx, + blockHashOpt, + spendingInfoDbs, + newTags, + relevantReceivedOutputs + ) .flatMap { res => for { dlcDbs <- dlcDbsF _ <- if (dlcDbs.nonEmpty) { logger.info( - s"Processing received utxos in tx ${tx.txIdBE.hex} for ${dlcDbs.size} DLC(s)") + s"Processing received utxos in tx ${tx.txIdBE.hex} for ${dlcDbs.size} DLC(s)" + ) insertTransaction(tx, blockHashOpt) } else FutureUtil.unit @@ -270,7 +289,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { case _: DLCState.AdaptorSigComputationState => val contractIdOpt = dlcDb.contractIdOpt.map(_.toHex) throw new IllegalStateException( - s"Cannot be settling a DLC when we are computing adaptor sigs! contractId=${contractIdOpt}") + s"Cannot be settling a DLC when we are computing adaptor sigs! contractId=${contractIdOpt}" + ) case DLCState.Confirmed | DLCState.Claimed | DLCState.RemoteClaimed | DLCState.Refunded => dlcDb @@ -287,15 +307,20 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { } } - /** Sends out a websocket event for the given dlcIds since their [[DLCState]] changed - * @param dlcIds the dlcIds that had their status change - * @param isRescanning if the wallet is rescanning or not, we don't want to send out events if the wallet is rescanning + /** Sends out a websocket event for the given dlcIds since their [[DLCState]] + * changed + * @param dlcIds + * the dlcIds that had their status change + * @param isRescanning + * if the wallet is rescanning or not, we don't want to send out events if + * the wallet is rescanning */ private def sendWsDLCStateChange( dlcIds: Vector[Sha256Digest], - isRescanning: Boolean): Future[Unit] = { + isRescanning: Boolean + ): Future[Unit] = { if (isRescanning) { - //don't send ws events if we are rescanning the wallet + // don't send ws events if we are rescanning the wallet Future.unit } else { val updatedDlcDbsF = Future.sequence(dlcIds.map(findDLC)) @@ -312,8 +337,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { override protected def processSpentUtxos( transaction: Transaction, outputsBeingSpent: Vector[SpendingInfoDb], - blockHashOpt: Option[DoubleSha256DigestBE]): Future[ - Vector[SpendingInfoDb]] = { + blockHashOpt: Option[DoubleSha256DigestBE] + ): Future[Vector[SpendingInfoDb]] = { val outPoints = transaction.inputs.map(_.previousOutput).toVector val dlcDbsF = dlcDAO.findByFundingOutPoints(outPoints) super @@ -324,7 +349,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { _ <- if (dlcDbs.nonEmpty) { logger.info( - s"Processing spent utxos in tx ${transaction.txIdBE.hex} for ${dlcDbs.size} DLC(s)") + s"Processing spent utxos in tx ${transaction.txIdBE.hex} for ${dlcDbs.size} DLC(s)" + ) insertTransaction(transaction, blockHashOpt) } else FutureUtil.unit @@ -338,9 +364,9 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { } } - private def getOutcomeDbInfo(oracleOutcome: OracleOutcome): ( - Vector[DLCOutcomeType], - Vector[SingleOracleInfo]) = { + private def getOutcomeDbInfo( + oracleOutcome: OracleOutcome + ): (Vector[DLCOutcomeType], Vector[SingleOracleInfo]) = { oracleOutcome match { case EnumOracleOutcome(oracles, outcome) => (Vector.fill(oracles.length)(outcome), oracles) @@ -353,13 +379,15 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { dlcDb: DLCDb, sigDbs: Vector[DLCCETSignaturesDb], offerRefundSig: PartialSignature, - fundingInputDbs: Vector[DLCFundingInputDb]): DLCSign = { + fundingInputDbs: Vector[DLCFundingInputDb] + ): DLCSign = { { - //if we don't have an acceptOpt because we don't have CET sigs - //how are we getting them here? + // if we don't have an acceptOpt because we don't have CET sigs + // how are we getting them here? val cetSigs: CETSignatures = CETSignatures( - sigDbs.map(dbSig => (dbSig.sigPoint, dbSig.initiatorSig.get))) + sigDbs.map(dbSig => (dbSig.sigPoint, dbSig.initiatorSig.get)) + ) val contractId = dlcDb.contractIdOpt.get val fundingSigs = @@ -373,7 +401,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { throw new RuntimeException("Script witness cannot be empty") case taprootWitness: TaprootWitness => throw new UnsupportedOperationException( - s"Taproot not supported, got=$taprootWitness") + s"Taproot not supported, got=$taprootWitness" + ) case witness: ScriptWitnessV0 => (input.outPoint, witness) } @@ -382,24 +411,25 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { } } - DLCSign(cetSigs, - offerRefundSig, - FundingSignatures(fundingSigs), - contractId) + DLCSign( + cetSigs, + offerRefundSig, + FundingSignatures(fundingSigs), + contractId + ) } } - /** Recovers the aggregate signature and oracle outcome used - * to claim the DLC. Remember, this flow is for [[DLCState.RemoteClaimed]] - * so we do not necessarily have access to what the [[OracleAttestment]] is + /** Recovers the aggregate signature and oracle outcome used to claim the DLC. + * Remember, this flow is for [[DLCState.RemoteClaimed]] so we do not + * necessarily have access to what the [[OracleAttestment]] is */ private def recoverSigAndOutcomeForRemoteClaimed( completeDbState: SetupCompleteDLCDbState, cet: WitnessTransaction, sigDbs: Vector[DLCCETSignaturesDb], - refundSigsDbOpt: Option[DLCRefundSigsDb]): ( - SchnorrDigitalSignature, - OracleOutcome) = { + refundSigsDbOpt: Option[DLCRefundSigsDb] + ): (SchnorrDigitalSignature, OracleOutcome) = { val dlcDb = completeDbState.dlcDb val dlcId = dlcDb.dlcId val isInit = dlcDb.isInitiator @@ -409,7 +439,8 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { val acceptOpt = completeDbState.acceptOpt require( acceptOpt.isDefined, - s"Accept message must still have CET signatures to recover an outcome on chain, dlcId=${dlcId.hex}") + s"Accept message must still have CET signatures to recover an outcome on chain, dlcId=${dlcId.hex}" + ) val accept = acceptOpt.get val fundingInputDbs = completeDbState.allFundingInputs @@ -426,15 +457,17 @@ private[bitcoins] trait DLCTransactionProcessing extends TransactionProcessing { require( signOpt.isDefined, - s"Can only recompute outcome if signMsg is defined, dlcId=${dlcId.hex}") + s"Can only recompute outcome if signMsg is defined, dlcId=${dlcId.hex}" + ) val sign = signOpt.get - val sigsAndOutcomeOpt = DLCStatus.calculateOutcomeAndSig(isInitiator = - isInit, - offer = offer, - accept = accept, - sign = sign, - cet = cet) + val sigsAndOutcomeOpt = DLCStatus.calculateOutcomeAndSig( + isInitiator = isInit, + offer = offer, + accept = accept, + sign = sign, + cet = cet + ) require( sigsAndOutcomeOpt.isDefined, diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/IncomingDLCOffersHandling.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/IncomingDLCOffersHandling.scala index 0a515f4097..d13cc5e116 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/IncomingDLCOffersHandling.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/internal/IncomingDLCOffersHandling.scala @@ -18,10 +18,13 @@ trait IncomingDLCOffersHandling { self: DLCWallet => def registerIncomingDLCOffer( offerTLV: DLCOfferTLV, peerOpt: Option[String], - message: Option[String]): Future[Sha256Digest] = { - val dbo = IncomingDLCOfferDbHelper.fromTLV(offerTLV = offerTLV, - peer = peerOpt, - message = message) + message: Option[String] + ): Future[Sha256Digest] = { + val dbo = IncomingDLCOfferDbHelper.fromTLV( + offerTLV = offerTLV, + peer = peerOpt, + message = message + ) val contactDbOpt = peerOpt.map(DLCContactDbHelper.fromPeerAddress) for { added <- dlcWalletDAOs.incomingDLCOfferDAO.create(dbo) @@ -46,7 +49,8 @@ trait IncomingDLCOffersHandling { self: DLCWallet => } def findIncomingDLCOffer( - offerHash: Sha256Digest): Future[Option[IncomingDLCOfferDb]] = { + offerHash: Sha256Digest + ): Future[Option[IncomingDLCOfferDb]] = { dlcWalletDAOs.incomingDLCOfferDAO.find(offerHash) } @@ -70,7 +74,8 @@ trait IncomingDLCOffersHandling { self: DLCWallet => override def addDLCContactMapping( dlcId: Sha256Digest, - contcatId: InetSocketAddress): Future[Unit] = { + contcatId: InetSocketAddress + ): Future[Unit] = { dlcDAO .updateDLCContactMapping(dlcId, contcatId) } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDAO.scala index 3a2407aa36..d3bea8a597 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDAO.scala @@ -14,8 +14,8 @@ import scala.concurrent.{ExecutionContext, Future} case class DLCAcceptDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[DLCAcceptDb, Sha256Digest] + override val appConfig: DLCAppConfig +) extends CRUD[DLCAcceptDb, Sha256Digest] with SlickUtil[DLCAcceptDb, Sha256Digest] with DLCIdDaoUtil[DLCAcceptDb, Sha256Digest] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -32,31 +32,36 @@ case class DLCAcceptDAO()(implicit createAllNoAutoInc(ts, safeDatabase) override def findByPrimaryKeys( - ids: Vector[Sha256Digest]): Query[DLCAcceptTable, DLCAcceptDb, Seq] = + ids: Vector[Sha256Digest] + ): Query[DLCAcceptTable, DLCAcceptDb, Seq] = table.filter(_.dlcId.inSet(ids)) override def findByPrimaryKey( - id: Sha256Digest): Query[DLCAcceptTable, DLCAcceptDb, Seq] = { + id: Sha256Digest + ): Query[DLCAcceptTable, DLCAcceptDb, Seq] = { table .filter(_.dlcId === id) } override def findAll( - dlcs: Vector[DLCAcceptDb]): Query[DLCAcceptTable, DLCAcceptDb, Seq] = + dlcs: Vector[DLCAcceptDb] + ): Query[DLCAcceptTable, DLCAcceptDb, Seq] = findByPrimaryKeys(dlcs.map(_.dlcId)) - override def findByDLCIdsAction(dlcIds: Vector[Sha256Digest]): DBIOAction[ - Vector[DLCAcceptDb], - profile.api.NoStream, - profile.api.Effect.Read] = { + override def findByDLCIdsAction( + dlcIds: Vector[Sha256Digest] + ): DBIOAction[Vector[ + DLCAcceptDb + ], + profile.api.NoStream, + profile.api.Effect.Read] = { val q = table.filter(_.dlcId.inSet(dlcIds)) q.result.map(_.toVector) } - override def deleteByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] = { + override def deleteByDLCIdAction( + dlcId: Sha256Digest + ): DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] = { val q = table.filter(_.dlcId === dlcId) q.delete } @@ -79,21 +84,26 @@ case class DLCAcceptDAO()(implicit def changeSerialId: Rep[UInt64] = column("change_serial_id") def negotiationFields: Rep[NegotiationFieldsTLV] = column( - "negotiation_fields") + "negotiation_fields" + ) def * : ProvenShape[DLCAcceptDb] = - (dlcId, - fundingPubKey, - payoutAddress, - payoutSerialId, - collateral, - changeAddress, - changeSerialId, - negotiationFields).<>(DLCAcceptDb.tupled, DLCAcceptDb.unapply) + ( + dlcId, + fundingPubKey, + payoutAddress, + payoutSerialId, + collateral, + changeAddress, + changeSerialId, + negotiationFields + ).<>(DLCAcceptDb.tupled, DLCAcceptDb.unapply) def fk: ForeignKeyQuery[_, DLCDb] = - foreignKey("fk_dlc_id", - sourceColumns = dlcId, - targetTableQuery = dlcTable)(_.dlcId) + foreignKey( + "fk_dlc_id", + sourceColumns = dlcId, + targetTableQuery = dlcTable + )(_.dlcId) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDb.scala index bd9c913f61..38793c1695 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAcceptDb.scala @@ -18,7 +18,8 @@ case class DLCAcceptDb( collateral: CurrencyUnit, changeAddress: BitcoinAddress, changeSerialId: UInt64, - negotiationFieldsTLV: NegotiationFieldsTLV) { + negotiationFieldsTLV: NegotiationFieldsTLV +) { lazy val negotiationFields: NegotiationFields = NegotiationFields.fromTLV(negotiationFieldsTLV) @@ -27,7 +28,8 @@ case class DLCAcceptDb( tempContractId: Sha256Digest, fundingInputs: Vector[DLCFundingInput], outcomeSigs: Vector[(ECPublicKey, ECAdaptorSignature)], - refundSig: PartialSignature): DLCAccept = { + refundSig: PartialSignature + ): DLCAccept = { val pubKeys = DLCPublicKeys(fundingKey, payoutAddress) val cetSigs = CETSignatures(outcomeSigs) @@ -47,7 +49,8 @@ case class DLCAcceptDb( def toDLCAcceptWithoutSigs( tempContractId: Sha256Digest, - fundingInputs: Vector[DLCFundingInput]): DLCAcceptWithoutSigs = { + fundingInputs: Vector[DLCFundingInput] + ): DLCAcceptWithoutSigs = { val pubKeys = DLCPublicKeys(fundingKey, payoutAddress) diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAnnouncementDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAnnouncementDAO.scala index 90092afecd..7f96c12a8a 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAnnouncementDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAnnouncementDAO.scala @@ -12,8 +12,8 @@ case class DLCAnnouncementPrimaryKey(dlcId: Sha256Digest, announcementId: Long) case class DLCAnnouncementDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[DLCAnnouncementDb, DLCAnnouncementPrimaryKey] + override val appConfig: DLCAppConfig +) extends CRUD[DLCAnnouncementDb, DLCAnnouncementPrimaryKey] with SlickUtil[DLCAnnouncementDb, DLCAnnouncementPrimaryKey] with DLCIdDaoUtilNoPK[DLCAnnouncementDb] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -24,7 +24,8 @@ case class DLCAnnouncementDAO()(implicit TableQuery[DLCAnnouncementTable] private lazy val announcementDataTable: slick.lifted.TableQuery[ - OracleAnnouncementDataDAO#OracleAnnouncementsTable] = { + OracleAnnouncementDataDAO#OracleAnnouncementsTable + ] = { OracleAnnouncementDataDAO().table } @@ -33,14 +34,13 @@ case class DLCAnnouncementDAO()(implicit } override def createAll( - ts: Vector[DLCAnnouncementDb]): Future[Vector[DLCAnnouncementDb]] = + ts: Vector[DLCAnnouncementDb] + ): Future[Vector[DLCAnnouncementDb]] = createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - ids: Vector[DLCAnnouncementPrimaryKey]): profile.api.Query[ - DLCAnnouncementTable, - DLCAnnouncementDb, - Seq] = { + ids: Vector[DLCAnnouncementPrimaryKey] + ): profile.api.Query[DLCAnnouncementTable, DLCAnnouncementDb, Seq] = { // is there a better way to do this? val starting = table.filterNot(_.dlcId === Sha256Digest.empty) @@ -54,53 +54,52 @@ case class DLCAnnouncementDAO()(implicit } } - override def findByPrimaryKey(id: DLCAnnouncementPrimaryKey): Query[ - DLCAnnouncementTable, - DLCAnnouncementDb, - Seq] = { + override def findByPrimaryKey( + id: DLCAnnouncementPrimaryKey + ): Query[DLCAnnouncementTable, DLCAnnouncementDb, Seq] = { table.filter(t => t.dlcId === id.dlcId && t.announcementId === id.announcementId) } - override def find(t: DLCAnnouncementDb): profile.api.Query[ - Table[DLCAnnouncementDb], - DLCAnnouncementDb, - Seq] = { + override def find( + t: DLCAnnouncementDb + ): profile.api.Query[Table[DLCAnnouncementDb], DLCAnnouncementDb, Seq] = { findByPrimaryKey(DLCAnnouncementPrimaryKey(t.dlcId, t.announcementId)) } - override protected def findAll(ts: Vector[DLCAnnouncementDb]): Query[ - DLCAnnouncementTable, - DLCAnnouncementDb, - Seq] = findByPrimaryKeys( - ts.map(t => DLCAnnouncementPrimaryKey(t.dlcId, t.announcementId))) + override protected def findAll( + ts: Vector[DLCAnnouncementDb] + ): Query[DLCAnnouncementTable, DLCAnnouncementDb, Seq] = findByPrimaryKeys( + ts.map(t => DLCAnnouncementPrimaryKey(t.dlcId, t.announcementId)) + ) def findByAnnouncementIds( - ids: Vector[Long]): Future[Vector[DLCAnnouncementDb]] = { + ids: Vector[Long] + ): Future[Vector[DLCAnnouncementDb]] = { val action = findByAnnouncementIdsAction(ids) safeDatabase.runVec(action) } - def findByAnnouncementIdsAction(ids: Vector[Long]): DBIOAction[ - Vector[DLCAnnouncementDb], - NoStream, - Effect.Read] = { + def findByAnnouncementIdsAction( + ids: Vector[Long] + ): DBIOAction[Vector[DLCAnnouncementDb], NoStream, Effect.Read] = { val query = table.filter(_.announcementId.inSet(ids)) query.result.map(_.toVector) } - override def findByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Vector[DLCAnnouncementDb], - profile.api.NoStream, - profile.api.Effect.Read] = { + override def findByDLCIdAction( + dlcId: Sha256Digest): DBIOAction[Vector[ + DLCAnnouncementDb + ], + profile.api.NoStream, + profile.api.Effect.Read] = { val q = table.filter(_.dlcId === dlcId) q.result.map(_.toVector) } - override def deleteByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] = { + override def deleteByDLCIdAction( + dlcId: Sha256Digest + ): DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] = { val q = table.filter(_.dlcId === dlcId) q.delete } @@ -121,17 +120,23 @@ case class DLCAnnouncementDAO()(implicit .<>(DLCAnnouncementDb.tupled, DLCAnnouncementDb.unapply) def primaryKey: PrimaryKey = - primaryKey(name = "pk_announcement_id_index", - sourceColumns = (dlcId, announcementId)) + primaryKey( + name = "pk_announcement_id_index", + sourceColumns = (dlcId, announcementId) + ) def fkAnnouncementId: ForeignKeyQuery[_, OracleAnnouncementDataDb] = - foreignKey("fk_announcement_id", - sourceColumns = announcementId, - targetTableQuery = announcementDataTable)(_.id) + foreignKey( + "fk_announcement_id", + sourceColumns = announcementId, + targetTableQuery = announcementDataTable + )(_.id) def fkDLCId: ForeignKeyQuery[_, DLCDb] = - foreignKey("fk_dlc_id", - sourceColumns = dlcId, - targetTableQuery = dlcTable)(_.dlcId) + foreignKey( + "fk_dlc_id", + sourceColumns = dlcId, + targetTableQuery = dlcTable + )(_.dlcId) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAnnouncementDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAnnouncementDb.scala index 06c88df330..ce36f2302f 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAnnouncementDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCAnnouncementDb.scala @@ -2,9 +2,8 @@ package org.bitcoins.dlc.wallet.models import org.bitcoins.crypto.Sha256Digest -/** This table is for mapping announcements to DLCs, - * as well as, some contains DLC specific data about - * the announcement. +/** This table is for mapping announcements to DLCs, as well as, some contains + * DLC specific data about the announcement. */ case class DLCAnnouncementDb( dlcId: Sha256Digest, diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCCETSignaturesDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCCETSignaturesDAO.scala index c8e7c6d6c6..3def62ceef 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCCETSignaturesDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCCETSignaturesDAO.scala @@ -11,8 +11,8 @@ case class DLCCETSignaturesPrimaryKey(dlcId: Sha256Digest, contractIndex: Long) case class DLCCETSignaturesDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[DLCCETSignaturesDb, DLCCETSignaturesPrimaryKey] + override val appConfig: DLCAppConfig +) extends CRUD[DLCCETSignaturesDb, DLCCETSignaturesPrimaryKey] with SlickUtil[DLCCETSignaturesDb, DLCCETSignaturesPrimaryKey] with DLCIdDaoUtilNoPK[DLCCETSignaturesDb] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -27,14 +27,13 @@ case class DLCCETSignaturesDAO()(implicit } override def createAll( - ts: Vector[DLCCETSignaturesDb]): Future[Vector[DLCCETSignaturesDb]] = + ts: Vector[DLCCETSignaturesDb] + ): Future[Vector[DLCCETSignaturesDb]] = createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - ids: Vector[DLCCETSignaturesPrimaryKey]): Query[ - DLCCETSignatureTable, - DLCCETSignaturesDb, - Seq] = { + ids: Vector[DLCCETSignaturesPrimaryKey] + ): Query[DLCCETSignatureTable, DLCCETSignaturesDb, Seq] = { // is there a better way to do this? val starting = table.filter(_.dlcId =!= Sha256Digest.empty) @@ -49,39 +48,38 @@ case class DLCCETSignaturesDAO()(implicit } } - override def findByPrimaryKey(id: DLCCETSignaturesPrimaryKey): Query[ - DLCCETSignatureTable, - DLCCETSignaturesDb, - Seq] = { + override def findByPrimaryKey( + id: DLCCETSignaturesPrimaryKey + ): Query[DLCCETSignatureTable, DLCCETSignaturesDb, Seq] = { table.filter(t => t.dlcId === id.dlcId && t.index === id.contractIndex) } - override def find(t: DLCCETSignaturesDb): Query[ - DLCCETSignatureTable, - DLCCETSignaturesDb, - Seq] = { + override def find( + t: DLCCETSignaturesDb + ): Query[DLCCETSignatureTable, DLCCETSignaturesDb, Seq] = { findByPrimaryKey(DLCCETSignaturesPrimaryKey(t.dlcId, t.index)) } - override def findAll(dlcs: Vector[DLCCETSignaturesDb]): Query[ - DLCCETSignatureTable, - DLCCETSignaturesDb, - Seq] = + override def findAll( + dlcs: Vector[DLCCETSignaturesDb] + ): Query[DLCCETSignatureTable, DLCCETSignaturesDb, Seq] = findByPrimaryKeys( - dlcs.map(sig => DLCCETSignaturesPrimaryKey(sig.dlcId, sig.index))) + dlcs.map(sig => DLCCETSignaturesPrimaryKey(sig.dlcId, sig.index)) + ) - override def findByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Vector[DLCCETSignaturesDb], - profile.api.NoStream, - profile.api.Effect.Read] = { + override def findByDLCIdAction( + dlcId: Sha256Digest): DBIOAction[Vector[ + DLCCETSignaturesDb + ], + profile.api.NoStream, + profile.api.Effect.Read] = { val q = table.filter(_.dlcId === dlcId) q.result.map(_.toVector) } - override def deleteByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] = { + override def deleteByDLCIdAction( + dlcId: Sha256Digest + ): DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] = { val q = table.filter(_.dlcId === dlcId) q.delete } @@ -102,14 +100,17 @@ case class DLCCETSignaturesDAO()(implicit def * : ProvenShape[DLCCETSignaturesDb] = (dlcId, index, sigPoint, accepterSig, initiatorSig).<>( DLCCETSignaturesDb.tupled, - DLCCETSignaturesDb.unapply) + DLCCETSignaturesDb.unapply + ) def pk: PrimaryKey = primaryKey(name = "pk_cet_sigs", sourceColumns = (dlcId, index)) def fk = - foreignKey("fk_dlc_id", - sourceColumns = dlcId, - targetTableQuery = dlcTable)(_.dlcId) + foreignKey( + "fk_dlc_id", + sourceColumns = dlcId, + targetTableQuery = dlcTable + )(_.dlcId) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContactDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContactDAO.scala index 2e5e80ad14..e26e6a1167 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContactDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContactDAO.scala @@ -10,8 +10,8 @@ import scala.concurrent.{ExecutionContext, Future} case class DLCContactDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[DLCContactDb, InetSocketAddress] + override val appConfig: DLCAppConfig +) extends CRUD[DLCContactDb, InetSocketAddress] with SlickUtil[DLCContactDb, InetSocketAddress] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) import mappers._ @@ -21,7 +21,8 @@ case class DLCContactDAO()(implicit TableQuery[DLCContactTable] override def createAll( - ts: Vector[DLCContactDb]): Future[Vector[DLCContactDb]] = + ts: Vector[DLCContactDb] + ): Future[Vector[DLCContactDb]] = createAllNoAutoInc(ts, safeDatabase) def createIfDoesNotExist(contact: DLCContactDb): Future[DLCContactDb] = { @@ -41,20 +42,21 @@ case class DLCContactDAO()(implicit safeDatabase.run(action) } - override protected def findByPrimaryKeys(ids: Vector[ - InetSocketAddress]): Query[DLCContactTable, DLCContactDb, Seq] = + override protected def findByPrimaryKeys( + ids: Vector[InetSocketAddress] + ): Query[DLCContactTable, DLCContactDb, Seq] = table.filter(_.address.inSet(ids)).sortBy(_.alias) override def findByPrimaryKey( - id: InetSocketAddress): Query[DLCContactTable, DLCContactDb, Seq] = { + id: InetSocketAddress + ): Query[DLCContactTable, DLCContactDb, Seq] = { table .filter(_.address === id) } - override def findAll(contacts: Vector[DLCContactDb]): Query[ - DLCContactTable, - DLCContactDb, - Seq] = + override def findAll( + contacts: Vector[DLCContactDb] + ): Query[DLCContactTable, DLCContactDb, Seq] = findByPrimaryKeys(contacts.map(_.address)) def delete(address: InetSocketAddress): Future[Int] = { diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContractDataDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContractDataDAO.scala index f27d96ef18..b94c0b7464 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContractDataDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContractDataDAO.scala @@ -12,8 +12,8 @@ import scala.concurrent.{ExecutionContext, Future} case class DLCContractDataDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[DLCContractDataDb, Sha256Digest] + override val appConfig: DLCAppConfig +) extends CRUD[DLCContractDataDb, Sha256Digest] with SlickUtil[DLCContractDataDb, Sha256Digest] with DLCIdDaoUtil[DLCContractDataDb, Sha256Digest] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -28,39 +28,41 @@ case class DLCContractDataDAO()(implicit } override def createAll( - ts: Vector[DLCContractDataDb]): Future[Vector[DLCContractDataDb]] = + ts: Vector[DLCContractDataDb] + ): Future[Vector[DLCContractDataDb]] = createAllNoAutoInc(ts, safeDatabase) - override def findByPrimaryKeys(ids: Vector[Sha256Digest]): Query[ - DLCContractDataTable, - DLCContractDataDb, - Seq] = + override def findByPrimaryKeys( + ids: Vector[Sha256Digest] + ): Query[DLCContractDataTable, DLCContractDataDb, Seq] = table.filter(_.dlcId.inSet(ids)) override def findByPrimaryKey( - id: Sha256Digest): Query[DLCContractDataTable, DLCContractDataDb, Seq] = { + id: Sha256Digest + ): Query[DLCContractDataTable, DLCContractDataDb, Seq] = { table .filter(_.dlcId === id) } - override def findAll(dlcs: Vector[DLCContractDataDb]): Query[ - DLCContractDataTable, - DLCContractDataDb, - Seq] = + override def findAll( + dlcs: Vector[DLCContractDataDb] + ): Query[DLCContractDataTable, DLCContractDataDb, Seq] = findByPrimaryKeys(dlcs.map(_.dlcId)) - override def findByDLCIdsAction(dlcIds: Vector[Sha256Digest]): DBIOAction[ - Vector[DLCContractDataDb], - profile.api.NoStream, - profile.api.Effect.Read] = { + override def findByDLCIdsAction( + dlcIds: Vector[Sha256Digest] + ): DBIOAction[Vector[ + DLCContractDataDb + ], + profile.api.NoStream, + profile.api.Effect.Read] = { val q = table.filter(_.dlcId.inSet(dlcIds)) q.result.map(_.toVector) } - override def deleteByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] = { + override def deleteByDLCIdAction( + dlcId: Sha256Digest + ): DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] = { val q = table.filter(_.dlcId === dlcId) q.delete } @@ -73,10 +75,12 @@ case class DLCContractDataDAO()(implicit def oracleThreshold: Rep[Int] = column("oracle_threshold") def oracleParamsOpt: Rep[Option[OracleParamsV0TLV]] = column( - "oracle_params") + "oracle_params" + ) def contractDescriptor: Rep[ContractDescriptorTLV] = column( - "contract_descriptor") + "contract_descriptor" + ) def contractMaturity: Rep[BlockTimeStamp] = column("contract_maturity") @@ -85,17 +89,21 @@ case class DLCContractDataDAO()(implicit def totalCollateral: Rep[CurrencyUnit] = column("total_collateral") def * : ProvenShape[DLCContractDataDb] = - (dlcId, - oracleThreshold, - oracleParamsOpt, - contractDescriptor, - contractMaturity, - contractTimeout, - totalCollateral).<>(DLCContractDataDb.tupled, DLCContractDataDb.unapply) + ( + dlcId, + oracleThreshold, + oracleParamsOpt, + contractDescriptor, + contractMaturity, + contractTimeout, + totalCollateral + ).<>(DLCContractDataDb.tupled, DLCContractDataDb.unapply) def fk = - foreignKey("fk_dlc_id", - sourceColumns = dlcId, - targetTableQuery = dlcTable)(_.dlcId) + foreignKey( + "fk_dlc_id", + sourceColumns = dlcId, + targetTableQuery = dlcTable + )(_.dlcId) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContractDataDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContractDataDb.scala index 9d2a7ba582..6db4eedfad 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContractDataDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCContractDataDb.scala @@ -6,8 +6,8 @@ import org.bitcoins.core.protocol.dlc.models._ import org.bitcoins.core.protocol.tlv.{ContractDescriptorTLV, OracleParamsV0TLV} import org.bitcoins.crypto._ -/** This table contains all the meta information about a DLC. - * This includes various identifiers as well as state and a BIP 32 key path. +/** This table contains all the meta information about a DLC. This includes + * various identifiers as well as state and a BIP 32 key path. */ case class DLCContractDataDb( dlcId: Sha256Digest, diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCDAO.scala index 30758a9fe8..cfe4375efd 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCDAO.scala @@ -20,8 +20,8 @@ import scala.concurrent.{ExecutionContext, Future} case class DLCDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[DLCDb, Sha256Digest] + override val appConfig: DLCAppConfig +) extends CRUD[DLCDb, Sha256Digest] with SlickUtil[DLCDb, Sha256Digest] with DLCIdDaoUtil[DLCDb, Sha256Digest] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -30,18 +30,21 @@ case class DLCDAO()(implicit override val table: TableQuery[DLCTable] = TableQuery[DLCTable] - private lazy val contactTable: slick.lifted.TableQuery[ - DLCContactDAO#DLCContactTable] = DLCContactDAO().table + private lazy val contactTable + : slick.lifted.TableQuery[DLCContactDAO#DLCContactTable] = + DLCContactDAO().table override def createAll(ts: Vector[DLCDb]): Future[Vector[DLCDb]] = createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - ids: Vector[Sha256Digest]): Query[DLCTable, DLCDb, Seq] = + ids: Vector[Sha256Digest] + ): Query[DLCTable, DLCDb, Seq] = table.filter(_.dlcId.inSet(ids)) override def findByPrimaryKey( - id: Sha256Digest): Query[DLCTable, DLCDb, Seq] = { + id: Sha256Digest + ): Query[DLCTable, DLCDb, Seq] = { table .filter(_.dlcId === id) } @@ -49,18 +52,19 @@ case class DLCDAO()(implicit override def findAll(dlcs: Vector[DLCDb]): Query[DLCTable, DLCDb, Seq] = findByPrimaryKeys(dlcs.map(_.dlcId)) - override def findByDLCIdsAction(dlcIds: Vector[Sha256Digest]): DBIOAction[ - Vector[DLCDb], - profile.api.NoStream, - profile.api.Effect.Read] = { + override def findByDLCIdsAction( + dlcIds: Vector[Sha256Digest]): DBIOAction[Vector[ + DLCDb + ], + profile.api.NoStream, + profile.api.Effect.Read] = { val q = table.filter(_.dlcId.inSet(dlcIds)) q.result.map(_.toVector) } - override def deleteByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] = { + override def deleteByDLCIdAction( + dlcId: Sha256Digest + ): DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] = { val q = table.filter(_.dlcId === dlcId) q.delete } @@ -71,7 +75,8 @@ case class DLCDAO()(implicit } def findByTempContractId( - tempContractId: Sha256Digest): Future[Option[DLCDb]] = { + tempContractId: Sha256Digest + ): Future[Option[DLCDb]] = { val q = table.filter(_.tempContractId === tempContractId) safeDatabase.run(q.result).map { @@ -81,12 +86,14 @@ case class DLCDAO()(implicit None case dlcs: Vector[DLCDb] => throw new RuntimeException( - s"More than one DLC per tempContractId (${tempContractId.hex}), got: $dlcs") + s"More than one DLC per tempContractId (${tempContractId.hex}), got: $dlcs" + ) } } def findByTempContractId( - tempContractId: Sha256DigestBE): Future[Option[DLCDb]] = + tempContractId: Sha256DigestBE + ): Future[Option[DLCDb]] = findByTempContractId(tempContractId.flip) def findByContractId(contractId: ByteVector): Future[Option[DLCDb]] = { @@ -99,19 +106,22 @@ case class DLCDAO()(implicit None case dlcs: Vector[DLCDb] => throw new RuntimeException( - s"More than one DLC per contractId (${contractId.toHex}), got: $dlcs") + s"More than one DLC per contractId (${contractId.toHex}), got: $dlcs" + ) } } def findByFundingOutPoint( - outPoint: TransactionOutPoint): Future[Option[DLCDb]] = { + outPoint: TransactionOutPoint + ): Future[Option[DLCDb]] = { val q = table.filter(_.fundingOutPointOpt === outPoint) safeDatabase.run(q.result).map(_.headOption) } def findByFundingOutPoints( - outPoints: Vector[TransactionOutPoint]): Future[Vector[DLCDb]] = { + outPoints: Vector[TransactionOutPoint] + ): Future[Vector[DLCDb]] = { val q = table.filter(_.fundingOutPointOpt.inSet(outPoints)) safeDatabase.runVec(q.result) @@ -128,20 +138,21 @@ case class DLCDAO()(implicit } def findByContactIdAction( - contactId: String): DBIOAction[Vector[DLCDb], NoStream, Effect.Read] = { + contactId: String + ): DBIOAction[Vector[DLCDb], NoStream, Effect.Read] = { val peer: Option[String] = Some(contactId) table.filter(_.peerOpt === peer).result.map(_.toVector) } def findByStateAction( - state: DLCState): DBIOAction[Vector[DLCDb], NoStream, Effect.Read] = { + state: DLCState + ): DBIOAction[Vector[DLCDb], NoStream, Effect.Read] = { table.filter(_.state === state).result.map(_.toVector) } - def findByStatesAction(states: Vector[DLCState]): DBIOAction[ - Vector[DLCDb], - NoStream, - Effect.Read] = { + def findByStatesAction( + states: Vector[DLCState] + ): DBIOAction[Vector[DLCDb], NoStream, Effect.Read] = { table.filter(_.state.inSet(states)).result.map(_.toVector) } @@ -151,7 +162,8 @@ case class DLCDAO()(implicit def updateDLCContactMapping( dlcId: Sha256Digest, - contcatId: InetSocketAddress): Future[Unit] = { + contcatId: InetSocketAddress + ): Future[Unit] = { val contactQuery = contactTable.filter(_.address === contcatId) val action = for { @@ -161,7 +173,8 @@ case class DLCDAO()(implicit else DBIO.failed(new SQLException(s"Unknown contact: $contcatId")) res <- updatePeerAction( dlcId, - Some(contcatId.getHostName + ":" + contcatId.getPort)) + Some(contcatId.getHostName + ":" + contcatId.getPort) + ) } yield res safeDatabase.run(action).map(_ => ()) @@ -175,10 +188,8 @@ case class DLCDAO()(implicit private def updatePeerAction( dlcId: Sha256Digest, - peerOpt: Option[String]): DBIOAction[ - Int, - NoStream, - Effect.Read with Effect.Write] = { + peerOpt: Option[String] + ): DBIOAction[Int, NoStream, Effect.Read with Effect.Write] = { val dlcQuery = table.filter(_.dlcId === dlcId) for { @@ -192,7 +203,8 @@ case class DLCDAO()(implicit } def findByDLCSerializationVersion( - version: DLCSerializationVersion): Future[Vector[DLCDb]] = { + version: DLCSerializationVersion + ): Future[Vector[DLCDb]] = { val action = table.filter(_.serializationVersion === version).result safeDatabase .run(action) @@ -238,31 +250,35 @@ case class DLCDAO()(implicit column("closing_tx_id") def aggregateSignatureOpt: Rep[Option[SchnorrDigitalSignature]] = column( - "aggregate_signature") + "aggregate_signature" + ) def serializationVersion: Rep[DLCSerializationVersion] = column( - "serialization_version") + "serialization_version" + ) def peerOpt: Rep[Option[String]] = column("peer") override def * : ProvenShape[DLCDb] = - (dlcId, - tempContractId, - contractId, - protocolVersion, - state, - isInitiator, - account, - changeIndex, - keyIndex, - feeRate, - fundOutputSerialId, - lastUpdated, - fundingOutPointOpt, - fundingTxIdOpt, - closingTxIdOpt, - aggregateSignatureOpt, - serializationVersion, - peerOpt).<>(DLCDb.tupled, DLCDb.unapply) + ( + dlcId, + tempContractId, + contractId, + protocolVersion, + state, + isInitiator, + account, + changeIndex, + keyIndex, + feeRate, + fundOutputSerialId, + lastUpdated, + fundingOutPointOpt, + fundingTxIdOpt, + closingTxIdOpt, + aggregateSignatureOpt, + serializationVersion, + peerOpt + ).<>(DLCDb.tupled, DLCDb.unapply) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCDbState.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCDbState.scala index b70e268703..fcfd52b334 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCDbState.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCDbState.scala @@ -29,23 +29,23 @@ sealed trait DLCDbState { } def offer: DLCOffer = { - offerDb.toDLCOffer(contractInfo = contractInfo, - fundingInputs = offerFundingInputs, - dlcDb = dlcDb, - contractDataDb = contractDataDb) + offerDb.toDLCOffer( + contractInfo = contractInfo, + fundingInputs = offerFundingInputs, + dlcDb = dlcDb, + contractDataDb = contractDataDb + ) } final def state: DLCState = dlcDb.state } -/** Represents a DLC in the database that - * has not had its funding transaction published. - * This means we are still setting up the DLC +/** Represents a DLC in the database that has not had its funding transaction + * published. This means we are still setting up the DLC */ sealed trait DLCSetupDbState extends DLCDbState -/** Represents a DLC in the database that has - * been fully setup and settled +/** Represents a DLC in the database that has been fully setup and settled */ sealed trait DLCClosedDbState extends DLCDbState @@ -55,21 +55,23 @@ case class OfferedDbState( contractInfo: ContractInfo, offerDb: DLCOfferDb, offerFundingInputsDb: Vector[DLCFundingInputDb], - offerPrevTxs: Vector[TransactionDb]) - extends DLCSetupDbState { + offerPrevTxs: Vector[TransactionDb] +) extends DLCSetupDbState { /** Converts a [[OfferedDbState]] to an [[AcceptDbState]] * @param acceptDb * @param acceptFundingInputsDb * @param acceptPrevTxsDb - * @param cetSignaturesOpt the cet signatures, if we haven't pruned them from the database + * @param cetSignaturesOpt + * the cet signatures, if we haven't pruned them from the database */ def toAcceptDb( acceptDb: DLCAcceptDb, acceptFundingInputsDb: Vector[DLCFundingInputDb], acceptPrevTxsDb: Vector[TransactionDb], cetSigsOpt: Option[Vector[DLCCETSignaturesDb]], - refundSigDb: DLCRefundSigsDb): AcceptDbState = { + refundSigDb: DLCRefundSigsDb + ): AcceptDbState = { AcceptDbState( dlcDb = dlcDb, contractDataDb = contractDataDb, @@ -138,16 +140,18 @@ sealed trait SetupCompleteDLCDbState extends DLCSetupDbState { } } - /** Reconstructs the [[DLCAccept]] message if we have [[CETSignatures]] - * in the database. If we don't have the signatures because we have pruned - * them we return None as we can't reconstruct the message + /** Reconstructs the [[DLCAccept]] message if we have [[CETSignatures]] in the + * database. If we don't have the signatures because we have pruned them we + * return None as we can't reconstruct the message */ def acceptOpt: Option[DLCAccept] = { acceptCETSigsOpt.map { cetSignatures => - acceptDb.toDLCAccept(dlcDb.tempContractId, - acceptFundingInputs, - outcomeSigs = cetSignatures.outcomeSigs, - refundSig = refundSigDb.accepterSig) + acceptDb.toDLCAccept( + dlcDb.tempContractId, + acceptFundingInputs, + outcomeSigs = cetSignatures.outcomeSigs, + refundSig = refundSigDb.accepterSig + ) } } } @@ -163,8 +167,8 @@ case class AcceptDbState( acceptFundingInputsDb: Vector[DLCFundingInputDb], acceptPrevTxs: Vector[TransactionDb], cetSigsOpt: Option[Vector[DLCCETSignaturesDb]], - refundSigDb: DLCRefundSigsDb) - extends SetupCompleteDLCDbState { + refundSigDb: DLCRefundSigsDb +) extends SetupCompleteDLCDbState { override val allFundingInputs: Vector[DLCFundingInputDb] = offerFundingInputsDb ++ acceptFundingInputsDb @@ -179,20 +183,22 @@ case class AcceptDbState( else acceptPrevTxs } - /** Converts the AcceptDbState -> SignDbState if we have - * all parties CET signatures and refund signatures + /** Converts the AcceptDbState -> SignDbState if we have all parties CET + * signatures and refund signatures */ def toSignDbOpt: Option[SignDbState] = { - //if we haven't pruned CET signatures from the db - //they must have the offerer's CET signatures defined + // if we haven't pruned CET signatures from the db + // they must have the offerer's CET signatures defined cetSigsOpt.map { cetSigs => - require(cetSigs.forall(_.initiatorSig.isDefined), - s"CET signatures must be defined for the offerer") + require( + cetSigs.forall(_.initiatorSig.isDefined), + s"CET signatures must be defined for the offerer" + ) } - //if we don't have a refund signature from the offerer - //yet we haven't completed the sign message + // if we don't have a refund signature from the offerer + // yet we haven't completed the sign message refundSigDb.initiatorSig.map { _ => val sign = SignDbState( dlcDb, @@ -225,13 +231,17 @@ case class SignDbState( refundSigDb: DLCRefundSigsDb, cetSigsOpt: Option[Vector[DLCCETSignaturesDb]] ) extends SetupCompleteDLCDbState { - require(refundSigDb.initiatorSig.isDefined, - s"Refund signature for offerer must be defined") + require( + refundSigDb.initiatorSig.isDefined, + s"Refund signature for offerer must be defined" + ) - //If we have not prune CET signatures, the offerer CET signatures must be defined + // If we have not prune CET signatures, the offerer CET signatures must be defined cetSigsOpt.map(cetSigs => - require(cetSigs.forall(_.initiatorSig.isDefined), - s"Offerer CET signatures must be defined when in SignDbState")) + require( + cetSigs.forall(_.initiatorSig.isDefined), + s"Offerer CET signatures must be defined when in SignDbState" + )) override val allFundingInputs: Vector[DLCFundingInputDb] = offerFundingInputsDb ++ acceptFundingInputsDb @@ -255,8 +265,8 @@ case class ClosedDbStateWithCETSigs( offerFundingInputsDb ++ acceptFundingInputsDb } -/** Sometimes we prune CET sigs from the database to save on disk space. - * We need to handle this different than [[ClosedDbStateWithCETSigs]] +/** Sometimes we prune CET sigs from the database to save on disk space. We need + * to handle this different than [[ClosedDbStateWithCETSigs]] */ case class ClosedDbStateNoCETSigs( dlcDb: DLCDb, @@ -268,14 +278,15 @@ case class ClosedDbStateNoCETSigs( offerPrevTxs: Vector[TransactionDb], acceptFundingInputsDb: Vector[DLCFundingInputDb], acceptPrevTxs: Vector[TransactionDb], - refundSigsDb: DLCRefundSigsDb) - extends DLCClosedDbState + refundSigsDb: DLCRefundSigsDb +) extends DLCClosedDbState object DLCClosedDbState { def fromCompleteSetupState( completeState: SetupCompleteDLCDbState, - cetSigsOpt: Option[Vector[DLCCETSignaturesDb]]): DLCClosedDbState = { + cetSigsOpt: Option[Vector[DLCCETSignaturesDb]] + ): DLCClosedDbState = { cetSigsOpt match { case Some(cetSigs) => ClosedDbStateWithCETSigs( diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCFundingInputDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCFundingInputDAO.scala index a144f782b7..58fc39701f 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCFundingInputDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCFundingInputDAO.scala @@ -16,8 +16,8 @@ import scala.concurrent.{ExecutionContext, Future} case class DLCFundingInputDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[DLCFundingInputDb, TransactionOutPoint] + override val appConfig: DLCAppConfig +) extends CRUD[DLCFundingInputDb, TransactionOutPoint] with SlickUtil[DLCFundingInputDb, TransactionOutPoint] with DLCIdDaoUtilNoPK[DLCFundingInputDb] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -32,49 +32,48 @@ case class DLCFundingInputDAO()(implicit } override def createAll( - ts: Vector[DLCFundingInputDb]): Future[Vector[DLCFundingInputDb]] = + ts: Vector[DLCFundingInputDb] + ): Future[Vector[DLCFundingInputDb]] = createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - outPoints: Vector[TransactionOutPoint]): Query[ - DLCFundingInputsTable, - DLCFundingInputDb, - Seq] = + outPoints: Vector[TransactionOutPoint] + ): Query[DLCFundingInputsTable, DLCFundingInputDb, Seq] = table.filter(_.outPoint.inSet(outPoints)) - override def findByPrimaryKey(outPoint: TransactionOutPoint): Query[ - DLCFundingInputsTable, - DLCFundingInputDb, - Seq] = { + override def findByPrimaryKey( + outPoint: TransactionOutPoint + ): Query[DLCFundingInputsTable, DLCFundingInputDb, Seq] = { table .filter(_.outPoint === outPoint) } - override def findAll(dlcs: Vector[DLCFundingInputDb]): Query[ - DLCFundingInputsTable, - DLCFundingInputDb, - Seq] = + override def findAll( + dlcs: Vector[DLCFundingInputDb] + ): Query[DLCFundingInputsTable, DLCFundingInputDb, Seq] = findByPrimaryKeys(dlcs.map(_.outPoint)) - override def findByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Vector[DLCFundingInputDb], - profile.api.NoStream, - profile.api.Effect.Read] = { + override def findByDLCIdAction( + dlcId: Sha256Digest): DBIOAction[Vector[ + DLCFundingInputDb + ], + profile.api.NoStream, + profile.api.Effect.Read] = { val q = table.filter(_.dlcId === dlcId) q.result.map(_.toVector) } - override def deleteByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] = { + override def deleteByDLCIdAction( + dlcId: Sha256Digest + ): DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] = { val q = table.filter(_.dlcId === dlcId) q.delete } def findByDLCId( dlcId: Sha256Digest, - isInitiator: Boolean): Future[Vector[DLCFundingInputDb]] = { + isInitiator: Boolean + ): Future[Vector[DLCFundingInputDb]] = { val q = table .filter(_.dlcId === dlcId) .filter(_.isInitiator === isInitiator) @@ -107,20 +106,24 @@ case class DLCFundingInputDAO()(implicit column("witness_script_opt") def * : ProvenShape[DLCFundingInputDb] = - (dlcId, - isInitiator, - index, - inputSerialId, - outPoint, - output, - nSequence, - maxWitnessLength, - redeemScriptOpt, - witnessScriptOpt).<>(DLCFundingInputDb.tupled, DLCFundingInputDb.unapply) + ( + dlcId, + isInitiator, + index, + inputSerialId, + outPoint, + output, + nSequence, + maxWitnessLength, + redeemScriptOpt, + witnessScriptOpt + ).<>(DLCFundingInputDb.tupled, DLCFundingInputDb.unapply) def fk: ForeignKeyQuery[_, DLCDb] = - foreignKey("fk_dlc_id", - sourceColumns = dlcId, - targetTableQuery = dlcTable)(_.dlcId) + foreignKey( + "fk_dlc_id", + sourceColumns = dlcId, + targetTableQuery = dlcTable + )(_.dlcId) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCFundingInputDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCFundingInputDb.scala index 9c3a3afdd0..05fd921415 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCFundingInputDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCFundingInputDb.scala @@ -19,7 +19,8 @@ case class DLCFundingInputDb( nSequence: UInt32, maxWitnessLength: Long, redeemScriptOpt: Option[ScriptPubKey], - witnessScriptOpt: Option[ScriptWitness]) { + witnessScriptOpt: Option[ScriptWitness] +) { lazy val toOutputReference: OutputReference = OutputReference(outPoint, output) diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCIdDaoUtil.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCIdDaoUtil.scala index 72499f673a..014233638b 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCIdDaoUtil.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCIdDaoUtil.scala @@ -5,54 +5,61 @@ import org.bitcoins.db.CRUD import scala.concurrent.Future -/** Helper methods for querying by dlcId whne the dlcId is the primary key on the table */ +/** Helper methods for querying by dlcId whne the dlcId is the primary key on + * the table + */ trait DLCIdDaoUtil[T, PrimaryKeyType] { _: CRUD[T, PrimaryKeyType] => - def findByDLCIdAction(dlcId: Sha256Digest): profile.api.DBIOAction[ - Option[T], - profile.api.NoStream, - profile.api.Effect.Read] = { + def findByDLCIdAction( + dlcId: Sha256Digest): profile.api.DBIOAction[Option[ + T + ], + profile.api.NoStream, + profile.api.Effect.Read] = { findByDLCIdsAction(Vector(dlcId)) .map(_.headOption) } - def findByDLCIdsAction(dlcId: Vector[Sha256Digest]): profile.api.DBIOAction[ - Vector[T], - profile.api.NoStream, - profile.api.Effect.Read] + def findByDLCIdsAction( + dlcId: Vector[Sha256Digest] + ): profile.api.DBIOAction[Vector[ + T + ], + profile.api.NoStream, + profile.api.Effect.Read] def findByDLCId(dlcId: Sha256Digest): Future[Option[T]] = { safeDatabase.run(findByDLCIdAction(dlcId)) } - def deleteByDLCIdAction(dlcId: Sha256Digest): profile.api.DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] + def deleteByDLCIdAction( + dlcId: Sha256Digest + ): profile.api.DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] def deleteByDLCId(dlcId: Sha256Digest): Future[Int] = { safeDatabase.run(deleteByDLCIdAction(dlcId)) } } -/** Helper methods for querying by dlcId when the dlcId is not a primary - * key on the table +/** Helper methods for querying by dlcId when the dlcId is not a primary key on + * the table */ trait DLCIdDaoUtilNoPK[T] { _: CRUD[T, _] => - def findByDLCIdAction(dlcId: Sha256Digest): profile.api.DBIOAction[ - Vector[T], - profile.api.NoStream, - profile.api.Effect.Read] + def findByDLCIdAction( + dlcId: Sha256Digest): profile.api.DBIOAction[Vector[ + T + ], + profile.api.NoStream, + profile.api.Effect.Read] def findByDLCId(dlcId: Sha256Digest): Future[Vector[T]] = { safeDatabase.runVec(findByDLCIdAction(dlcId)) } - def deleteByDLCIdAction(dlcId: Sha256Digest): profile.api.DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] + def deleteByDLCIdAction( + dlcId: Sha256Digest + ): profile.api.DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] def deleteByDLCId(dlcId: Sha256Digest): Future[Int] = { safeDatabase.run(deleteByDLCIdAction(dlcId)) diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCOfferDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCOfferDAO.scala index c94bfd382f..0bb6b8212f 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCOfferDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCOfferDAO.scala @@ -13,8 +13,8 @@ import scala.concurrent.{ExecutionContext, Future} case class DLCOfferDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[DLCOfferDb, Sha256Digest] + override val appConfig: DLCAppConfig +) extends CRUD[DLCOfferDb, Sha256Digest] with SlickUtil[DLCOfferDb, Sha256Digest] with DLCIdDaoUtil[DLCOfferDb, Sha256Digest] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -31,31 +31,36 @@ case class DLCOfferDAO()(implicit createAllNoAutoInc(ts, safeDatabase) override def findByPrimaryKeys( - ids: Vector[Sha256Digest]): Query[DLCOfferTable, DLCOfferDb, Seq] = + ids: Vector[Sha256Digest] + ): Query[DLCOfferTable, DLCOfferDb, Seq] = table.filter(_.dlcId.inSet(ids)) override def findByPrimaryKey( - id: Sha256Digest): Query[DLCOfferTable, DLCOfferDb, Seq] = { + id: Sha256Digest + ): Query[DLCOfferTable, DLCOfferDb, Seq] = { table .filter(_.dlcId === id) } override def findAll( - dlcs: Vector[DLCOfferDb]): Query[DLCOfferTable, DLCOfferDb, Seq] = + dlcs: Vector[DLCOfferDb] + ): Query[DLCOfferTable, DLCOfferDb, Seq] = findByPrimaryKeys(dlcs.map(_.dlcId)) - override def findByDLCIdsAction(dlcIds: Vector[Sha256Digest]): DBIOAction[ - Vector[DLCOfferDb], - profile.api.NoStream, - profile.api.Effect.Read] = { + override def findByDLCIdsAction( + dlcIds: Vector[Sha256Digest] + ): DBIOAction[Vector[ + DLCOfferDb + ], + profile.api.NoStream, + profile.api.Effect.Read] = { val q = table.filter(_.dlcId.inSet(dlcIds)) q.result.map(_.toVector) } - override def deleteByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] = { + override def deleteByDLCIdAction( + dlcId: Sha256Digest + ): DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] = { val q = table.filter(_.dlcId === dlcId) q.delete } @@ -78,17 +83,21 @@ case class DLCOfferDAO()(implicit def changeSerialId: Rep[UInt64] = column("change_serial_id") def * : ProvenShape[DLCOfferDb] = - (dlcId, - fundingPubKey, - payoutAddress, - payoutSerialId, - collateral, - changeAddress, - changeSerialId).<>(DLCOfferDb.tupled, DLCOfferDb.unapply) + ( + dlcId, + fundingPubKey, + payoutAddress, + payoutSerialId, + collateral, + changeAddress, + changeSerialId + ).<>(DLCOfferDb.tupled, DLCOfferDb.unapply) def fk: ForeignKeyQuery[_, DLCDb] = - foreignKey("fk_dlc_id", - sourceColumns = dlcId, - targetTableQuery = dlcTable)(_.dlcId) + foreignKey( + "fk_dlc_id", + sourceColumns = dlcId, + targetTableQuery = dlcTable + )(_.dlcId) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCOfferDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCOfferDb.scala index 58ed01febf..de6f961846 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCOfferDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCOfferDb.scala @@ -17,7 +17,8 @@ case class DLCOfferDb( payoutSerialId: UInt64, collateral: CurrencyUnit, changeAddress: BitcoinAddress, - changeSerialId: UInt64) { + changeSerialId: UInt64 +) { val dlcPubKeys: DLCPublicKeys = DLCPublicKeys(fundingKey, payoutAddress) @@ -25,12 +26,15 @@ case class DLCOfferDb( contractInfo: ContractInfo, fundingInputs: Vector[DLCFundingInput], dlcDb: DLCDb, - contractDataDb: DLCContractDataDb): DLCOffer = { - toDLCOffer(contractInfo, - fundingInputs, - dlcDb.fundOutputSerialId, - dlcDb.feeRate, - contractDataDb.dlcTimeouts) + contractDataDb: DLCContractDataDb + ): DLCOffer = { + toDLCOffer( + contractInfo, + fundingInputs, + dlcDb.fundOutputSerialId, + dlcDb.feeRate, + contractDataDb.dlcTimeouts + ) } def toDLCOffer( @@ -38,7 +42,8 @@ case class DLCOfferDb( fundingInputs: Vector[DLCFundingInput], fundOutputSerialId: UInt64, feeRate: SatoshisPerVirtualByte, - dlcTimeouts: DLCTimeouts): DLCOffer = { + dlcTimeouts: DLCTimeouts + ): DLCOffer = { DLCOffer( protocolVersionOpt = DLCOfferTLV.currentVersionOpt, contractInfo = contractInfo, diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDAO.scala index 706601e430..47a1ebd70c 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDAO.scala @@ -11,8 +11,8 @@ import scala.concurrent.{ExecutionContext, Future} case class DLCRefundSigsDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[DLCRefundSigsDb, Sha256Digest] + override val appConfig: DLCAppConfig +) extends CRUD[DLCRefundSigsDb, Sha256Digest] with SlickUtil[DLCRefundSigsDb, Sha256Digest] with DLCIdDaoUtil[DLCRefundSigsDb, Sha256Digest] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -27,39 +27,41 @@ case class DLCRefundSigsDAO()(implicit } override def createAll( - ts: Vector[DLCRefundSigsDb]): Future[Vector[DLCRefundSigsDb]] = + ts: Vector[DLCRefundSigsDb] + ): Future[Vector[DLCRefundSigsDb]] = createAllNoAutoInc(ts, safeDatabase) - override protected def findByPrimaryKeys(ids: Vector[Sha256Digest]): Query[ - DLCRefundSigTable, - DLCRefundSigsDb, - Seq] = + override protected def findByPrimaryKeys( + ids: Vector[Sha256Digest] + ): Query[DLCRefundSigTable, DLCRefundSigsDb, Seq] = table.filter(_.dlcId.inSet(ids)) override def findByPrimaryKey( - id: Sha256Digest): Query[DLCRefundSigTable, DLCRefundSigsDb, Seq] = { + id: Sha256Digest + ): Query[DLCRefundSigTable, DLCRefundSigsDb, Seq] = { table .filter(_.dlcId === id) } - override def findAll(dlcs: Vector[DLCRefundSigsDb]): Query[ - DLCRefundSigTable, - DLCRefundSigsDb, - Seq] = + override def findAll( + dlcs: Vector[DLCRefundSigsDb] + ): Query[DLCRefundSigTable, DLCRefundSigsDb, Seq] = findByPrimaryKeys(dlcs.map(_.dlcId)) - override def findByDLCIdsAction(dlcIds: Vector[Sha256Digest]): DBIOAction[ - Vector[DLCRefundSigsDb], - profile.api.NoStream, - profile.api.Effect.Read] = { + override def findByDLCIdsAction( + dlcIds: Vector[Sha256Digest] + ): DBIOAction[Vector[ + DLCRefundSigsDb + ], + profile.api.NoStream, + profile.api.Effect.Read] = { val q = table.filter(_.dlcId.inSet(dlcIds)) q.result.map(_.toVector) } - override def deleteByDLCIdAction(dlcId: Sha256Digest): DBIOAction[ - Int, - profile.api.NoStream, - profile.api.Effect.Write] = { + override def deleteByDLCIdAction( + dlcId: Sha256Digest + ): DBIOAction[Int, profile.api.NoStream, profile.api.Effect.Write] = { val q = table.filter(_.dlcId === dlcId) q.delete } @@ -74,12 +76,16 @@ case class DLCRefundSigsDAO()(implicit def initiatorSig: Rep[Option[PartialSignature]] = column("initiator_sig") def * : ProvenShape[DLCRefundSigsDb] = - (dlcId, accepterSig, initiatorSig).<>(DLCRefundSigsDb.tupled, - DLCRefundSigsDb.unapply) + (dlcId, accepterSig, initiatorSig).<>( + DLCRefundSigsDb.tupled, + DLCRefundSigsDb.unapply + ) def fk: ForeignKeyQuery[_, DLCDb] = - foreignKey("fk_dlc_id", - sourceColumns = dlcId, - targetTableQuery = dlcTable)(_.dlcId) + foreignKey( + "fk_dlc_id", + sourceColumns = dlcId, + targetTableQuery = dlcTable + )(_.dlcId) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDb.scala index d68e2a26e7..bbd581f5b2 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRefundSigsDb.scala @@ -6,4 +6,5 @@ import org.bitcoins.crypto.Sha256Digest case class DLCRefundSigsDb( dlcId: Sha256Digest, accepterSig: PartialSignature, - initiatorSig: Option[PartialSignature]) + initiatorSig: Option[PartialSignature] +) diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRemoteTxDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRemoteTxDAO.scala index ffca51e536..df4cd7b3b5 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRemoteTxDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCRemoteTxDAO.scala @@ -13,8 +13,8 @@ import scala.concurrent.ExecutionContext case class DLCRemoteTxDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends TxDAO[TransactionDb] { + override val appConfig: DLCAppConfig +) extends TxDAO[TransactionDb] { import profile.api._ private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -46,15 +46,17 @@ case class DLCRemoteTxDAO()(implicit def blockHash: Rep[Option[DoubleSha256DigestBE]] = column("block_hash") def * : ProvenShape[TransactionDb] = - (txIdBE, - transaction, - unsignedTxIdBE, - unsignedTx, - wTxIdBEOpt, - totalOutput, - numInputs, - numOutputs, - locktime, - blockHash).<>(TransactionDb.tupled, TransactionDb.unapply) + ( + txIdBE, + transaction, + unsignedTxIdBE, + unsignedTx, + wTxIdBEOpt, + totalOutput, + numInputs, + numOutputs, + locktime, + blockHash + ).<>(TransactionDb.tupled, TransactionDb.unapply) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCWalletDAOs.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCWalletDAOs.scala index 03e92df4d0..99aaaa5510 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCWalletDAOs.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/DLCWalletDAOs.scala @@ -13,4 +13,5 @@ case class DLCWalletDAOs( oracleAnnouncementDAO: OracleAnnouncementDataDAO, dlcRemoteTxDAO: DLCRemoteTxDAO, incomingDLCOfferDAO: IncomingDLCOfferDAO, - contactDAO: DLCContactDAO) + contactDAO: DLCContactDAO +) diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/IncomingDLCOfferDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/IncomingDLCOfferDAO.scala index 2194947f6b..53cafae628 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/IncomingDLCOfferDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/IncomingDLCOfferDAO.scala @@ -11,8 +11,8 @@ import scala.concurrent.{ExecutionContext, Future} case class IncomingDLCOfferDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[IncomingDLCOfferDb, Sha256Digest] + override val appConfig: DLCAppConfig +) extends CRUD[IncomingDLCOfferDb, Sha256Digest] with SlickUtil[IncomingDLCOfferDb, Sha256Digest] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) import mappers._ @@ -22,25 +22,22 @@ case class IncomingDLCOfferDAO()(implicit TableQuery[IncomingDLCOfferTable] override def createAll( - ts: Vector[IncomingDLCOfferDb]): Future[Vector[IncomingDLCOfferDb]] = + ts: Vector[IncomingDLCOfferDb] + ): Future[Vector[IncomingDLCOfferDb]] = createAllNoAutoInc(ts, safeDatabase) - override def findAllAction(): DBIOAction[ - Vector[IncomingDLCOfferDb], - NoStream, - Effect.Read] = + override def findAllAction() + : DBIOAction[Vector[IncomingDLCOfferDb], NoStream, Effect.Read] = table.sortBy(_.receivedAt.desc).result.map(_.toVector) - override protected def findByPrimaryKeys(ids: Vector[Sha256Digest]): Query[ - Table[IncomingDLCOfferDb], - IncomingDLCOfferDb, - Seq] = + override protected def findByPrimaryKeys( + ids: Vector[Sha256Digest] + ): Query[Table[IncomingDLCOfferDb], IncomingDLCOfferDb, Seq] = table.filter(_.hash.inSet(ids)) - override protected def findAll(ts: Vector[IncomingDLCOfferDb]): Query[ - Table[IncomingDLCOfferDb], - IncomingDLCOfferDb, - Seq] = + override protected def findAll( + ts: Vector[IncomingDLCOfferDb] + ): Query[Table[IncomingDLCOfferDb], IncomingDLCOfferDb, Seq] = findByPrimaryKeys(ts.map(_.hash)) def delete(pk: Sha256Digest): Future[Int] = { @@ -67,10 +64,12 @@ case class IncomingDLCOfferDAO()(implicit def offerTLV: Rep[DLCOfferTLV] = column("offer_tlv") override def * = - (hash, - receivedAt, - peer, - message, - offerTLV) <> (IncomingDLCOfferDb.tupled, IncomingDLCOfferDb.unapply) + ( + hash, + receivedAt, + peer, + message, + offerTLV + ) <> (IncomingDLCOfferDb.tupled, IncomingDLCOfferDb.unapply) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/IncomingDLCOfferDbHelper.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/IncomingDLCOfferDbHelper.scala index 2ddc34aa1f..0c94fdb860 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/IncomingDLCOfferDbHelper.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/IncomingDLCOfferDbHelper.scala @@ -12,7 +12,8 @@ object IncomingDLCOfferDbHelper { offerTLV: DLCOfferTLV, peer: Option[String] = None, message: Option[String] = None, - receivedAt: Instant = Instant.now()): IncomingDLCOfferDb = { + receivedAt: Instant = Instant.now() + ): IncomingDLCOfferDb = { IncomingDLCOfferDb( hash = CryptoUtil.sha256(offerTLV.bytes), receivedAt = receivedAt, diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/InitializedAccept.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/InitializedAccept.scala index b595c0fc0c..4b23812788 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/InitializedAccept.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/InitializedAccept.scala @@ -11,14 +11,22 @@ case class InitializedAccept( fundingInputsDb: Vector[DLCFundingInputDb], pubKeys: DLCPublicKeys, contractDataDb: DLCContractDataDb, - acceptWithoutSigs: DLCAcceptWithoutSigs) { - require(dlc.dlcId == offerDb.dlcId, - s"dlc.dlcId=${dlc.dlcId} offerDb.dlcId=${offerDb.dlcId}") - require(dlc.dlcId == acceptDb.dlcId, - s"dlc.dlcId=${dlc.dlcId} offerDb.dlcId=${acceptDb.dlcId}") - require(dlc.dlcId == contractDataDb.dlcId, - s"dlc.dlcId=${dlc.dlcId} offerDb.dlcId=${contractDataDb.dlcId}") + acceptWithoutSigs: DLCAcceptWithoutSigs +) { + require( + dlc.dlcId == offerDb.dlcId, + s"dlc.dlcId=${dlc.dlcId} offerDb.dlcId=${offerDb.dlcId}" + ) + require( + dlc.dlcId == acceptDb.dlcId, + s"dlc.dlcId=${dlc.dlcId} offerDb.dlcId=${acceptDb.dlcId}" + ) + require( + dlc.dlcId == contractDataDb.dlcId, + s"dlc.dlcId=${dlc.dlcId} offerDb.dlcId=${contractDataDb.dlcId}" + ) require( pubKeys == acceptWithoutSigs.pubKeys, - s"pubKeys=${pubKeys} acceptWithoutSigs.pubKeys=${acceptWithoutSigs.pubKeys}") + s"pubKeys=${pubKeys} acceptWithoutSigs.pubKeys=${acceptWithoutSigs.pubKeys}" + ) } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleAnnouncementDataDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleAnnouncementDataDAO.scala index 14099ae0f2..ad4cfd8c8d 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleAnnouncementDataDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleAnnouncementDataDAO.scala @@ -11,8 +11,8 @@ import scala.concurrent.{ExecutionContext, Future} case class OracleAnnouncementDataDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUDAutoInc[OracleAnnouncementDataDb] { + override val appConfig: DLCAppConfig +) extends CRUDAutoInc[OracleAnnouncementDataDb] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) import mappers._ import profile.api._ @@ -21,15 +21,16 @@ case class OracleAnnouncementDataDAO()(implicit TableQuery[OracleAnnouncementsTable] def findByPublicKey( - publicKey: SchnorrPublicKey): Future[Vector[OracleAnnouncementDataDb]] = { + publicKey: SchnorrPublicKey + ): Future[Vector[OracleAnnouncementDataDb]] = { val query = table.filter(_.publicKey === publicKey) safeDatabase.runVec(query.result) } def findByAnnouncementSignatures( - signatures: Vector[SchnorrDigitalSignature]): Future[ - Vector[OracleAnnouncementDataDb]] = { + signatures: Vector[SchnorrDigitalSignature] + ): Future[Vector[OracleAnnouncementDataDb]] = { val query = table.filter(_.announcementSignature.inSet(signatures)) safeDatabase @@ -40,10 +41,9 @@ case class OracleAnnouncementDataDAO()(implicit safeDatabase.run(findByIdsAction(ids)) } - def findByIdsAction(ids: Vector[Long]): DBIOAction[ - Vector[OracleAnnouncementDataDb], - NoStream, - Effect.Read] = { + def findByIdsAction( + ids: Vector[Long] + ): DBIOAction[Vector[OracleAnnouncementDataDb], NoStream, Effect.Read] = { table.filter(_.id.inSet(ids)).result.map(_.toVector) } @@ -55,10 +55,12 @@ case class OracleAnnouncementDataDAO()(implicit extends TableAutoInc[OracleAnnouncementDataDb]( tag, schemaName, - "oracle_announcement_data") { + "oracle_announcement_data" + ) { def announcementSignature: Rep[SchnorrDigitalSignature] = column( - "announcement_signature") + "announcement_signature" + ) def publicKey: Rep[SchnorrPublicKey] = column("pub_key") @@ -71,13 +73,15 @@ case class OracleAnnouncementDataDAO()(implicit def eventMaturity: Rep[UInt32] = column("event_maturity") override def * : ProvenShape[OracleAnnouncementDataDb] = - (id.?, - announcementSignature, - publicKey, - signingPublicKey, - eventId, - eventDescriptor, - eventMaturity) + ( + id.?, + announcementSignature, + publicKey, + signingPublicKey, + eventId, + eventDescriptor, + eventMaturity + ) .<>(OracleAnnouncementDataDb.tupled, OracleAnnouncementDataDb.unapply) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleAnnouncementDataDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleAnnouncementDataDb.scala index 6b58c9db00..f87acf5abb 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleAnnouncementDataDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleAnnouncementDataDb.scala @@ -22,19 +22,21 @@ case class OracleAnnouncementDataDb( object OracleAnnouncementDbHelper { def fromAnnouncement(tlv: OracleAnnouncementTLV): OracleAnnouncementDataDb = { - OracleAnnouncementDataDb(None, - tlv.announcementSignature, - tlv.publicKey, - tlv.publicKey, - tlv.eventTLV.eventId, - tlv.eventTLV.eventDescriptor, - tlv.eventTLV.eventMaturityEpoch) + OracleAnnouncementDataDb( + None, + tlv.announcementSignature, + tlv.publicKey, + tlv.publicKey, + tlv.eventTLV.eventId, + tlv.eventTLV.eventDescriptor, + tlv.eventTLV.eventMaturityEpoch + ) } def fromAnnouncements( - announcementTLVs: Vector[OracleAnnouncementTLV]): Vector[ - OracleAnnouncementDataDb] = { + announcementTLVs: Vector[OracleAnnouncementTLV] + ): Vector[OracleAnnouncementDataDb] = { announcementTLVs.map(fromAnnouncement) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleNonceDAO.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleNonceDAO.scala index f44d4df49d..e56e307a8c 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleNonceDAO.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleNonceDAO.scala @@ -11,8 +11,8 @@ case class OracleNoncePrimaryKey(announcementId: Long, index: Long) case class OracleNonceDAO()(implicit override val ec: ExecutionContext, - override val appConfig: DLCAppConfig) - extends CRUD[OracleNonceDb, OracleNoncePrimaryKey] + override val appConfig: DLCAppConfig +) extends CRUD[OracleNonceDb, OracleNoncePrimaryKey] with SlickUtil[OracleNonceDb, OracleNoncePrimaryKey] { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) import mappers._ @@ -22,19 +22,19 @@ case class OracleNonceDAO()(implicit TableQuery[OracleNoncesTable] private lazy val announcementDataTable: slick.lifted.TableQuery[ - OracleAnnouncementDataDAO#OracleAnnouncementsTable] = { + OracleAnnouncementDataDAO#OracleAnnouncementsTable + ] = { OracleAnnouncementDataDAO().table } override def createAll( - ts: Vector[OracleNonceDb]): Future[Vector[OracleNonceDb]] = + ts: Vector[OracleNonceDb] + ): Future[Vector[OracleNonceDb]] = createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - ids: Vector[OracleNoncePrimaryKey]): profile.api.Query[ - profile.api.Table[OracleNonceDb], - OracleNonceDb, - Seq] = { + ids: Vector[OracleNoncePrimaryKey] + ): profile.api.Query[profile.api.Table[OracleNonceDb], OracleNonceDb, Seq] = { // is there a better way to do this? val starting = table.filterNot(_.announcementId === -1L) @@ -48,40 +48,39 @@ case class OracleNonceDAO()(implicit } override protected def findByPrimaryKey( - id: OracleNoncePrimaryKey): profile.api.Query[ - profile.api.Table[OracleNonceDb], - OracleNonceDb, - Seq] = { + id: OracleNoncePrimaryKey + ): profile.api.Query[profile.api.Table[OracleNonceDb], OracleNonceDb, Seq] = { table.filter(t => t.announcementId === id.announcementId && t.index === id.index) } override def find( - t: OracleNonceDb): Query[Table[OracleNonceDb], OracleNonceDb, Seq] = { + t: OracleNonceDb + ): Query[Table[OracleNonceDb], OracleNonceDb, Seq] = { findByPrimaryKey(OracleNoncePrimaryKey(t.announcementId, t.index)) } - override protected def findAll(ts: Vector[OracleNonceDb]): Query[ - Table[OracleNonceDb], - OracleNonceDb, - Seq] = + override protected def findAll( + ts: Vector[OracleNonceDb] + ): Query[Table[OracleNonceDb], OracleNonceDb, Seq] = findByPrimaryKeys( - ts.map(t => OracleNoncePrimaryKey(t.announcementId, t.index))) + ts.map(t => OracleNoncePrimaryKey(t.announcementId, t.index)) + ) def findByNonce(nonce: SchnorrNonce): Future[Option[OracleNonceDb]] = { findByNonces(Vector(nonce)).map(_.headOption) } - def findByNoncesAction(nonces: Vector[SchnorrNonce]): DBIOAction[ - Vector[OracleNonceDb], - NoStream, - Effect.Read] = { + def findByNoncesAction( + nonces: Vector[SchnorrNonce] + ): DBIOAction[Vector[OracleNonceDb], NoStream, Effect.Read] = { val query = table.filter(_.nonce.inSet(nonces)) query.result.map(_.toVector) } def findByNonces( - nonces: Vector[SchnorrNonce]): Future[Vector[OracleNonceDb]] = { + nonces: Vector[SchnorrNonce] + ): Future[Vector[OracleNonceDb]] = { val action = findByNoncesAction(nonces) safeDatabase.runVec(action) } @@ -91,14 +90,14 @@ case class OracleNonceDAO()(implicit } def findByAnnouncementIds( - ids: Vector[Long]): Future[Vector[OracleNonceDb]] = { + ids: Vector[Long] + ): Future[Vector[OracleNonceDb]] = { safeDatabase.run(findByAnnouncementIdsAction(ids)) } - def findByAnnouncementIdsAction(ids: Vector[Long]): DBIOAction[ - Vector[OracleNonceDb], - NoStream, - Effect.Read] = { + def findByAnnouncementIdsAction( + ids: Vector[Long] + ): DBIOAction[Vector[OracleNonceDb], NoStream, Effect.Read] = { table.filter(_.announcementId.inSet(ids)).result.map(_.toVector) } @@ -110,7 +109,8 @@ case class OracleNonceDAO()(implicit def index: Rep[Long] = column("index") def announcementSignature: Rep[SchnorrDigitalSignature] = column( - "announcement_signature") + "announcement_signature" + ) def nonce: Rep[SchnorrNonce] = column("nonce", O.Unique) @@ -123,12 +123,16 @@ case class OracleNonceDAO()(implicit .<>(OracleNonceDb.tupled, OracleNonceDb.unapply) def pk: PrimaryKey = - primaryKey(name = "pk_oracle_nonces", - sourceColumns = (announcementId, index)) + primaryKey( + name = "pk_oracle_nonces", + sourceColumns = (announcementId, index) + ) def fk = - foreignKey("fk_announcement_id", - sourceColumns = announcementId, - targetTableQuery = announcementDataTable)(_.id) + foreignKey( + "fk_announcement_id", + sourceColumns = announcementId, + targetTableQuery = announcementDataTable + )(_.id) } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleNonceDb.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleNonceDb.scala index a86c10064f..7cd93bdf87 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleNonceDb.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/models/OracleNonceDb.scala @@ -16,23 +16,26 @@ object OracleNonceDbHelper { def fromAnnouncement( id: Long, - tlv: OracleAnnouncementTLV): Vector[OracleNonceDb] = { + tlv: OracleAnnouncementTLV + ): Vector[OracleNonceDb] = { tlv.eventTLV match { case v0: OracleEventV0TLV => v0.nonces.zipWithIndex.map { case (nonce, index) => - OracleNonceDb(id, - index, - SchnorrDigitalSignature.dummy, - nonce, - None, - None) + OracleNonceDb( + id, + index, + SchnorrDigitalSignature.dummy, + nonce, + None, + None + ) } } } def fromAnnouncements( - announcementsWithId: Vector[(OracleAnnouncementTLV, Long)]): Vector[ - OracleNonceDb] = { + announcementsWithId: Vector[(OracleAnnouncementTLV, Long)] + ): Vector[OracleNonceDb] = { announcementsWithId.flatMap { case (announcement, id) => fromAnnouncement(id, announcement) } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCAcceptUtil.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCAcceptUtil.scala index 98c3696c3f..d90f8e8c6d 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCAcceptUtil.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCAcceptUtil.scala @@ -34,7 +34,9 @@ import scala.concurrent.{ExecutionContext, Future} object DLCAcceptUtil extends BitcoinSLogger { - /** Builds an [[DLCAcceptWithoutSigs]] message from relevant data inside of the [[DLCWallet]] */ + /** Builds an [[DLCAcceptWithoutSigs]] message from relevant data inside of + * the [[DLCWallet]] + */ def buildAcceptWithoutSigs( keyIndex: Int, chainType: HDChainType, @@ -45,14 +47,14 @@ object DLCAcceptUtil extends BitcoinSLogger { collateral: CurrencyUnit, networkParameters: NetworkParameters, externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): ( - DLCAcceptWithoutSigs, - DLCPublicKeys) = { + externalChangeAddressOpt: Option[BitcoinAddress] + ): (DLCAcceptWithoutSigs, DLCPublicKeys) = { val spendingInfos = fundRawTxHelper.scriptSigParams val txBuilder = fundRawTxHelper.txBuilderWithFinalizer val serialIds = DLCMessage.genSerialIds( spendingInfos.size, - offer.fundingInputs.map(_.inputSerialId)) + offer.fundingInputs.map(_.inputSerialId) + ) val utxos = spendingInfos.zip(serialIds).map { case (utxo, id) => DLCFundingInput .fromInputSigningInfo(utxo, id, TransactionConstants.enableRBFSequence) @@ -71,12 +73,15 @@ object DLCAcceptUtil extends BitcoinSLogger { externalPayoutAddressOpt = externalPayoutAddressOpt ) - require(dlcPubKeys.fundingKey == fundingPrivKey.publicKey, - "Did not derive the same funding private and public key") + require( + dlcPubKeys.fundingKey == fundingPrivKey.publicKey, + "Did not derive the same funding private and public key" + ) val payoutSerialId = DLCMessage.genSerialId(Vector(offer.payoutSerialId)) val changeSerialId = DLCMessage.genSerialId( - Vector(offer.fundOutputSerialId, offer.changeSerialId)) + Vector(offer.fundOutputSerialId, offer.changeSerialId) + ) val acceptWithoutSigs = DLCAcceptWithoutSigs( totalCollateral = collateral.satoshis, pubKeys = dlcPubKeys, @@ -94,7 +99,8 @@ object DLCAcceptUtil extends BitcoinSLogger { def buildAcceptContractDataDb( contractInfo: ContractInfo, dlcId: Sha256Digest, - offer: DLCOffer): DLCContractDataDb = { + offer: DLCOffer + ): DLCContractDataDb = { val oracleParamsOpt = OracleInfo.getOracleParamsOpt(contractInfo.oracleInfos.head) DLCContractDataDb( @@ -116,7 +122,8 @@ object DLCAcceptUtil extends BitcoinSLogger { chainType: HDChainType, nextIndex: Int, contractInfo: ContractInfo, - peerOpt: Option[String]): DLCDb = { + peerOpt: Option[String] + ): DLCDb = { DLCDb( dlcId = dlcId, tempContractId = offer.tempContractId, @@ -143,7 +150,8 @@ object DLCAcceptUtil extends BitcoinSLogger { dlc: DLCDb, acceptWithoutSigs: DLCAcceptWithoutSigs, dlcPubKeys: DLCPublicKeys, - collateral: CurrencyUnit): DLCAcceptDb = { + collateral: CurrencyUnit + ): DLCAcceptDb = { DLCAcceptDb( dlcId = dlc.dlcId, fundingKey = dlcPubKeys.fundingKey, @@ -161,14 +169,15 @@ object DLCAcceptUtil extends BitcoinSLogger { dlcId: Sha256Digest, offer: DLCOffer, dlcWalletDAOs: DLCWalletDAOs, - transactionDAO: TransactionDAO)(implicit - ec: ExecutionContext): Future[Option[DLCAccept]] = { + transactionDAO: TransactionDAO + )(implicit ec: ExecutionContext): Future[Option[DLCAccept]] = { val resultNestedF: Future[Option[Future[DLCAccept]]] = for { dlcAcceptDbs <- dlcWalletDAOs.dlcAcceptDAO.findByDLCId(dlcId) dlcAcceptFOpt = { dlcAcceptDbs.headOption.map { case dlcAcceptDb => logger.debug( - s"DLC Accept (${dlcId.hex}) has already been made, returning accept") + s"DLC Accept (${dlcId.hex}) has already been made, returning accept" + ) for { fundingInputs <- dlcWalletDAOs.dlcInputsDAO.findByDLCId(dlcId, isInitiator = false) @@ -180,12 +189,14 @@ object DLCAcceptUtil extends BitcoinSLogger { val inputRefs = DLCTxUtil.matchPrevTxsWithInputs(fundingInputs, prevTxs) - dlcAcceptDb.toDLCAccept(offer.tempContractId, - inputRefs, - outcomeSigsDbs.map { db => - db.sigPoint -> db.accepterSig - }, - refundSigsDb.get.accepterSig) + dlcAcceptDb.toDLCAccept( + offer.tempContractId, + inputRefs, + outcomeSigsDbs.map { db => + db.sigPoint -> db.accepterSig + }, + refundSigsDb.get.accepterSig + ) } } } diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCActionBuilder.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCActionBuilder.scala index ae5117ef7e..4cc82eb382 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCActionBuilder.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCActionBuilder.scala @@ -20,51 +20,58 @@ case class DLCActionBuilder(dlcWalletDAOs: DLCWalletDAOs) { private val dlcRefundSigDAO = dlcWalletDAOs.dlcRefundSigDAO private val oracleNonceDAO = dlcWalletDAOs.oracleNonceDAO - //idk if it matters which profile api i import, but i need access to transactionally + // idk if it matters which profile api i import, but i need access to transactionally import dlcWalletDAOs.dlcDAO.profile.api._ private val mappers = new DbCommonsColumnMappers(dlcWalletDAOs.dlcDAO.profile) import mappers.sha256DigestMapper - /** Builds an offer in our database, adds relevant information to the global table, - * contract data, announcements, funding inputs, and the actual offer itself + /** Builds an offer in our database, adds relevant information to the global + * table, contract data, announcements, funding inputs, and the actual offer + * itself */ def buildCreateOfferAction( dlcDb: DLCDb, contractDataDb: DLCContractDataDb, dlcAnnouncementDbs: Vector[DLCAnnouncementDb], dlcInputs: Vector[DLCFundingInputDb], - dlcOfferDb: DLCOfferDb)(implicit ec: ExecutionContext): DBIOAction[ + dlcOfferDb: DLCOfferDb + )(implicit ec: ExecutionContext): DBIOAction[ Unit, NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + Effect.Read with Effect.Write with Effect.Transactional + ] = { val globalAction = dlcDAO.upsertAction(dlcDb) val contractAction = contractDataDAO.upsertAction(contractDataDb) val announcementAction = dlcAnnouncementDAO.upsertAllAction(dlcAnnouncementDbs) val inputsAction = dlcInputsDAO.upsertAllAction(dlcInputs) val offerAction = dlcOfferDAO.upsertAction(dlcOfferDb) - val actions = Vector(globalAction, - contractAction, - announcementAction, - inputsAction, - offerAction) + val actions = Vector( + globalAction, + contractAction, + announcementAction, + inputsAction, + offerAction + ) val allActions = DBIO .sequence(actions) .map(_ => ()) allActions } - /** Builds an accept in our database, adds relevant information to the - * offer table, accept table, cet sigs table, inputs table, and refund table + /** Builds an accept in our database, adds relevant information to the offer + * table, accept table, cet sigs table, inputs table, and refund table */ def buildCreateAcceptAction( dlcDb: DLCDb, offerInputs: Vector[DLCFundingInputDb], cetSigsDb: Vector[DLCCETSignaturesDb], - refundSigsDb: DLCRefundSigsDb)(implicit ec: ExecutionContext): DBIOAction[ + refundSigsDb: DLCRefundSigsDb + )(implicit ec: ExecutionContext): DBIOAction[ Unit, NoStream, - Effect.Write with Effect.Read with Effect.Transactional] = { + Effect.Write with Effect.Read with Effect.Transactional + ] = { val dlcDbAction = dlcDAO.updateAction(dlcDb) val inputAction = dlcInputsDAO.upsertAllAction(offerInputs) val sigsAction = dlcSigsDAO.createAllAction(cetSigsDb) @@ -77,14 +84,12 @@ case class DLCActionBuilder(dlcWalletDAOs: DLCWalletDAOs) { allActions } - /** Creates the action to delete the given dlc from our database. - * This removes references to the dlc in our various tables + /** Creates the action to delete the given dlc from our database. This removes + * references to the dlc in our various tables */ def deleteDLCAction(dlcId: Sha256Digest)(implicit - ec: ExecutionContext): DBIOAction[ - Unit, - NoStream, - Effect.Write with Effect.Transactional] = { + ec: ExecutionContext + ): DBIOAction[Unit, NoStream, Effect.Write with Effect.Transactional] = { val deleteSigA = dlcSigsDAO.deleteByDLCIdAction(dlcId) val deleteRefundSigA = dlcRefundSigDAO.deleteByDLCIdAction(dlcId) val deleteInputSigA = dlcInputsDAO.deleteByDLCIdAction(dlcId) @@ -108,27 +113,32 @@ case class DLCActionBuilder(dlcWalletDAOs: DLCWalletDAOs) { action } - /** Retrieves a DBIOAction that fetches the global dlc db, - * the contract, the offer, and funding inputs + /** Retrieves a DBIOAction that fetches the global dlc db, the contract, the + * offer, and funding inputs */ - def getDLCOfferDataAction(dlcId: Sha256Digest)(implicit - ec: ExecutionContext): DBIOAction[ + def getDLCOfferDataAction( + dlcId: Sha256Digest + )(implicit ec: ExecutionContext): DBIOAction[ ( Option[DLCDb], Option[DLCContractDataDb], Option[DLCOfferDb], - Vector[DLCFundingInputDb]), + Vector[DLCFundingInputDb] + ), NoStream, - Effect.Read with Effect.Transactional] = { + Effect.Read with Effect.Transactional + ] = { val dlcDbQ = dlcDAO.findByPrimaryKey(dlcId) val contractDbsQ = contractDataDAO.findByPrimaryKey(dlcId) val offerDbsQ = dlcOfferDAO.findByPrimaryKey(dlcId) - //optimization to use sql queries rather than action - //as this method gets called a lot. - val dlcDbOfferDbContractDataDbOptA: DBIOAction[ - Option[((DLCDb, DLCOfferDb), DLCContractDataDb)], - NoStream, - Effect.Read with Effect.Transactional] = { + // optimization to use sql queries rather than action + // as this method gets called a lot. + val dlcDbOfferDbContractDataDbOptA + : DBIOAction[Option[ + ((DLCDb, DLCOfferDb), DLCContractDataDb) + ], + NoStream, + Effect.Read with Effect.Transactional] = { dlcDbQ .join(offerDbsQ) .on(_.dlcId === _.dlcId) @@ -143,7 +153,7 @@ case class DLCActionBuilder(dlcWalletDAOs: DLCWalletDAOs) { val combined = for { dlcDbOfferDbContractDataDbOpt <- dlcDbOfferDbContractDataDbOptA inputs <- fundingInputsAction - //only want offerer inputs + // only want offerer inputs offerInputs = inputs.filter(_.isInitiator) } yield { dlcDbOfferDbContractDataDbOpt match { @@ -157,22 +167,25 @@ case class DLCActionBuilder(dlcWalletDAOs: DLCWalletDAOs) { combined } - /** Updates various tables in our database with oracle attestations - * that are published by the oracle + /** Updates various tables in our database with oracle attestations that are + * published by the oracle */ def updateDLCOracleSigsAction( - outcomeAndSigByNonce: Map[ - SchnorrNonce, - (String, SchnorrDigitalSignature)])(implicit - ec: ExecutionContext): DBIOAction[ - Vector[OracleNonceDb], - NoStream, - Effect.Write with Effect.Read with Effect.Transactional] = { + outcomeAndSigByNonce: Map[SchnorrNonce, (String, SchnorrDigitalSignature)] + )(implicit ec: ExecutionContext) + : DBIOAction[Vector[ + OracleNonceDb + ], + NoStream, + Effect.Write with Effect.Read with Effect.Transactional] = { val updateAction = for { nonceDbs <- oracleNonceDAO.findByNoncesAction( - outcomeAndSigByNonce.keys.toVector) - _ = assert(nonceDbs.size == outcomeAndSigByNonce.keys.size, - "Didn't receive all nonce dbs") + outcomeAndSigByNonce.keys.toVector + ) + _ = assert( + nonceDbs.size == outcomeAndSigByNonce.keys.size, + "Didn't receive all nonce dbs" + ) updated = nonceDbs.map { db => val (outcome, sig) = outcomeAndSigByNonce(db.nonce) diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCStatusBuilder.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCStatusBuilder.scala index 0667cfb7dc..259e92bdb2 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCStatusBuilder.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCStatusBuilder.scala @@ -12,9 +12,10 @@ import org.bitcoins.dlc.wallet.accounting.{AccountingUtil, DLCAccountingDbs} import org.bitcoins.dlc.wallet.models._ /** Creates a case class that represents all DLC data from dlcdb.sqlite - * Unfortunately we have to read some data from walletdb.sqlite to build a - * full [[DLCStatus]] - * @see https://github.com/bitcoin-s/bitcoin-s/pull/4555#issuecomment-1200113188 + * Unfortunately we have to read some data from walletdb.sqlite to build a full + * [[DLCStatus]] + * @see + * https://github.com/bitcoin-s/bitcoin-s/pull/4555#issuecomment-1200113188 */ case class IntermediaryDLCStatus( dlcDb: DLCDb, @@ -29,16 +30,18 @@ case class IntermediaryDLCStatus( def complete( payoutAddressOpt: Option[PayoutAddress], - closingTxOpt: Option[TransactionDb]): DLCStatus = { + closingTxOpt: Option[TransactionDb] + ): DLCStatus = { val dlcId = dlcDb.dlcId dlcDb.state match { case _: DLCState.InProgressState => - DLCStatusBuilder.buildInProgressDLCStatus(dlcDb = dlcDb, - contractInfo = contractInfo, - contractData = contractData, - offerDb = offerDb, - payoutAddress = - payoutAddressOpt) + DLCStatusBuilder.buildInProgressDLCStatus( + dlcDb = dlcDb, + contractInfo = contractInfo, + contractData = contractData, + offerDb = offerDb, + payoutAddress = payoutAddressOpt + ) case _: DLCState.ClosedState => (acceptDbOpt, closingTxOpt) match { case (Some(acceptDb), Some(closingTx)) => @@ -56,13 +59,16 @@ case class IntermediaryDLCStatus( ) case (None, None) => throw new RuntimeException( - s"Could not find acceptDb or closingTx for closing state=${dlcDb.state} dlcId=$dlcId") + s"Could not find acceptDb or closingTx for closing state=${dlcDb.state} dlcId=$dlcId" + ) case (Some(_), None) => throw new RuntimeException( - s"Could not find closingTx for state=${dlcDb.state} dlcId=$dlcId") + s"Could not find closingTx for state=${dlcDb.state} dlcId=$dlcId" + ) case (None, Some(_)) => throw new RuntimeException( - s"Cannot find acceptDb for dlcId=$dlcId. This likely means we have data corruption") + s"Cannot find acceptDb for dlcId=$dlcId. This likely means we have data corruption" + ) } } } @@ -70,13 +76,16 @@ case class IntermediaryDLCStatus( object DLCStatusBuilder { - /** Helper method to convert a bunch of indepdendent datastructures into a in progress dlc status */ + /** Helper method to convert a bunch of indepdendent datastructures into a in + * progress dlc status + */ def buildInProgressDLCStatus( dlcDb: DLCDb, contractInfo: ContractInfo, contractData: DLCContractDataDb, offerDb: DLCOfferDb, - payoutAddress: Option[PayoutAddress]): DLCStatus = { + payoutAddress: Option[PayoutAddress] + ): DLCStatus = { require( dlcDb.state.isInstanceOf[DLCState.InProgressState], s"Cannot have divergent states between dlcDb and the parameter state, got= dlcDb.state=${dlcDb.state} state=${dlcDb.state}" @@ -215,7 +224,8 @@ object DLCStatusBuilder { offerDb: DLCOfferDb, acceptDb: DLCAcceptDb, closingTx: Transaction, - payoutAddress: Option[PayoutAddress]): ClosedDLCStatus = { + payoutAddress: Option[PayoutAddress] + ): ClosedDLCStatus = { require( dlcDb.state.isInstanceOf[DLCState.ClosedState], s"Cannot have divergent states beteween dlcDb and the parameter state, got= dlcDb.state=${dlcDb.state} state=${dlcDb.state}" @@ -235,7 +245,7 @@ object DLCStatusBuilder { } val status = dlcDb.state.asInstanceOf[DLCState.ClosedState] match { case DLCState.Refunded => - //no oracle information in the refund case + // no oracle information in the refund case val refund = Refunded( dlcId, dlcDb.isInitiator, @@ -259,7 +269,8 @@ object DLCStatusBuilder { val (oracleOutcome, sigs) = getOracleOutcomeAndSigs( announcementIds = announcementIds, announcementsWithId = announcementsWithId, - nonceDbs = nonceDbs) + nonceDbs = nonceDbs + ) oracleOutcomeState match { case DLCState.Claimed => @@ -309,15 +320,14 @@ object DLCStatusBuilder { status } - /** Calculates oracle outcome and signatures. Returns none if the dlc is not in a valid state to - * calculate the outcome + /** Calculates oracle outcome and signatures. Returns none if the dlc is not + * in a valid state to calculate the outcome */ def getOracleOutcomeAndSigs( announcementIds: Vector[DLCAnnouncementDb], announcementsWithId: Vector[(OracleAnnouncementV0TLV, Long)], - nonceDbs: Vector[OracleNonceDb]): ( - OracleOutcome, - OrderedSchnorrSignatures) = { + nonceDbs: Vector[OracleNonceDb] + ): (OracleOutcome, OrderedSchnorrSignatures) = { val noncesByAnnouncement: Map[Long, Vector[OracleNonceDb]] = nonceDbs.sortBy(_.index).groupBy(_.announcementId) val oracleOutcome = { @@ -325,19 +335,25 @@ object DLCStatusBuilder { val usedOracles = usedOracleIds.sortBy(_.index).map { used => announcementsWithId.find(_._2 == used.announcementId).get } - require(usedOracles.nonEmpty, - s"Error, no oracles used, dlcIds=${announcementIds.map(_.dlcId)}") + require( + usedOracles.nonEmpty, + s"Error, no oracles used, dlcIds=${announcementIds.map(_.dlcId)}" + ) announcementsWithId.head._1.eventTLV.eventDescriptor match { case _: EnumEventDescriptorV0TLV => val oracleInfos = usedOracles.map(t => EnumSingleOracleInfo(t._1)) val outcomes = usedOracles.map { case (_, id) => val nonces = noncesByAnnouncement(id) - require(nonces.size == 1, - s"Only 1 outcome for enum, got ${nonces.size}") + require( + nonces.size == 1, + s"Only 1 outcome for enum, got ${nonces.size}" + ) EnumOutcome(nonces.head.outcomeOpt.get) } - require(outcomes.distinct.size == 1, - s"Should only be one outcome for enum, got $outcomes") + require( + outcomes.distinct.size == 1, + s"Should only be one outcome for enum, got $outcomes" + ) EnumOracleOutcome(oracleInfos, outcomes.head) case _: UnsignedDigitDecompositionEventDescriptor => val oraclesAndOutcomes = usedOracles.map { case (announcement, id) => diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCTxUtil.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCTxUtil.scala index 1ff6d86607..8f8a3f7dee 100644 --- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCTxUtil.scala +++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/util/DLCTxUtil.scala @@ -6,19 +6,23 @@ import org.bitcoins.dlc.wallet.models.DLCFundingInputDb object DLCTxUtil { - /** Takes in a list of inputs to fund DLCs, and pairs them with the full funding transaction for this input - * and then converts the input tx pair to a [[DLCFundingInput]] - * @throws NoSuchElementException when we have an input we cannot find the funding transaction for + /** Takes in a list of inputs to fund DLCs, and pairs them with the full + * funding transaction for this input and then converts the input tx pair to + * a [[DLCFundingInput]] + * @throws NoSuchElementException + * when we have an input we cannot find the funding transaction for */ def matchPrevTxsWithInputs( inputs: Vector[DLCFundingInputDb], - prevTxs: Vector[TransactionDb]): Vector[DLCFundingInput] = { + prevTxs: Vector[TransactionDb] + ): Vector[DLCFundingInput] = { inputs.sortBy(_.index).map { i => prevTxs.find(_.txId == i.outPoint.txId) match { case Some(txDb) => i.toFundingInput(txDb.transaction) case None => throw new NoSuchElementException( - s"Could not find previous transaction with txIdBE=${i.outPoint.txId.flip.hex}") + s"Could not find previous transaction with txIdBE=${i.outPoint.txId.flip.hex}" + ) } } } diff --git a/eclair-rpc-test/src/test/scala/org/bitcoins/eclair/rpc/EclairRpcClientTest.scala b/eclair-rpc-test/src/test/scala/org/bitcoins/eclair/rpc/EclairRpcClientTest.scala index af0e144638..8a51399d3d 100644 --- a/eclair-rpc-test/src/test/scala/org/bitcoins/eclair/rpc/EclairRpcClientTest.scala +++ b/eclair-rpc-test/src/test/scala/org/bitcoins/eclair/rpc/EclairRpcClientTest.scala @@ -85,9 +85,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { lazy val fourthClientF: Future[EclairRpcClient] = eclairNodesF.map(_.c4) - /** There is specific cases where we just need two clients, - * so this is a helper val that pairs two connected - * clients together with an open channel + /** There is specific cases where we just need two clients, so this is a + * helper val that pairs two connected clients together with an open channel */ lazy val clientF: Future[EclairRpcClient] = secondClientF lazy val otherClientF: Future[EclairRpcClient] = thirdClientF @@ -95,26 +94,29 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { private val clients = Vector.newBuilder[EclairRpcClient] - /** Executes a test with the default clients defined at the - * top of this file + /** Executes a test with the default clients defined at the top of this file * * @param test * @tparam T * @return */ def executeWithClientOtherClient[T]( - test: (EclairRpcClient, EclairRpcClient) => Future[T]): Future[T] = { + test: (EclairRpcClient, EclairRpcClient) => Future[T] + ): Future[T] = { - executeSpecificClients(clientF = clientF, - otherClientF = otherClientF, - test = test) + executeSpecificClients( + clientF = clientF, + otherClientF = otherClientF, + test = test + ) } /** Executes the test with the clients passed as a parameter */ def executeSpecificClients[T]( clientF: Future[EclairRpcClient], otherClientF: Future[EclairRpcClient], - test: (EclairRpcClient, EclairRpcClient) => Future[T]): Future[T] = { + test: (EclairRpcClient, EclairRpcClient) => Future[T] + ): Future[T] = { clientF.flatMap { c1 => otherClientF.flatMap { other => test(c1, other) @@ -152,7 +154,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { } } - /** Please keep this test the very first. All other tests rely on the propagated gossip messages. + /** Please keep this test the very first. All other tests rely on the + * propagated gossip messages. */ it should "wait for all gossip messages get propagated throughout the network and get a route to an invoice" in { val hasRoute = () => { @@ -168,7 +171,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { _ = assert( info.publicAddresses .map(_.getHostString) - .exists(_.endsWith(".onion"))) + .exists(_.endsWith(".onion")) + ) routes <- client1.findRoute(invoice, None) } yield { routes.head.asInstanceOf[NodeRoute].nodeIds.size == 4 @@ -220,24 +224,30 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { .awaitUntilIncomingPaymentStatus[IncomingPaymentStatus.Received]( client4, invoice.lnTags.paymentHash.hash, - interval = 1.second) + interval = 1.second + ) - _ <- EclairRpcTestUtil.awaitUntilPaymentSucceeded(client1, - paymentId, - duration = 1.second) + _ <- EclairRpcTestUtil.awaitUntilPaymentSucceeded( + client1, + paymentId, + duration = 1.second + ) _ <- TestAsyncUtil.retryUntilSatisfiedF( conditionF = () => client4.audit().map(_.received.nonEmpty), interval = 1.second, - maxTries = 60) + maxTries = 60 + ) _ <- TestAsyncUtil.retryUntilSatisfiedF( conditionF = () => client2.audit().map(_.relayed.nonEmpty), interval = 1.second, - maxTries = 60) + maxTries = 60 + ) _ <- TestAsyncUtil.retryUntilSatisfiedF( conditionF = () => client1.audit().map(_.sent.nonEmpty), interval = 1.second, - maxTries = 60) + maxTries = 60 + ) } yield { succeed } @@ -314,7 +324,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { assert( invoice.hrp.toString == LnHumanReadablePart .lnbcrt(Some(12345.msats.toLnCurrencyUnit)) - .toString) + .toString + ) assert(invoice.network == LnBitcoinRegTest) assert(invoice.amount.contains(123450.pBTC)) assert(invoice.isValidSignature) @@ -328,16 +339,19 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { it should "be able to create an invoice with amount and expiry time" in { for { c <- clientF - invoice <- c.createInvoice(description = "test", - amountMsat = 12345.msats, - expireIn = 67890.seconds) + invoice <- c.createInvoice( + description = "test", + amountMsat = 12345.msats, + expireIn = 67890.seconds + ) info <- c.getInfo } yield { assert(invoice.nodeId == info.nodeId) assert( invoice.hrp.toString == LnHumanReadablePart .lnbcrt(Some(12345.msats.toLnCurrencyUnit)) - .toString) + .toString + ) assert(invoice.network == LnBitcoinRegTest) assert(invoice.amount.contains(123450.pBTC)) assert(invoice.isValidSignature) @@ -353,18 +367,21 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { it should "be able to create an invoice with amount, expiry time, and fallbackAddress" in { for { c <- clientF - invoice <- c.createInvoice(description = "test", - amountMsat = Some(12345.msats), - expireIn = Some(67890.seconds), - fallbackAddress = Some(testBitcoinAddress), - paymentPreimage = None) + invoice <- c.createInvoice( + description = "test", + amountMsat = Some(12345.msats), + expireIn = Some(67890.seconds), + fallbackAddress = Some(testBitcoinAddress), + paymentPreimage = None + ) info <- c.getInfo } yield { assert(invoice.nodeId == info.nodeId) assert( invoice.hrp.toString == LnHumanReadablePart .lnbcrt(Some(123450.pBTC)) - .toString) + .toString + ) assert(invoice.network == LnBitcoinRegTest) assert(invoice.amount.contains(123450.pBTC)) assert(invoice.isValidSignature) @@ -376,7 +393,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { } val testPaymentPreimage = PaymentPreimage.fromHex( - "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff") + "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff" + ) it should "be able to create an invoice with amount, expiry time, fallbackAddress, and preimage" in { for { @@ -394,7 +412,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { assert( invoice.hrp.toString == LnHumanReadablePart .lnbcrt(Some(12345.msats.toLnCurrencyUnit)) - .toString) + .toString + ) assert(invoice.network == LnBitcoinRegTest) assert(invoice.amount.contains(123450.pBTC)) assert(invoice.isValidSignature) @@ -407,21 +426,25 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { it should "be able to start and shutdown a node" in { val eclairTestClient = - EclairRpcTestClient.fromSbtDownload(eclairVersionOpt = None, - eclairCommitOpt = None, - bitcoindRpcClientOpt = None) + EclairRpcTestClient.fromSbtDownload( + eclairVersionOpt = None, + eclairCommitOpt = None, + bitcoindRpcClientOpt = None + ) for { eclair <- eclairTestClient.start() - _ <- TestAsyncUtil.retryUntilSatisfiedF(conditionF = - () => eclair.isStarted(), - interval = 1.second, - maxTries = 60) + _ <- TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => eclair.isStarted(), + interval = 1.second, + maxTries = 60 + ) _ = EclairRpcTestUtil.shutdown(eclair) _ <- - TestAsyncUtil.retryUntilSatisfiedF(conditionF = - () => eclair.isStarted().map(!_), - interval = 1.second, - maxTries = 60) + TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => eclair.isStarted().map(!_), + interval = 1.second, + maxTries = 60 + ) } yield succeed } @@ -492,8 +515,10 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { changeAddrF.flatMap { addr => val amountF = bitcoindRpcClientF.flatMap { bitcoindRpcClient => - bitcoindRpcClient.getReceivedByAddress(address = addr, - minConfirmations = 0) + bitcoindRpcClient.getReceivedByAddress( + address = addr, + minConfirmations = 0 + ) } amountF.map(amt => assert(amt > CurrencyUnits.zero)) } @@ -516,10 +541,12 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { } val badCredentialsF = goodCredentialsF.map { good => - EclairAuthCredentials("bad_password", - good.bitcoinAuthOpt, - rpcPort = good.rpcPort, - bitcoindRpcUri = good.bitcoindRpcUri) + EclairAuthCredentials( + "bad_password", + good.bitcoinAuthOpt, + rpcPort = good.rpcPort, + bitcoindRpcUri = good.bitcoindRpcUri + ) } val badInstanceF = badCredentialsF.flatMap { badCredentials => @@ -541,9 +568,11 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { val badClientF = badInstanceF.map( - new EclairRpcClient(_, - Some( - EclairRpcTestClient.sbtBinaryDirectory.toFile))) + new EclairRpcClient( + _, + Some(EclairRpcTestClient.sbtBinaryDirectory.toFile) + ) + ) badClientF.flatMap { badClient => recoverToSucceededIf[RuntimeException](badClient.getInfo) @@ -551,7 +580,7 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { } it should "be able to list an existing peer and isConnected must be true" in { - //test assumes that a connection to a peer was made in `beforeAll` + // test assumes that a connection to a peer was made in `beforeAll` val otherClientNodeIdF = { val getOtherClientNodeId = { (_: EclairRpcClient, otherClient: EclairRpcClient) => @@ -575,22 +604,25 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { preimage = PaymentPreimage.random invoice <- otherClient.createInvoice("foo", amt, preimage) route <- client.findRoute(otherClientNodeId, amt) - result <- client.sendToRoute(invoice, - route.head, - amt, - invoice.lnTags.paymentHash.hash, - finalCltvExpiry = 144, - recipientAmountMsat = None, - parentId = None, - externalId = Some("ext_id")) + result <- client.sendToRoute( + invoice, + route.head, + amt, + invoice.lnTags.paymentHash.hash, + finalCltvExpiry = 144, + recipientAmountMsat = None, + parentId = None, + externalId = Some("ext_id") + ) _ <- EclairRpcTestUtil .awaitUntilIncomingPaymentStatus[ - IncomingPaymentStatus.Received]( - otherClient, - invoice.lnTags.paymentHash.hash) - _ <- EclairRpcTestUtil.awaitUntilPaymentSucceeded(client, - result.parentId) + IncomingPaymentStatus.Received + ](otherClient, invoice.lnTags.paymentHash.hash) + _ <- EclairRpcTestUtil.awaitUntilPaymentSucceeded( + client, + result.parentId + ) succeeded <- client.getSentInfo(result.parentId) } yield { assert(otherClientNodeId == invoice.nodeId) @@ -625,8 +657,10 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { channels <- client.channels(otherClientNodeId) // without this we've been getting "route not found" // probably an async issue, this is more elegant than Thread.sleep - _ = assert(channels.exists(_.state == ChannelState.NORMAL), - "Nodes did not have open channel!") + _ = assert( + channels.exists(_.state == ChannelState.NORMAL), + "Nodes did not have open channel!" + ) preimage = PaymentPreimage.random wsEventP = Promise[WebSocketEvent]() _ <- client.connectToWebSocket { event => @@ -634,12 +668,14 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { wsEventP.success(event) } } - paymentId <- client.sendToNode(otherClientNodeId, - amt, - None, - None, - None, - Some("ext_id")) + paymentId <- client.sendToNode( + otherClientNodeId, + amt, + None, + None, + None, + Some("ext_id") + ) wsEvent <- wsEventP.future succeeded <- client.getSentInfo(paymentId) _ <- client.close(channelId) @@ -660,7 +696,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { assert(succeededPayment.externalId.contains("ext_id")) assert( succeededPayment.status - .isInstanceOf[OutgoingPaymentStatus.Succeeded]) + .isInstanceOf[OutgoingPaymentStatus.Succeeded] + ) } } } @@ -695,11 +732,13 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { assert(succeeded.nonEmpty) assert( - received.get.paymentRequest.paymentHash == invoice.lnTags.paymentHash.hash) + received.get.paymentRequest.paymentHash == invoice.lnTags.paymentHash.hash + ) assert( received.get.status .asInstanceOf[IncomingPaymentStatus.Received] - .amount == amt) + .amount == amt + ) val succeededPayment = succeeded.head assert(succeededPayment.amount == amt) @@ -739,7 +778,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { assert(succeededPayment.amount == amt) assert( succeededPayment.status - .isInstanceOf[OutgoingPaymentStatus.Succeeded]) + .isInstanceOf[OutgoingPaymentStatus.Succeeded] + ) } } } @@ -748,14 +788,17 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { } it should "be able to generate an invoice and get the same amount back" in { - val amt = PicoBitcoins(10) //this is the smallest unit we can use, 1 msat + val amt = PicoBitcoins(10) // this is the smallest unit we can use, 1 msat val description = "bitcoin-s test case" val expiry = System.currentTimeMillis().millis val invoiceF = clientF.flatMap( - _.createInvoice(description = description, - amountMsat = amt.toMSat, - expireIn = expiry)) + _.createInvoice( + description = description, + amountMsat = amt.toMSat, + expireIn = expiry + ) + ) val assert0: Future[Assertion] = { invoiceF.map { i => @@ -767,11 +810,14 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { val amt1 = NanoBitcoins.one val invoice1F = clientF.flatMap( - _.createInvoice(description = description, - amountMsat = Some(amt1.toMSat), - expireIn = Some(expiry), - None, - None)) + _.createInvoice( + description = description, + amountMsat = Some(amt1.toMSat), + expireIn = Some(expiry), + None, + None + ) + ) val assert1 = { invoice1F.map { i => @@ -783,9 +829,12 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { val amt2 = MicroBitcoins.one val invoice2F = clientF.flatMap( - _.createInvoice(description = description, - amountMsat = amt2.toMSat, - expireIn = expiry)) + _.createInvoice( + description = description, + amountMsat = amt2.toMSat, + expireIn = expiry + ) + ) val assert2 = { invoice2F.map { i => @@ -799,9 +848,12 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { val amt3 = MilliBitcoins.one val invoice3F = clientF.flatMap( - _.createInvoice(description = description, - amountMsat = amt3.toMSat, - expireIn = expiry)) + _.createInvoice( + description = description, + amountMsat = amt3.toMSat, + expireIn = expiry + ) + ) val assert3 = { invoice3F.map { i => @@ -824,9 +876,12 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { val expiry = 10.seconds val invoiceF = clientF.flatMap( - _.createInvoice(description = description, - amountMsat = amt, - expireIn = expiry)) + _.createInvoice( + description = description, + amountMsat = amt, + expireIn = expiry + ) + ) val paymentRequestF: Future[InvoiceResult] = invoiceF.flatMap { i => clientF.flatMap(_.parseInvoice(i)) @@ -852,16 +907,19 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { () => c2.getReceivedInfo(invoice) .map(_.get.status.isInstanceOf[IncomingPaymentStatus.Received]), - 1.seconds) + 1.seconds + ) receivedAgainOpt <- c2.getReceivedInfo(invoice) } yield { assert(receivedAgainOpt.isDefined) assert( receivedAgainOpt.get.status .asInstanceOf[IncomingPaymentStatus.Received] - .amount == amt) + .amount == amt + ) assert( - receivedAgainOpt.get.paymentRequest.paymentHash == invoice.lnTags.paymentHash.hash) + receivedAgainOpt.get.paymentRequest.paymentHash == invoice.lnTags.paymentHash.hash + ) } } @@ -875,16 +933,20 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { invoice: LnInvoice <- otherClient.createInvoice("monitor an invoice", amt) _ <- client.payInvoice(invoice) - received <- otherClient.monitorInvoice(invoice, - interval = 1.seconds, - maxAttempts = 60) + received <- otherClient.monitorInvoice( + invoice, + interval = 1.seconds, + maxAttempts = 60 + ) } yield { assert( received.status .asInstanceOf[IncomingPaymentStatus.Received] - .amount == amt) + .amount == amt + ) assert( - received.paymentRequest.paymentHash == invoice.lnTags.paymentHash.hash) + received.paymentRequest.paymentHash == invoice.lnTags.paymentHash.hash + ) } res } @@ -906,10 +968,12 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { val connectedClientsF: Future[EclairNodes4] = { freshClients1F.flatMap { case (freshClient1, freshClient2) => freshClients2F.flatMap { case (freshClient3, freshClient4) => - clients ++= List(freshClient1, - freshClient2, - freshClient3, - freshClient4) + clients ++= List( + freshClient1, + freshClient2, + freshClient3, + freshClient4 + ) val connect1And3 = EclairRpcTestUtil.connectLNNodes(freshClient1, freshClient3) @@ -917,10 +981,12 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { EclairRpcTestUtil.connectLNNodes(freshClient1, freshClient4)) connect1And3.flatMap { _ => connect1And4.map { _ => - EclairNodes4(freshClient1, - freshClient2, - freshClient3, - freshClient4) + EclairNodes4( + freshClient1, + freshClient2, + freshClient3, + freshClient4 + ) } } } @@ -929,7 +995,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { def openChannel( c1: EclairRpcClient, - c2: EclairRpcClient): Future[FundedChannelId] = { + c2: EclairRpcClient + ): Future[FundedChannelId] = { EclairRpcTestUtil .openChannel(c1, c2, Satoshis(500000), MilliSatoshis(500000)) } @@ -979,7 +1046,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { .map(_.forall(updateIsInChannels(ourOpenChannels))) }), interval = 1.second, - maxTries = 60) + maxTries = 60 + ) } yield { succeed } @@ -989,9 +1057,11 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { val client2F = connectedClientsF.map(_.c2) sendPaymentsF.flatMap { _ => - executeSpecificClients(clientF = client1F, - otherClientF = client2F, - test = getChannelUpdates) + executeSpecificClients( + clientF = client1F, + otherClientF = client2F, + test = getChannelUpdates + ) } } @@ -1012,8 +1082,10 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { invoice2 <- client.createInvoice("test", paymentAmount2) paymentId2 <- otherClient.payInvoice(invoice2) - _ <- EclairRpcTestUtil.awaitUntilPaymentSucceeded(otherClient, - paymentId2) + _ <- EclairRpcTestUtil.awaitUntilPaymentSucceeded( + otherClient, + paymentId2 + ) sentInfo2 <- otherClient.getSentInfo(invoice2.lnTags.paymentHash.hash) } yield { assert(sentInfo.head.amount == paymentAmount) @@ -1061,7 +1133,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { it should "get all channels" in { clientF.flatMap( - _.allChannels().flatMap(channels => assert(channels.nonEmpty))) + _.allChannels().flatMap(channels => assert(channels.nonEmpty)) + ) } it should "get all channel updates" in { @@ -1081,10 +1154,10 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { } it must "receive gossip messages about channel updates for nodes we do not have a direct channel with" in { - //make sure we see payments outside of our immediate peers - //this is important because these gossip messages contain - //information about channel fees, so we need to get updates - //about the channels for future fee calculations + // make sure we see payments outside of our immediate peers + // this is important because these gossip messages contain + // information about channel fees, so we need to get updates + // about the channels for future fee calculations val sentPaymentF = secondClientF.flatMap { c1 => thirdClientF.flatMap { c2 => EclairRpcTestUtil.sendPayments(c1, c2, numPayments = 1) @@ -1108,15 +1181,17 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { } AsyncUtil - .retryUntilSatisfiedF((() => checkUpdates()), - interval = 1.second, - maxTries = 60) + .retryUntilSatisfiedF( + (() => checkUpdates()), + interval = 1.second, + maxTries = 60 + ) .transform(_ => succeed, ex => ex) } } - //the second client and fourth client aren't directly connected - //which is why i am choosing to use them for this test + // the second client and fourth client aren't directly connected + // which is why i am choosing to use them for this test executeSpecificClients( clientF = secondClientF, otherClientF = fourthClientF, @@ -1180,7 +1255,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { c.listPendingInvoices(from = None, to = None).map(_.contains(i)) }), interval = 1.second, - maxTries = 60) + maxTries = 60 + ) } yield { assert(!res.contains(i)) } @@ -1210,7 +1286,8 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { private def hasConnection( client: Future[EclairRpcClient], - nodeId: NodeId): Future[Assertion] = { + nodeId: NodeId + ): Future[Assertion] = { val hasPeersF = client.flatMap(_.getPeers.map(_.nonEmpty)) @@ -1224,10 +1301,13 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { hasPeersAssertF.flatMap(_ => isConnectedAssertF.map(isConn => isConn)) } - /** Checks that the given [[org.bitcoins.eclair.rpc.client.EclairRpcClient]] has the given chanId */ + /** Checks that the given [[org.bitcoins.eclair.rpc.client.EclairRpcClient]] + * has the given chanId + */ private def hasChannel( client: EclairRpcClient, - chanId: ChannelId): Future[Assertion] = { + chanId: ChannelId + ): Future[Assertion] = { val recognizedOpenChannel: Future[Assertion] = { val chanResultF: Future[ChannelResult] = client.channel(chanId) @@ -1239,8 +1319,9 @@ class EclairRpcClientTest extends BitcoinSAsyncTest { recognizedOpenChannel } - private def updateIsInChannels(channels: Seq[OpenChannelInfo])( - update: ChannelUpdate): Boolean = { + private def updateIsInChannels( + channels: Seq[OpenChannelInfo] + )(update: ChannelUpdate): Boolean = { channels.exists(_.shortChannelId == update.shortChannelId) } diff --git a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/api/EclairApi.scala b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/api/EclairApi.scala index f78ee699ba..fc79ddd10b 100644 --- a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/api/EclairApi.scala +++ b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/api/EclairApi.scala @@ -21,9 +21,11 @@ import java.time.Instant import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} -/** This trait defines methods to interact with the Eclair lightning node via its API. +/** This trait defines methods to interact with the Eclair lightning node via + * its API. * - * @see [[https://acinq.github.io/eclair/]] + * @see + * [[https://acinq.github.io/eclair/]] */ trait EclairApi { @@ -38,8 +40,10 @@ trait EclairApi { def audit(): Future[AuditResult] /** List all sent/received/relayed payments in the given interval - * @param from start timestamp - * @param to end timestamp + * @param from + * start timestamp + * @param to + * end timestamp */ def audit(from: Option[Instant], to: Option[Instant]): Future[AuditResult] @@ -48,7 +52,8 @@ trait EclairApi { def allUpdates(nodeId: NodeId): Future[Vector[ChannelUpdate]] def allUpdates( - nodeIdOpt: Option[NodeId] = None): Future[Vector[ChannelUpdate]] = + nodeIdOpt: Option[NodeId] = None + ): Future[Vector[ChannelUpdate]] = nodeIdOpt match { case Some(nodeId) => allUpdates(nodeId) case None => allUpdates() @@ -74,13 +79,15 @@ trait EclairApi { def findRoute( nodeId: NodeId, - amountMsat: MilliSatoshis): Future[Vector[Route]] + amountMsat: MilliSatoshis + ): Future[Vector[Route]] def findRoute(invoice: LnInvoice): Future[Vector[Route]] def findRoute( invoice: LnInvoice, - amountMsat: MilliSatoshis): Future[Vector[Route]] + amountMsat: MilliSatoshis + ): Future[Vector[Route]] def forceClose(channelId: ChannelId): Future[ChannelCommandResult] @@ -97,7 +104,8 @@ trait EclairApi { def updateRelayFee( nodeId: NodeId, feeBaseMsat: MilliSatoshis, - feeProportionalMillionths: Long): Future[UpdateRelayFeeResult] + feeProportionalMillionths: Long + ): Future[UpdateRelayFeeResult] def updateRelayFee( nodeIds: Vector[NodeId], @@ -111,18 +119,20 @@ trait EclairApi { pushMsat: Option[MilliSatoshis], feerateSatPerByte: Option[SatoshisPerByte], channelFlags: Option[Byte], - openTimeout: Option[FiniteDuration]): Future[FundedChannelId] + openTimeout: Option[FiniteDuration] + ): Future[FundedChannelId] - /** The network that this [[org.bitcoins.eclair.rpc.api.EclairApi EclairApi]] is - * running on. This is not available directly from the eclair api, but is a very - * useful helper method + /** The network that this [[org.bitcoins.eclair.rpc.api.EclairApi EclairApi]] + * is running on. This is not available directly from the eclair api, but is + * a very useful helper method * @return */ def network: LnParams def networkFees( from: Option[FiniteDuration], - to: Option[FiniteDuration]): Future[Vector[NetworkFeesResult]] + to: Option[FiniteDuration] + ): Future[Vector[NetworkFeesResult]] def nodeId(): Future[NodeId] = { getNodeURI.map(_.nodeId) @@ -132,52 +142,63 @@ trait EclairApi { def createInvoice( description: String, - amountMsat: MilliSatoshis): Future[LnInvoice] + amountMsat: MilliSatoshis + ): Future[LnInvoice] def createInvoice( description: String, amountMsat: MilliSatoshis, - expireIn: FiniteDuration): Future[LnInvoice] + expireIn: FiniteDuration + ): Future[LnInvoice] def createInvoice( description: String, amountMsat: MilliSatoshis, - paymentPreimage: PaymentPreimage): Future[LnInvoice] + paymentPreimage: PaymentPreimage + ): Future[LnInvoice] def createInvoice( description: String, amountMsat: MilliSatoshis, expireIn: FiniteDuration, - paymentPreimage: PaymentPreimage): Future[LnInvoice] + paymentPreimage: PaymentPreimage + ): Future[LnInvoice] def createInvoice( description: String, amountMsat: Option[MilliSatoshis], expireIn: Option[FiniteDuration], fallbackAddress: Option[Address], - paymentPreimage: Option[PaymentPreimage]): Future[LnInvoice] + paymentPreimage: Option[PaymentPreimage] + ): Future[LnInvoice] /** Returns a future that is completed when this invoice has been paid too. - * This also publishes the [[IncomingPayment received payment result]] to the event bush - * when the payment is received + * This also publishes the [[IncomingPayment received payment result]] to the + * event bush when the payment is received * - * @param lnInvoice the invoice to monitor - * @param maxAttempts the number of attempts we ping eclair until we fail the returned future. Pinging occurrs every 1 second + * @param lnInvoice + * the invoice to monitor + * @param maxAttempts + * the number of attempts we ping eclair until we fail the returned future. + * Pinging occurrs every 1 second */ def monitorInvoice( lnInvoice: LnInvoice, interval: FiniteDuration, - maxAttempts: Int): Future[IncomingPayment] + maxAttempts: Int + ): Future[IncomingPayment] def getInvoice(paymentHash: Sha256Digest): Future[LnInvoice] def listInvoices( from: Option[Instant], - to: Option[Instant]): Future[Vector[LnInvoice]] + to: Option[Instant] + ): Future[Vector[LnInvoice]] def listPendingInvoices( from: Option[Instant], - to: Option[Instant]): Future[Vector[LnInvoice]] + to: Option[Instant] + ): Future[Vector[LnInvoice]] def parseInvoice(invoice: LnInvoice): Future[InvoiceResult] @@ -187,12 +208,14 @@ trait EclairApi { def payInvoice( invoice: LnInvoice, - externalId: Option[String]): Future[PaymentId] + externalId: Option[String] + ): Future[PaymentId] def payInvoice( invoice: LnInvoice, amount: MilliSatoshis, - externalId: Option[String]): Future[PaymentId] + externalId: Option[String] + ): Future[PaymentId] def payInvoice( invoice: LnInvoice, @@ -200,24 +223,32 @@ trait EclairApi { maxAttempts: Option[Int], feeThresholdSat: Option[Satoshis], maxFeePct: Option[Int], - externalId: Option[String]): Future[PaymentId] + externalId: Option[String] + ): Future[PaymentId] - /** Pings eclair to see if a invoice has been paid and returns [[OutgoingPayment PaymentResult]] + /** Pings eclair to see if a invoice has been paid and returns + * [[OutgoingPayment PaymentResult]] * - * @param paymentId the payment id returnned by [[org.bitcoins.eclair.rpc.api.EclairApi.payInvoice payInvoice]] - * @param interval the ping interval - * @param maxAttempts the maximum number of pings + * @param paymentId + * the payment id returnned by + * [[org.bitcoins.eclair.rpc.api.EclairApi.payInvoice payInvoice]] + * @param interval + * the ping interval + * @param maxAttempts + * the maximum number of pings */ def monitorSentPayment( paymentId: PaymentId, interval: FiniteDuration, - maxAttempts: Int): Future[OutgoingPayment] + maxAttempts: Int + ): Future[OutgoingPayment] def payAndMonitorInvoice( invoice: LnInvoice, externalId: Option[String], interval: FiniteDuration, - maxAttempts: Int): Future[OutgoingPayment] = + maxAttempts: Int + ): Future[OutgoingPayment] = for { paymentId <- payInvoice(invoice, externalId) paymentResult <- monitorSentPayment(paymentId, interval, maxAttempts) @@ -228,7 +259,8 @@ trait EclairApi { amount: MilliSatoshis, externalId: Option[String], interval: FiniteDuration, - maxAttempts: Int): Future[OutgoingPayment] = + maxAttempts: Int + ): Future[OutgoingPayment] = for { paymentId <- payInvoice(invoice, amount, externalId) paymentResult <- monitorSentPayment(paymentId, interval, maxAttempts) @@ -239,7 +271,8 @@ trait EclairApi { def getSentInfo(id: PaymentId): Future[Vector[OutgoingPayment]] def getReceivedInfo( - paymentHash: Sha256Digest): Future[Option[IncomingPayment]] + paymentHash: Sha256Digest + ): Future[Option[IncomingPayment]] def getReceivedInfo(invoice: LnInvoice): Future[Option[IncomingPayment]] @@ -249,7 +282,8 @@ trait EclairApi { maxAttempts: Option[Int], feeThresholdSat: Option[Satoshis], maxFeePct: Option[Int], - externalId: Option[String]): Future[PaymentId] + externalId: Option[String] + ): Future[PaymentId] /** Documented by not implemented in Eclair */ @@ -261,11 +295,14 @@ trait EclairApi { finalCltvExpiry: Long, recipientAmountMsat: Option[MilliSatoshis], parentId: Option[PaymentId], - externalId: Option[String]): Future[SendToRouteResult] + externalId: Option[String] + ): Future[SendToRouteResult] def usableBalances(): Future[Vector[UsableBalancesResult]] - /** Connects to the Eclair web socket end point and passes [[WebSocketEvent]]s to the given [[eventHandler]] */ + /** Connects to the Eclair web socket end point and passes [[WebSocketEvent]]s + * to the given [[eventHandler]] + */ def connectToWebSocket(eventHandler: WebSocketEvent => Unit): Future[Unit] def getNewAddress(): Future[BitcoinAddress] @@ -274,10 +311,12 @@ trait EclairApi { def onChainTransactions( count: Int, - skip: Int): Future[Vector[WalletTransaction]] + skip: Int + ): Future[Vector[WalletTransaction]] def sendOnChain( address: BitcoinAddress, amount: Satoshis, - confirmationTarget: Int): Future[DoubleSha256DigestBE] + confirmationTarget: Int + ): Future[DoubleSha256DigestBE] } diff --git a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/client/EclairRpcClient.scala b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/client/EclairRpcClient.scala index 02966a0a73..cdffdcacc4 100644 --- a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/client/EclairRpcClient.scala +++ b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/client/EclairRpcClient.scala @@ -56,12 +56,14 @@ import scala.concurrent.duration.{DurationInt, FiniteDuration} import scala.concurrent.{ExecutionContext, Future, Promise} import scala.util.{Failure, Properties, Success} -/** @param binary Path to Eclair Jar. If not present, reads - * environment variable `ECLAIR_PATH` +/** @param binary + * Path to Eclair Jar. If not present, reads environment variable + * `ECLAIR_PATH` */ class EclairRpcClient( val instance: EclairInstance, - binary: Option[File] = None)(implicit system: ActorSystem) + binary: Option[File] = None +)(implicit system: ActorSystem) extends EclairApi with NativeProcessFactory with StartStopAsync[EclairRpcClient] { @@ -93,11 +95,15 @@ class EclairRpcClient( */ override def audit( from: Option[Instant], - to: Option[Instant]): Future[AuditResult] = + to: Option[Instant] + ): Future[AuditResult] = eclairCall[AuditResult]( "audit", - Seq(from.map(x => "from" -> x.getEpochSecond.toString), - to.map(x => "to" -> x.getEpochSecond.toString)).flatten: _*) + Seq( + from.map(x => "from" -> x.getEpochSecond.toString), + to.map(x => "to" -> x.getEpochSecond.toString) + ).flatten: _* + ) override def channel(channelId: ChannelId): Future[ChannelResult] = { eclairCall[ChannelResult]("channel", "channelId" -> channelId.hex) @@ -116,7 +122,8 @@ class EclairRpcClient( private def close( channelId: ChannelId, shortChannelId: Option[ShortChannelId], - scriptPubKey: Option[ScriptPubKey]): Future[ChannelCommandResult] = { + scriptPubKey: Option[ScriptPubKey] + ): Future[ChannelCommandResult] = { val params = Seq("channelId" -> channelId.hex) ++ Seq( shortChannelId.map(x => "shortChannelId" -> x.toString), @@ -131,7 +138,8 @@ class EclairRpcClient( override def close( channelId: ChannelId, - scriptPubKey: ScriptPubKey): Future[ChannelCommandResult] = { + scriptPubKey: ScriptPubKey + ): Future[ChannelCommandResult] = { close(channelId, scriptPubKey = Some(scriptPubKey), shortChannelId = None) } @@ -141,7 +149,8 @@ class EclairRpcClient( override def connect( nodeId: NodeId, host: String, - port: Int): Future[Unit] = { + port: Int + ): Future[Unit] = { val uri = NodeUri(nodeId, host, port) connect(uri) } @@ -156,10 +165,13 @@ class EclairRpcClient( override def findRoute( nodeId: NodeId, - amountMsat: MilliSatoshis): Future[Vector[Route]] = { - eclairCall[Vector[Route]]("findroutetonode", - "nodeId" -> nodeId.toString, - "amountMsat" -> amountMsat.toBigDecimal.toString) + amountMsat: MilliSatoshis + ): Future[Vector[Route]] = { + eclairCall[Vector[Route]]( + "findroutetonode", + "nodeId" -> nodeId.toString, + "amountMsat" -> amountMsat.toBigDecimal.toString + ) } override def findRoute(invoice: LnInvoice): Future[Vector[Route]] = { @@ -168,29 +180,35 @@ class EclairRpcClient( override def findRoute( invoice: LnInvoice, - amount: MilliSatoshis): Future[Vector[Route]] = { + amount: MilliSatoshis + ): Future[Vector[Route]] = { findRoute(invoice, Some(amount)) } def findRoute( invoice: LnInvoice, - amountMsat: Option[MilliSatoshis]): Future[Vector[Route]] = { + amountMsat: Option[MilliSatoshis] + ): Future[Vector[Route]] = { val params = Seq( Some("invoice" -> invoice.toString), - amountMsat.map(x => "amountMsat" -> x.toBigDecimal.toString)).flatten + amountMsat.map(x => "amountMsat" -> x.toBigDecimal.toString) + ).flatten eclairCall[Vector[Route]]("findroute", params: _*) } override def forceClose( - channelId: ChannelId): Future[ChannelCommandResult] = { + channelId: ChannelId + ): Future[ChannelCommandResult] = { eclairCall[ChannelCommandResult]("forceclose", "channelId" -> channelId.hex) } override def forceClose( - shortChannelId: ShortChannelId): Future[ChannelCommandResult] = { + shortChannelId: ShortChannelId + ): Future[ChannelCommandResult] = { eclairCall[ChannelCommandResult]( "forceclose", - "shortChannelId" -> shortChannelId.toString) + "shortChannelId" -> shortChannelId.toString + ) } override def getInfo: Future[GetInfoResult] = { @@ -213,7 +231,8 @@ class EclairRpcClient( override def isConnected(nodeId: NodeId): Future[Boolean] = { getPeers.map( - _.exists(p => p.nodeId == nodeId && p.state == PeerState.CONNECTED)) + _.exists(p => p.nodeId == nodeId && p.state == PeerState.CONNECTED) + ) } override def network: LnParams = { @@ -226,60 +245,71 @@ class EclairRpcClient( pushMsat: Option[MilliSatoshis], feerateSatPerByte: Option[SatoshisPerByte], channelFlags: Option[Byte], - openTimeout: Option[FiniteDuration]): Future[FundedChannelId] = { + openTimeout: Option[FiniteDuration] + ): Future[FundedChannelId] = { val fundingSatoshis = funding.satoshis.toBigDecimal.toString val params: Seq[(String, String)] = - Seq("nodeId" -> nodeId.toString, - "fundingSatoshis" -> fundingSatoshis) ++ Seq( + Seq( + "nodeId" -> nodeId.toString, + "fundingSatoshis" -> fundingSatoshis + ) ++ Seq( pushMsat.map(x => "pushMsat" -> x.toBigDecimal.toString), feerateSatPerByte.map(x => "feerateSatPerByte" -> x.toLong.toString), channelFlags.map(x => "channelFlags" -> x.toString), openTimeout.map(x => "openTimeoutSeconds" -> x.toSeconds.toString) ).flatten - //this is unfortunately returned in this format - //created channel 30bdf849eb9f72c9b41a09e38a6d83138c2edf332cb116dd7cf0f0dfb66be395 + // this is unfortunately returned in this format + // created channel 30bdf849eb9f72c9b41a09e38a6d83138c2edf332cb116dd7cf0f0dfb66be395 val call = eclairCall[String]("open", params: _*) - //let's just return the chanId + // let's just return the chanId val chanIdF = call.map(_.split(" ").last) chanIdF.map(FundedChannelId.fromHex) } def open(nodeId: NodeId, funding: CurrencyUnit): Future[FundedChannelId] = { - open(nodeId, - funding, - pushMsat = None, - feerateSatPerByte = None, - channelFlags = None, - openTimeout = None) + open( + nodeId, + funding, + pushMsat = None, + feerateSatPerByte = None, + channelFlags = None, + openTimeout = None + ) } def open( nodeId: NodeId, funding: CurrencyUnit, - pushMsat: MilliSatoshis): Future[FundedChannelId] = { - open(nodeId, - funding, - Some(pushMsat), - feerateSatPerByte = None, - channelFlags = None, - openTimeout = None) + pushMsat: MilliSatoshis + ): Future[FundedChannelId] = { + open( + nodeId, + funding, + Some(pushMsat), + feerateSatPerByte = None, + channelFlags = None, + openTimeout = None + ) } def open( nodeId: NodeId, funding: CurrencyUnit, pushMsat: MilliSatoshis, - feerateSatPerByte: SatoshisPerByte): Future[FundedChannelId] = { - open(nodeId, - funding, - Some(pushMsat), - Some(feerateSatPerByte), - channelFlags = None, - openTimeout = None) + feerateSatPerByte: SatoshisPerByte + ): Future[FundedChannelId] = { + open( + nodeId, + funding, + Some(pushMsat), + Some(feerateSatPerByte), + channelFlags = None, + openTimeout = None + ) } def open( @@ -287,26 +317,32 @@ class EclairRpcClient( fundingSatoshis: CurrencyUnit, pushMsat: MilliSatoshis = MilliSatoshis.zero, feerateSatPerByte: SatoshisPerByte, - channelFlags: Byte): Future[FundedChannelId] = { - open(nodeId, - fundingSatoshis, - Some(pushMsat), - Some(feerateSatPerByte), - Some(channelFlags), - None) + channelFlags: Byte + ): Future[FundedChannelId] = { + open( + nodeId, + fundingSatoshis, + Some(pushMsat), + Some(feerateSatPerByte), + Some(channelFlags), + None + ) } def open( nodeId: NodeId, fundingSatoshis: CurrencyUnit, feerateSatPerByte: SatoshisPerByte, - channelFlags: Byte): Future[FundedChannelId] = { - open(nodeId, - fundingSatoshis, - pushMsat = None, - Some(feerateSatPerByte), - Some(channelFlags), - None) + channelFlags: Byte + ): Future[FundedChannelId] = { + open( + nodeId, + fundingSatoshis, + pushMsat = None, + Some(feerateSatPerByte), + Some(channelFlags), + None + ) } override def getPeers: Future[Vector[PeerInfo]] = { @@ -319,38 +355,46 @@ class EclairRpcClient( override def createInvoice( description: String, - amountMsat: MilliSatoshis): Future[LnInvoice] = { + amountMsat: MilliSatoshis + ): Future[LnInvoice] = { createInvoice(description, Some(amountMsat), None, None, None) } override def createInvoice( description: String, amountMsat: MilliSatoshis, - expireIn: FiniteDuration): Future[LnInvoice] = { + expireIn: FiniteDuration + ): Future[LnInvoice] = { createInvoice(description, Some(amountMsat), Some(expireIn), None, None) } override def createInvoice( description: String, amountMsat: MilliSatoshis, - paymentPreimage: PaymentPreimage): Future[LnInvoice] = { - createInvoice(description, - Some(amountMsat), - None, - None, - Some(paymentPreimage)) + paymentPreimage: PaymentPreimage + ): Future[LnInvoice] = { + createInvoice( + description, + Some(amountMsat), + None, + None, + Some(paymentPreimage) + ) } override def createInvoice( description: String, amountMsat: MilliSatoshis, expireIn: FiniteDuration, - paymentPreimage: PaymentPreimage): Future[LnInvoice] = { - createInvoice(description, - Some(amountMsat), - Some(expireIn), - None, - Some(paymentPreimage)) + paymentPreimage: PaymentPreimage + ): Future[LnInvoice] = { + createInvoice( + description, + Some(amountMsat), + Some(expireIn), + None, + Some(paymentPreimage) + ) } override def createInvoice( @@ -358,7 +402,8 @@ class EclairRpcClient( amountMsat: Option[MilliSatoshis], expireIn: Option[FiniteDuration], fallbackAddress: Option[Address], - paymentPreimage: Option[PaymentPreimage]): Future[LnInvoice] = { + paymentPreimage: Option[PaymentPreimage] + ): Future[LnInvoice] = { val params = Seq( Some("description" -> description), amountMsat.map(x => "amountMsat" -> x.toBigDecimal.toString), @@ -378,7 +423,8 @@ class EclairRpcClient( override def monitorInvoice( lnInvoice: LnInvoice, interval: FiniteDuration = 1.second, - maxAttempts: Int = 60): Future[IncomingPayment] = { + maxAttempts: Int = 60 + ): Future[IncomingPayment] = { val p: Promise[IncomingPayment] = Promise[IncomingPayment]() val attempts = new AtomicInteger(0) val runnable = new Runnable() { @@ -386,27 +432,31 @@ class EclairRpcClient( override def run(): Unit = { val receivedInfoF = getReceivedInfo(lnInvoice) - //register callback that publishes a payment to our actor system's - //event stream, + // register callback that publishes a payment to our actor system's + // event stream, receivedInfoF.foreach { case None | Some( - IncomingPayment(_, _, _, _, IncomingPaymentStatus.Pending)) => + IncomingPayment(_, _, _, _, IncomingPaymentStatus.Pending) + ) => if (attempts.incrementAndGet() >= maxAttempts) { // too many tries to get info about a payment // either Eclair is down or the payment is still in PENDING state for some reason // complete the promise with an exception so the runnable will be canceled - p.failure(new RuntimeException( - s"EclairApi.monitorInvoice() [${instance.authCredentials.datadir}] too many attempts: ${attempts - .get()} for invoice=${lnInvoice}")) + p.failure( + new RuntimeException( + s"EclairApi.monitorInvoice() [${instance.authCredentials.datadir}] too many attempts: ${attempts + .get()} for invoice=${lnInvoice}" + ) + ) } case Some(result) => - //invoice has been paid, let's publish to event stream - //so subscribers so the even stream can see that a payment - //was received - //we need to create a `PaymentSucceeded` + // invoice has been paid, let's publish to event stream + // so subscribers so the even stream can see that a payment + // was received + // we need to create a `PaymentSucceeded` system.eventStream.publish(result) - //complete the promise so the runnable will be canceled + // complete the promise so the runnable will be canceled p.success(result) } @@ -430,18 +480,21 @@ class EclairRpcClient( override def payInvoice( invoice: LnInvoice, - amount: MilliSatoshis): Future[PaymentId] = + amount: MilliSatoshis + ): Future[PaymentId] = payInvoice(invoice, Some(amount), None, None, None, None) override def payInvoice( invoice: LnInvoice, - externalId: Option[String]): Future[PaymentId] = + externalId: Option[String] + ): Future[PaymentId] = payInvoice(invoice, None, None, None, None, externalId) override def payInvoice( invoice: LnInvoice, amount: MilliSatoshis, - externalId: Option[String]): Future[PaymentId] = + externalId: Option[String] + ): Future[PaymentId] = payInvoice(invoice, Some(amount), None, None, None, externalId) override def payInvoice( @@ -450,7 +503,8 @@ class EclairRpcClient( maxAttempts: Option[Int], feeThresholdSat: Option[Satoshis], maxFeePct: Option[Int], - externalId: Option[String]): Future[PaymentId] = { + externalId: Option[String] + ): Future[PaymentId] = { val params = Seq( Some("invoice" -> invoice.toString), amountMsat.map(x => "amountMsat" -> x.toBigDecimal.toString), @@ -464,18 +518,20 @@ class EclairRpcClient( } override def getReceivedInfo( - paymentHash: Sha256Digest): Future[Option[IncomingPayment]] = { + paymentHash: Sha256Digest + ): Future[Option[IncomingPayment]] = { getReceivedInfo("paymentHash" -> paymentHash.hex) } override def getReceivedInfo( - invoice: LnInvoice): Future[Option[IncomingPayment]] = { + invoice: LnInvoice + ): Future[Option[IncomingPayment]] = { getReceivedInfo("invoice" -> invoice.toString) } private def getReceivedInfo(params: (String, String)*) = { - //eclair continues the tradition of not responding to things in json... - //the failure case here is the string 'Not found' + // eclair continues the tradition of not responding to things in json... + // the failure case here is the string 'Not found' implicit val r: Reads[Option[IncomingPayment]] = Reads { js => val result: JsResult[IncomingPayment] = js.validate[IncomingPayment] @@ -488,9 +544,12 @@ class EclairRpcClient( } override def getSentInfo( - paymentHash: Sha256Digest): Future[Vector[OutgoingPayment]] = { - eclairCall[Vector[OutgoingPayment]]("getsentinfo", - "paymentHash" -> paymentHash.hex) + paymentHash: Sha256Digest + ): Future[Vector[OutgoingPayment]] = { + eclairCall[Vector[OutgoingPayment]]( + "getsentinfo", + "paymentHash" -> paymentHash.hex + ) } override def getSentInfo(id: PaymentId): Future[Vector[OutgoingPayment]] = { @@ -503,9 +562,12 @@ class EclairRpcClient( maxAttempts: Option[Int], feeThresholdSat: Option[Satoshis], maxFeePct: Option[Int], - externalId: Option[String]): Future[PaymentId] = { - val params = Seq("nodeId" -> nodeId.toString, - "amountMsat" -> amountMsat.toBigDecimal.toString) ++ Seq( + externalId: Option[String] + ): Future[PaymentId] = { + val params = Seq( + "nodeId" -> nodeId.toString, + "amountMsat" -> amountMsat.toBigDecimal.toString + ) ++ Seq( maxAttempts.map(x => "maxAttempts" -> x.toString), feeThresholdSat.map(x => "feeThresholdSat" -> x.toBigDecimal.toString), maxFeePct.map(x => "maxFeePct" -> x.toString), @@ -523,7 +585,8 @@ class EclairRpcClient( finalCltvExpiry: Long, recipientAmountMsat: Option[MilliSatoshis], parentId: Option[PaymentId], - externalId: Option[String]): Future[SendToRouteResult] = { + externalId: Option[String] + ): Future[SendToRouteResult] = { val ids = route match { case NodeRoute(_, ids) => "nodeIds" -> ids.mkString(",") case ChannelRoute(_, ids) => "shortChannelIds" -> ids.mkString(",") @@ -534,23 +597,27 @@ class EclairRpcClient( "amountMsat" -> amountMsat.toBigDecimal.toString, "paymentHash" -> paymentHash.hex, "finalCltvExpiry" -> finalCltvExpiry.toString - ) ++ Seq(recipientAmountMsat.map(x => "recipientAmountMsat" -> x.toString), - parentId.map(x => "parentId" -> x.toString), - externalId.map(x => "externalId" -> x)).flatten + ) ++ Seq( + recipientAmountMsat.map(x => "recipientAmountMsat" -> x.toString), + parentId.map(x => "parentId" -> x.toString), + externalId.map(x => "externalId" -> x) + ).flatten eclairCall[SendToRouteResult]("sendtoroute", params: _*) } override def updateRelayFee( nodeId: NodeId, feeBaseMsat: MilliSatoshis, - feeProportionalMillionths: Long): Future[UpdateRelayFeeResult] = { + feeProportionalMillionths: Long + ): Future[UpdateRelayFeeResult] = { updateRelayFee(Vector(nodeId), feeBaseMsat, feeProportionalMillionths) } override def updateRelayFee( nodeIds: Vector[NodeId], feeBaseMsat: MilliSatoshis, - feeProportionalMillionths: Long): Future[UpdateRelayFeeResult] = { + feeProportionalMillionths: Long + ): Future[UpdateRelayFeeResult] = { eclairCall[UpdateRelayFeeResult]( "updaterelayfee", "nodeIds" -> nodeIds.map(_.hex).mkString(","), @@ -565,11 +632,15 @@ class EclairRpcClient( override def networkFees( from: Option[FiniteDuration], - to: Option[FiniteDuration]): Future[Vector[NetworkFeesResult]] = { + to: Option[FiniteDuration] + ): Future[Vector[NetworkFeesResult]] = { eclairCall[Vector[NetworkFeesResult]]( "networkfees", - Seq(from.map(x => "from" -> x.toSeconds.toString), - to.map(x => "to" -> x.toSeconds.toString)).flatten: _*) + Seq( + from.map(x => "from" -> x.toSeconds.toString), + to.map(x => "to" -> x.toSeconds.toString) + ).flatten: _* + ) } override def getInvoice(paymentHash: Sha256Digest): Future[LnInvoice] = { @@ -582,27 +653,34 @@ class EclairRpcClient( override def listInvoices( from: Option[Instant], - to: Option[Instant]): Future[Vector[LnInvoice]] = { + to: Option[Instant] + ): Future[Vector[LnInvoice]] = { listInvoices("listinvoices", from, to) } override def listPendingInvoices( from: Option[Instant], - to: Option[Instant]): Future[Vector[LnInvoice]] = { + to: Option[Instant] + ): Future[Vector[LnInvoice]] = { listInvoices("listpendinginvoices", from, to) } private def listInvoices( command: String, from: Option[Instant], - to: Option[Instant]): Future[Vector[LnInvoice]] = { + to: Option[Instant] + ): Future[Vector[LnInvoice]] = { val resF = eclairCall[Vector[InvoiceResult]]( command, - Seq(from.map(x => "from" -> x.getEpochSecond.toString), - to.map(x => "to" -> x.getEpochSecond.toString)).flatten: _*) + Seq( + from.map(x => "from" -> x.getEpochSecond.toString), + to.map(x => "to" -> x.getEpochSecond.toString) + ).flatten: _* + ) resF.flatMap(xs => Future.sequence( - xs.map(x => Future.fromTry(LnInvoice.fromStringT(x.serialized))))) + xs.map(x => Future.fromTry(LnInvoice.fromStringT(x.serialized))) + )) } override def usableBalances(): Future[Vector[UsableBalancesResult]] = { @@ -623,25 +701,31 @@ class EclairRpcClient( override def onChainTransactions( count: Int = 10, - skip: Int = 0): Future[Vector[WalletTransaction]] = { - eclairCall[Vector[WalletTransaction]]("onchaintransactions", - "count" -> count.toString, - "skip" -> skip.toString) + skip: Int = 0 + ): Future[Vector[WalletTransaction]] = { + eclairCall[Vector[WalletTransaction]]( + "onchaintransactions", + "count" -> count.toString, + "skip" -> skip.toString + ) } override def sendOnChain( address: BitcoinAddress, amount: Satoshis, - confirmationTarget: Int): Future[DoubleSha256DigestBE] = { + confirmationTarget: Int + ): Future[DoubleSha256DigestBE] = { eclairCall[DoubleSha256DigestBE]( "sendonchain", "address" -> address.toString, "amountSatoshis" -> amount.toLong.toString, - "confirmationTarget" -> confirmationTarget.toString) + "confirmationTarget" -> confirmationTarget.toString + ) } private def eclairCall[T](command: String, parameters: (String, String)*)( - implicit reader: Reads[T]): Future[T] = { + implicit reader: Reads[T] + ): Future[T] = { val request = buildRequest(getDaemon, command, parameters: _*) logger.trace(s"eclair rpc call ${request}") @@ -661,7 +745,8 @@ class EclairRpcClient( private def parseResult[T]( result: JsResult[T], json: JsValue, - commandName: String): T = { + commandName: String + ): T = { result match { case res: JsSuccess[T] => res.value @@ -678,10 +763,12 @@ class EclairRpcClient( case _: JsError => logger.error( s"Could not parse JsResult for command=$commandName: ${JsError - .toJson(res) - .toString()} JSON ${json}") + .toJson(res) + .toString()} JSON ${json}" + ) throw new IllegalArgumentException( - s"Could not parse JsResult for command=$commandName") + s"Could not parse JsResult for command=$commandName" + ) } } } @@ -698,8 +785,10 @@ class EclairRpcClient( private lazy val http = Http(system) private lazy val httpConnectionPoolSettings = - Socks5ClientTransport.createConnectionPoolSettings(instance.rpcUri, - instance.proxyParams) + Socks5ClientTransport.createConnectionPoolSettings( + instance.rpcUri, + instance.proxyParams + ) private def sendRequest(req: HttpRequest): Future[HttpResponse] = { http.singleRequest(req, settings = httpConnectionPoolSettings) @@ -708,17 +797,21 @@ class EclairRpcClient( private def buildRequest( instance: EclairInstance, methodName: String, - params: (String, String)*): HttpRequest = { + params: (String, String)* + ): HttpRequest = { val uri = instance.rpcUri.resolve("/" + methodName).toString // Eclair doesn't use a username val username = "" val password = instance.authCredentials.password - HttpRequest(method = HttpMethods.POST, - uri, - entity = FormData(params: _*).toEntity) + HttpRequest( + method = HttpMethods.POST, + uri, + entity = FormData(params: _*).toEntity + ) .addCredentials( - HttpCredentials.createBasicHttpCredentials(username, password)) + HttpCredentials.createBasicHttpCredentials(username, password) + ) } private def pathToEclairJar: String = { @@ -730,7 +823,8 @@ class EclairRpcClient( binary.toString } else { throw new NoSuchFileException( - s"Given binary ($binary) does not exist!") + s"Given binary ($binary) does not exist!" + ) } case (None, Some(path)) => val eclairBinDir = @@ -746,12 +840,14 @@ class EclairRpcClient( jar.getPath } else { throw new NoSuchFileException( - s"Could not Eclair Jar at location ${jar.getPath}") + s"Could not Eclair Jar at location ${jar.getPath}" + ) } case (None, None) => val msg = List( "Environment variable ECLAIR_PATH is not set, and no binary is given!", - "Either needs to be set in order to start Eclair.") + "Either needs to be set in order to start Eclair." + ) throw new RuntimeException(msg.mkString(" ")) } } @@ -768,9 +864,9 @@ class EclairRpcClient( /** Starts eclair on the local system. * - * @return a future of the started EclairRpcClient when eclair is fully started. - * If eclair has not successfully started in 60 seconds - * the future times out. + * @return + * a future of the started EclairRpcClient when eclair is fully started. If + * eclair has not successfully started in 60 seconds the future times out. */ override def start(): Future[EclairRpcClient] = { @@ -779,16 +875,19 @@ class EclairRpcClient( val started: Future[EclairRpcClient] = { for { _ <- startedBinaryF - _ <- AsyncUtil.retryUntilSatisfiedF(() => isStarted(), - interval = 1.seconds, - maxTries = 60) + _ <- AsyncUtil.retryUntilSatisfiedF( + () => isStarted(), + interval = 1.seconds, + maxTries = 60 + ) } yield this } started } /** Boolean check to verify the state of the client - * @return Future Boolean representing if client has started + * @return + * Future Boolean representing if client has started */ def isStarted(): Future[Boolean] = { val p = Promise[Boolean]() @@ -803,9 +902,10 @@ class EclairRpcClient( p.future } - /** Returns a Future EclairRpcClient if able to shut down - * Eclair instance, inherits from the StartStop trait - * @return A future EclairRpcClient that is stopped + /** Returns a Future EclairRpcClient if able to shut down Eclair instance, + * inherits from the StartStop trait + * @return + * A future EclairRpcClient that is stopped */ override def stop(): Future[EclairRpcClient] = { val stoppedF = stopBinary() @@ -827,21 +927,22 @@ class EclairRpcClient( isStarted().map(started => !started) } - /** Pings eclair to see if a invoice has been paid - * If the invoice has been paid or the payment has failed, we publish a - * [[OutgoingPayment]] - * event to the [[org.apache.pekko.actor.ActorSystem ActorSystem]]'s + /** Pings eclair to see if a invoice has been paid If the invoice has been + * paid or the payment has failed, we publish a [[OutgoingPayment]] event to + * the [[org.apache.pekko.actor.ActorSystem ActorSystem]]'s * [[org.apache.pekko.event.EventStream ActorSystem.eventStream]] * - * We also return a Future[PaymentResult] that is completed when one of three things is true - * 1. The payment has succeeded - * 2. The payment has failed - * 3. We have attempted to query the eclair more than maxAttempts, and the payment is still pending + * We also return a Future[PaymentResult] that is completed when one of three + * things is true + * 1. The payment has succeeded 2. The payment has failed 3. We have + * attempted to query the eclair more than maxAttempts, and the payment + * is still pending */ override def monitorSentPayment( paymentId: PaymentId, interval: FiniteDuration, - maxAttempts: Int): Future[OutgoingPayment] = { + maxAttempts: Int + ): Future[OutgoingPayment] = { val p: Promise[OutgoingPayment] = Promise[OutgoingPayment]() val runnable = new Runnable() { @@ -856,13 +957,16 @@ class EclairRpcClient( p.failure( new RuntimeException( s"EclairApi.monitorSentPayment() too many attempts: ${attempts - .get()} for paymentId=${paymentId} for interval=${interval}")) + .get()} for paymentId=${paymentId} for interval=${interval}" + ) + ) } else { val resultsF = getSentInfo(paymentId) resultsF.failed.foreach { case e: Throwable => logger.error( s"Cannot check payment status for paymentId=${paymentId}", - e) + e + ) } val _ = for { results <- resultsF @@ -870,7 +974,7 @@ class EclairRpcClient( results.foreach { result => result.status match { case OutgoingPaymentStatus.Pending => - //do nothing, while we wait for eclair to attempt to process + // do nothing, while we wait for eclair to attempt to process case (_: OutgoingPaymentStatus.Succeeded | _: OutgoingPaymentStatus.Failed) => // invoice has been succeeded or has failed, let's publish to event stream @@ -898,7 +1002,8 @@ class EclairRpcClient( /** @inheritdoc */ override def connectToWebSocket( - eventHandler: WebSocketEvent => Unit): Future[Unit] = { + eventHandler: WebSocketEvent => Unit + ): Future[Unit] = { val incoming: Sink[Message, Future[Done]] = Sink.foreach[Message] { case message: TextMessage.Strict => @@ -925,7 +1030,10 @@ class EclairRpcClient( uri, extraHeaders = Vector( Authorization( - BasicHttpCredentials("", instance.authCredentials.password)))) + BasicHttpCredentials("", instance.authCredentials.password) + ) + ) + ) val (upgradeResponse, _) = Http().singleWebSocketRequest(request, flow) val connected = upgradeResponse.map { upgrade => @@ -933,7 +1041,8 @@ class EclairRpcClient( Done } else { throw new RuntimeException( - s"Connection failed: ${upgrade.response.status}") + s"Connection failed: ${upgrade.response.status}" + ) } } @@ -946,28 +1055,29 @@ class EclairRpcClient( object EclairRpcClient { - /** THe name we use to create actor systems. We use this to know which - * actor systems to shut down on node shutdown + /** THe name we use to create actor systems. We use this to know which actor + * systems to shut down on node shutdown */ private[eclair] val ActorSystemName = "eclair-rpc-client-created-by-bitcoin-s" - /** Creates an RPC client from the given instance, - * together with the given actor system. This is for - * advanced users, wher you need fine grained control - * over the RPC client. + /** Creates an RPC client from the given instance, together with the given + * actor system. This is for advanced users, wher you need fine grained + * control over the RPC client. */ def apply( instance: EclairInstance, - binary: Option[File] = None): EclairRpcClient = { + binary: Option[File] = None + ): EclairRpcClient = { implicit val system = ActorSystem.create(ActorSystemName) withActorSystem(instance, binary) } - /** Constructs a RPC client from the given datadir, or - * the default datadir if no directory is provided + /** Constructs a RPC client from the given datadir, or the default datadir if + * no directory is provided */ def withActorSystem(instance: EclairInstance, binary: Option[File] = None)( - implicit system: ActorSystem) = new EclairRpcClient(instance, binary) + implicit system: ActorSystem + ) = new EclairRpcClient(instance, binary) /** The current commit we support of Eclair */ private[bitcoins] val commit = "0077471" @@ -975,8 +1085,10 @@ object EclairRpcClient { /** The current version we support of Eclair */ private[bitcoins] val version = "0.8.0" - /** The bitcoind version that eclair is officially tested & supported with by ACINQ - * @see https://github.com/ACINQ/eclair/releases/tag/v0.8.0 + /** The bitcoind version that eclair is officially tested & supported with by + * ACINQ + * @see + * https://github.com/ACINQ/eclair/releases/tag/v0.8.0 */ val bitcoindV: BitcoindVersion = BitcoindVersion.V23 } diff --git a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/config/EclairAuthCredentials.scala b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/config/EclairAuthCredentials.scala index 07c302abcb..1e1ec0e979 100644 --- a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/config/EclairAuthCredentials.scala +++ b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/config/EclairAuthCredentials.scala @@ -34,19 +34,21 @@ sealed trait EclairAuthCredentials { def rpcPort: Int def copyWithDatadir(datadir: File): EclairAuthCredentials = { - EclairAuthCredentials(password = password, - bitcoinAuthOpt = bitcoinAuthOpt, - rpcPort = rpcPort, - bitcoindRpcUri = bitcoindRpcUri, - datadir = Some(datadir)) + EclairAuthCredentials( + password = password, + bitcoinAuthOpt = bitcoinAuthOpt, + rpcPort = rpcPort, + bitcoindRpcUri = bitcoindRpcUri, + datadir = Some(datadir) + ) } } /** @define fromConfigDoc - * Parses a [[com.typesafe.config.Config Config]] in the format of this - * [[https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/resources/reference.conf sample reference.conf]] - * file to a - * [[org.bitcoins.eclair.rpc.config.EclairAuthCredentials EclairAuthCredentials]] + * Parses a [[com.typesafe.config.Config Config]] in the format of this + * [[https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/resources/reference.conf sample reference.conf]] + * file to a + * [[org.bitcoins.eclair.rpc.config.EclairAuthCredentials EclairAuthCredentials]] */ object EclairAuthCredentials { @@ -55,20 +57,23 @@ object EclairAuthCredentials { bitcoinAuthOpt: Option[BitcoindAuthCredentials], rpcPort: Int, bitcoindRpcUri: URI, - datadir: Option[File]) - extends EclairAuthCredentials + datadir: Option[File] + ) extends EclairAuthCredentials def apply( password: String, bitcoinAuthOpt: Option[BitcoindAuthCredentials], rpcPort: Int, bitcoindRpcUri: URI, - datadir: Option[File] = None): EclairAuthCredentials = { - AuthCredentialsImpl(password, - bitcoinAuthOpt, - rpcPort, - bitcoindRpcUri, - datadir) + datadir: Option[File] = None + ): EclairAuthCredentials = { + AuthCredentialsImpl( + password, + bitcoinAuthOpt, + rpcPort, + bitcoindRpcUri, + datadir + ) } def fromDatadir(datadir: File): EclairAuthCredentials = { @@ -90,36 +95,43 @@ object EclairAuthCredentials { private[config] def fromConfig( config: Config, - datadir: Option[File]): EclairAuthCredentials = { + datadir: Option[File] + ): EclairAuthCredentials = { val bitcoindUsername = config.getString("eclair.bitcoind.rpcuser") val bitcoindPassword = config.getString("eclair.bitcoind.rpcpassword") val defaultBitcoindPort = getDefaultBitcoindRpcPort(config) val bitcoindRpcPort = - ConfigUtil.getIntOrElse(config, - "eclair.bitcoind.rpcport", - defaultBitcoindPort) + ConfigUtil.getIntOrElse( + config, + "eclair.bitcoind.rpcport", + defaultBitcoindPort + ) val bitcoindRpcHost = ConfigUtil.getStringOrElse(config, "eclair.bitcoind.host", "localhost") val bitcoindUri = new URI(s"http://$bitcoindRpcHost:$bitcoindRpcPort") - //does eclair not have a username field?? + // does eclair not have a username field?? val password = config.getString("eclair.api.password") val eclairRpcPort = ConfigUtil.getIntOrElse(config, "eclair.api.port", 8080) val bitcoindAuth = { - BitcoindAuthCredentials.PasswordBased(username = bitcoindUsername, - password = bitcoindPassword) + BitcoindAuthCredentials.PasswordBased( + username = bitcoindUsername, + password = bitcoindPassword + ) } - EclairAuthCredentials(password = password, - bitcoinAuthOpt = Some(bitcoindAuth), - rpcPort = eclairRpcPort, - bitcoindRpcUri = bitcoindUri, - datadir = datadir) + EclairAuthCredentials( + password = password, + bitcoinAuthOpt = Some(bitcoindAuth), + rpcPort = eclairRpcPort, + bitcoindRpcUri = bitcoindUri, + datadir = datadir + ) } private def getDefaultBitcoindRpcPort(config: Config): Int = { @@ -130,7 +142,8 @@ object EclairAuthCredentials { case "regtest" => RegTest.rpcPort case _: String => throw new IllegalArgumentException( - s"Got invalid chain parameter $network ") + s"Got invalid chain parameter $network " + ) } } diff --git a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/config/EclairInstance.scala b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/config/EclairInstance.scala index c8c4b38aae..b7b47bcb10 100644 --- a/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/config/EclairInstance.scala +++ b/eclair-rpc/src/main/scala/org/bitcoins/eclair/rpc/config/EclairInstance.scala @@ -31,10 +31,9 @@ sealed trait EclairInstanceLocal extends EclairInstance sealed trait EclairInstanceRemote extends EclairInstance /** @define fromConfigDoc - * Parses a [[com.typesafe.config.Config Config]] in the format of this - * [[https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/resources/reference.conf sample reference.conf]] - * file to a - * [[org.bitcoins.eclair.rpc.config.EclairInstance EclairInstance]] + * Parses a [[com.typesafe.config.Config Config]] in the format of this + * [[https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/resources/reference.conf sample reference.conf]] + * file to a [[org.bitcoins.eclair.rpc.config.EclairInstance EclairInstance]] */ object EclairInstanceLocal extends InstanceFactoryLocal[EclairInstanceLocal, ActorSystem] { @@ -48,8 +47,8 @@ object EclairInstanceLocal bitcoindRpcUri: Option[URI], bitcoindAuthCredentials: Option[BitcoindAuthCredentials], zmqConfig: Option[ZmqConfig], - proxyParams: Option[Socks5ProxyParams]) - extends EclairInstanceLocal + proxyParams: Option[Socks5ProxyParams] + ) extends EclairInstanceLocal def apply( network: NetworkParameters, @@ -62,15 +61,17 @@ object EclairInstanceLocal bitcoindAuthCredentials: Option[BitcoindAuthCredentials] = None, zmqConfig: Option[ZmqConfig] = None ): EclairInstance = { - EclairInstanceLocalImpl(network, - uri, - rpcUri, - authCredentials, - logbackXmlPath, - bitcoindRpcUri, - bitcoindAuthCredentials, - zmqConfig, - proxyParams) + EclairInstanceLocalImpl( + network, + uri, + rpcUri, + authCredentials, + logbackXmlPath, + bitcoindRpcUri, + bitcoindAuthCredentials, + zmqConfig, + proxyParams + ) } override val DEFAULT_DATADIR: Path = Paths.get(Properties.userHome, ".eclair") @@ -86,7 +87,8 @@ object EclairInstanceLocal def fromDatadir( datadir: File = DEFAULT_DATADIR.toFile, logbackXml: Option[String], - proxyParams: Option[Socks5ProxyParams]): EclairInstanceLocal = { + proxyParams: Option[Socks5ProxyParams] + ): EclairInstanceLocal = { require(datadir.exists, s"${datadir.getPath} does not exist!") require(datadir.isDirectory, s"${datadir.getPath} is not a directory!") @@ -97,13 +99,15 @@ object EclairInstanceLocal } override def fromConfigFile(file: File = DEFAULT_CONF_FILE.toFile)(implicit - system: ActorSystem): EclairInstanceLocal = + system: ActorSystem + ): EclairInstanceLocal = fromConfFile(file, None, None) def fromConfFile( file: File = DEFAULT_CONF_FILE.toFile, logbackXml: Option[String], - proxyParams: Option[Socks5ProxyParams]): EclairInstanceLocal = { + proxyParams: Option[Socks5ProxyParams] + ): EclairInstanceLocal = { require(file.exists, s"${file.getPath} does not exist!") require(file.isFile, s"${file.getPath} is not a file!") @@ -112,8 +116,9 @@ object EclairInstanceLocal fromConfig(config, file.getParentFile, logbackXml, proxyParams) } - override def fromDataDir(dir: File = DEFAULT_DATADIR.toFile)(implicit - system: ActorSystem): EclairInstanceLocal = { + override def fromDataDir( + dir: File = DEFAULT_DATADIR.toFile + )(implicit system: ActorSystem): EclairInstanceLocal = { require(dir.exists, s"${dir.getPath} does not exist!") require(dir.isDirectory, s"${dir.getPath} is not a directory!") @@ -127,7 +132,8 @@ object EclairInstanceLocal config: Config, datadir: File, logbackXml: Option[String], - proxyParams: Option[Socks5ProxyParams]): EclairInstanceLocal = { + proxyParams: Option[Socks5ProxyParams] + ): EclairInstanceLocal = { fromConfig(config, Some(datadir), logbackXml, proxyParams) } @@ -141,24 +147,29 @@ object EclairInstanceLocal config: Config, datadir: Option[File], logbackXml: Option[String], - proxyParams: Option[Socks5ProxyParams]): EclairInstanceLocal = { + proxyParams: Option[Socks5ProxyParams] + ): EclairInstanceLocal = { val chain = ConfigUtil.getStringOrElse(config, "eclair.chain", "testnet") // default conf: https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/resources/reference.conf val serverBindingIp = ConfigUtil.getStringOrElse(config, "eclair.server.binding-ip", "0.0.0.0") - val serverPort = ConfigUtil.getIntOrElse(config, - "eclair.server.port", - LnPolicy.DEFAULT_LN_P2P_PORT) + val serverPort = ConfigUtil.getIntOrElse( + config, + "eclair.server.port", + LnPolicy.DEFAULT_LN_P2P_PORT + ) // default conf: https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/resources/reference.conf val rpcHost = ConfigUtil.getStringOrElse(config, "eclair.api.binding-ip", "127.0.0.1") - val rpcPort = ConfigUtil.getIntOrElse(config, - "eclair.api.port", - LnPolicy.DEFAULT_ECLAIR_API_PORT) + val rpcPort = ConfigUtil.getIntOrElse( + config, + "eclair.api.port", + LnPolicy.DEFAULT_ECLAIR_API_PORT + ) val np: NetworkParameters = chain match { case "regtest" => RegTest @@ -166,7 +177,8 @@ object EclairInstanceLocal case "mainnet" => MainNet case network: String => throw new IllegalArgumentException( - s"Unknown network $network in eclair.conf") + s"Unknown network $network in eclair.conf" + ) } val uri: URI = new URI(s"http://$serverBindingIp:$serverPort") diff --git a/esplora-test/src/test/scala/org/bitcoins/esplora/EsploraClientTest.scala b/esplora-test/src/test/scala/org/bitcoins/esplora/EsploraClientTest.scala index d90ef33c31..d2409175a5 100644 --- a/esplora-test/src/test/scala/org/bitcoins/esplora/EsploraClientTest.scala +++ b/esplora-test/src/test/scala/org/bitcoins/esplora/EsploraClientTest.scala @@ -27,7 +27,8 @@ class EsploraClientTest extends BitcoinSAsyncTest { it must "get a transaction details" in { val txId = DoubleSha256DigestBE( - "7940246d561ecb869de19e91e306249eb0dfae84df43e59568b3f7092ce3190a") + "7940246d561ecb869de19e91e306249eb0dfae84df43e59568b3f7092ce3190a" + ) client .getTransaction(txId) .map { details => @@ -39,32 +40,45 @@ class EsploraClientTest extends BitcoinSAsyncTest { assert(details.status.confirmed) assert(details.status.block_height.exists(_ == 720542)) assert(details.status.block_time.exists(_ == 1643245253)) - assert(details.status.block_hash.exists(_ == DoubleSha256DigestBE( - "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185"))) + assert( + details.status.block_hash.exists( + _ == DoubleSha256DigestBE( + "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185" + ) + ) + ) } } it must "get a transaction status" in { val txId = DoubleSha256DigestBE( - "7940246d561ecb869de19e91e306249eb0dfae84df43e59568b3f7092ce3190a") + "7940246d561ecb869de19e91e306249eb0dfae84df43e59568b3f7092ce3190a" + ) client .getTransactionStatus(txId) .map { status => assert(status.block_height.exists(_ == 720542)) assert(status.block_time.exists(_ == 1643245253)) - assert(status.block_hash.exists(_ == DoubleSha256DigestBE( - "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185"))) + assert( + status.block_hash.exists( + _ == DoubleSha256DigestBE( + "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185" + ) + ) + ) } } it must "get a raw transaction" in { val txId = DoubleSha256DigestBE( - "7940246d561ecb869de19e91e306249eb0dfae84df43e59568b3f7092ce3190a") + "7940246d561ecb869de19e91e306249eb0dfae84df43e59568b3f7092ce3190a" + ) client .getRawTransaction(txId) .map { tx => val expected = Transaction( - "02000000017fc73ba05900f3b0eb2b3adb53b6899d2275a8f008fab03e01d6d5b4d8fd2aa8000000006b483045022100bb4bdad155b4f9431c279ef90fd2c7591fec8b194efa5fc022820906e1078b0f02201154bfd58ae73c44ea3df26c6ae7e41d9b39e2a2daa6fe9141c91db3fe37e8cb0121029da6c25d85a88c8a5f5982b1dacf88af00aba4239814015882238fd20cea022effffffff0222f20400000000001976a914b7122afa54297d62b3ff4666c2d07c4593f62bb588acdc030000000000001976a914e0fcab102a97ff6ffe8cd47e8e083da1918d0e0988ac00000000") + "02000000017fc73ba05900f3b0eb2b3adb53b6899d2275a8f008fab03e01d6d5b4d8fd2aa8000000006b483045022100bb4bdad155b4f9431c279ef90fd2c7591fec8b194efa5fc022820906e1078b0f02201154bfd58ae73c44ea3df26c6ae7e41d9b39e2a2daa6fe9141c91db3fe37e8cb0121029da6c25d85a88c8a5f5982b1dacf88af00aba4239814015882238fd20cea022effffffff0222f20400000000001976a914b7122afa54297d62b3ff4666c2d07c4593f62bb588acdc030000000000001976a914e0fcab102a97ff6ffe8cd47e8e083da1918d0e0988ac00000000" + ) assert(tx == expected) } @@ -94,7 +108,8 @@ class EsploraClientTest extends BitcoinSAsyncTest { BitcoinAddress.fromString("bc1qzd3y2pumhgtkrv5h2x96jaxgs056wvuwgqygac") val txid = DoubleSha256DigestBE( - "d4cbc49e9d6d051c5e23b843d06b5a187b506d238588e94bdb488f3846324bdc") + "d4cbc49e9d6d051c5e23b843d06b5a187b506d238588e94bdb488f3846324bdc" + ) client.getAddressTxs(addr, txid).map { txs => assert(txs.nonEmpty) @@ -114,7 +129,8 @@ class EsploraClientTest extends BitcoinSAsyncTest { it must "get a block" in { val hash = DoubleSha256DigestBE( - "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185") + "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185" + ) client.getBlock(hash).map { block => assert(block.id == hash) @@ -131,7 +147,8 @@ class EsploraClientTest extends BitcoinSAsyncTest { it must "get a block header" in { val hash = DoubleSha256DigestBE( - "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185") + "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185" + ) client.getBlockHeader(hash).map { header => assert(header.hashBE == hash) @@ -140,7 +157,8 @@ class EsploraClientTest extends BitcoinSAsyncTest { it must "get a raw block" in { val hash = DoubleSha256DigestBE( - "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185") + "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185" + ) client.getRawBlock(hash).map { block => assert(block.blockHeader.hashBE == hash) @@ -149,7 +167,8 @@ class EsploraClientTest extends BitcoinSAsyncTest { it must "get a block's height " in { val expected = DoubleSha256DigestBE( - "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185") + "000000000000000000074110fd51c9e34b9ea10ea88ce7fa43bf2cf80a3c2185" + ) client.getBlockHashAtHeight(720542).map { hash => assert(hash == expected) diff --git a/esplora/src/main/scala/org/bitcoins/esplora/EsploraClient.scala b/esplora/src/main/scala/org/bitcoins/esplora/EsploraClient.scala index 48a4d32878..f3e8345815 100644 --- a/esplora/src/main/scala/org/bitcoins/esplora/EsploraClient.scala +++ b/esplora/src/main/scala/org/bitcoins/esplora/EsploraClient.scala @@ -21,20 +21,24 @@ import scala.concurrent._ import scala.util.control.NonFatal class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( - implicit system: ActorSystem) - extends ChainQueryApi { + implicit system: ActorSystem +) extends ChainQueryApi { implicit val ec: ExecutionContext = system.dispatcher - require(!site.isTor || site.isTor && proxyParams.isDefined, - "proxyParams must be defined for a tor esplora site") + require( + !site.isTor || site.isTor && proxyParams.isDefined, + "proxyParams must be defined for a tor esplora site" + ) private val baseUrl = site.url private val httpClient: HttpExt = Http(system) private val httpConnectionPoolSettings = - Socks5ClientTransport.createConnectionPoolSettings(new URI(baseUrl), - proxyParams) + Socks5ClientTransport.createConnectionPoolSettings( + new URI(baseUrl), + proxyParams + ) private def sendRawRequest(request: HttpRequest): Future[ByteString] = { httpClient @@ -49,15 +53,17 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( .map(payload => payload.decodeString(ByteString.UTF_8)) } - private def sendRequestAndParse[T](httpRequest: HttpRequest)(implicit - reads: Reads[T]): Future[T] = { + private def sendRequestAndParse[T]( + httpRequest: HttpRequest + )(implicit reads: Reads[T]): Future[T] = { sendRequest(httpRequest).map { str => val json = Json.parse(str) json.validate[T] match { case JsSuccess(value, _) => value case JsError(errors) => throw new RuntimeException( - s"Error parsing json $json, ${errors.mkString("\n")}") + s"Error parsing json $json, ${errors.mkString("\n")}" + ) } } } @@ -70,7 +76,8 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( } def getTransactionStatus( - txId: DoubleSha256DigestBE): Future[EsploraTransactionStatus] = { + txId: DoubleSha256DigestBE + ): Future[EsploraTransactionStatus] = { val url = baseUrl + s"/tx/${txId.hex}/status" val request = HttpRequest(uri = url, method = HttpMethods.GET) @@ -102,7 +109,8 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( } def getAddressTxs( - addr: BitcoinAddress): Future[Vector[EsploraTransaction]] = { + addr: BitcoinAddress + ): Future[Vector[EsploraTransaction]] = { val url = baseUrl + s"/address/$addr/txs" val request = HttpRequest(uri = url, method = HttpMethods.GET) @@ -111,8 +119,8 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( def getAddressTxs( addr: BitcoinAddress, - lastSeenTxId: DoubleSha256DigestBE): Future[ - Vector[EsploraTransaction]] = { + lastSeenTxId: DoubleSha256DigestBE + ): Future[Vector[EsploraTransaction]] = { val url = baseUrl + s"/address/$addr/txs/chain/${lastSeenTxId.hex}" val request = HttpRequest(uri = url, method = HttpMethods.GET) @@ -120,7 +128,8 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( } def getMempoolTxs( - addr: BitcoinAddress): Future[Vector[EsploraTransaction]] = { + addr: BitcoinAddress + ): Future[Vector[EsploraTransaction]] = { val url = baseUrl + s"/address/$addr/txs/mempool" val request = HttpRequest(uri = url, method = HttpMethods.GET) @@ -160,7 +169,8 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( // -- ChainQueryApi -- override def getBestHashBlockHeight()(implicit - _ec: ExecutionContext): Future[Int] = { + _ec: ExecutionContext + ): Future[Int] = { val url = baseUrl + s"/blocks/tip/height" val request = HttpRequest(uri = url, method = HttpMethods.GET) @@ -175,7 +185,8 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( } override def getBlockHeight( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = { + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = { getBlock(blockHash) .map(_.height) .map(Some(_)) @@ -183,7 +194,8 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( } override def getNumberOfConfirmations( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = { + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = { val tipF = getBestHashBlockHeight() val heightF = getBlockHeight(blockHash) @@ -194,7 +206,8 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( } override def getFilterCount(): Future[Int] = Future.failed( - new UnsupportedOperationException("Esplora does not support block filters")) + new UnsupportedOperationException("Esplora does not support block filters") + ) override def getHeightByBlockStamp(blockStamp: BlockStamp): Future[Int] = { blockStamp match { @@ -205,16 +218,21 @@ class EsploraClient(site: EsploraSite, proxyParams: Option[Socks5ProxyParams])( case blockTime: BlockStamp.BlockTime => Future.failed( new UnsupportedOperationException( - s"Not implemented for Esplora Client: $blockTime")) + s"Not implemented for Esplora Client: $blockTime" + ) + ) } } override def getFiltersBetweenHeights( startHeight: Int, - endHeight: Int): Future[Vector[ChainQueryApi.FilterResponse]] = + endHeight: Int + ): Future[Vector[ChainQueryApi.FilterResponse]] = Future.failed( new UnsupportedOperationException( - "Esplora does not support block filters")) + "Esplora does not support block filters" + ) + ) override def epochSecondToBlockHeight(time: Long): Future[Int] = Future.successful(0) diff --git a/esplora/src/main/scala/org/bitcoins/esplora/EsploraJsonModels.scala b/esplora/src/main/scala/org/bitcoins/esplora/EsploraJsonModels.scala index 2dcc378df9..1e330b63ff 100644 --- a/esplora/src/main/scala/org/bitcoins/esplora/EsploraJsonModels.scala +++ b/esplora/src/main/scala/org/bitcoins/esplora/EsploraJsonModels.scala @@ -17,8 +17,8 @@ object EsploraJsonModels { confirmed: Boolean, block_height: Option[Long], block_hash: Option[DoubleSha256DigestBE], - block_time: Option[Long]) - extends EsploraJsonModel + block_time: Option[Long] + ) extends EsploraJsonModel implicit val EsploraTransactionStatusReads: Reads[EsploraTransactionStatus] = Json.reads[EsploraTransactionStatus] @@ -30,8 +30,8 @@ object EsploraJsonModels { size: Int, weight: Int, fee: Satoshis, - status: EsploraTransactionStatus) - extends EsploraJsonModel + status: EsploraTransactionStatus + ) extends EsploraJsonModel implicit val EsploraTransactionReads: Reads[EsploraTransaction] = Json.reads[EsploraTransaction] @@ -40,8 +40,8 @@ object EsploraJsonModels { funded_txo_count: Int, funded_txo_sum: Satoshis, spent_txo_count: Int, - spent_txo_sum: Satoshis) - extends EsploraJsonModel + spent_txo_sum: Satoshis + ) extends EsploraJsonModel implicit val addressChainStatsReads: Reads[AddressChainStats] = Json.reads[AddressChainStats] @@ -49,8 +49,8 @@ object EsploraJsonModels { case class AddressStats( address: BitcoinAddress, chain_stats: AddressChainStats, - mempool_stats: AddressChainStats) - extends EsploraJsonModel { + mempool_stats: AddressChainStats + ) extends EsploraJsonModel { val totalReceived: CurrencyUnit = chain_stats.funded_txo_sum + mempool_stats.funded_txo_sum diff --git a/fee-provider-test/src/test/scala/org/bitcoins/feeprovider/FeeRateProviderTest.scala b/fee-provider-test/src/test/scala/org/bitcoins/feeprovider/FeeRateProviderTest.scala index c15b547621..c23d15a59c 100644 --- a/fee-provider-test/src/test/scala/org/bitcoins/feeprovider/FeeRateProviderTest.scala +++ b/fee-provider-test/src/test/scala/org/bitcoins/feeprovider/FeeRateProviderTest.scala @@ -89,7 +89,8 @@ class FeeRateProviderTest extends BitcoinSAsyncTest { it must "fail to create a BitcoinerLiveFeeRateProvider with invalid minutes" in { assertThrows[IllegalArgumentException]( - BitcoinerLiveFeeRateProvider(-1, proxyParams)) + BitcoinerLiveFeeRateProvider(-1, proxyParams) + ) } it must "get the correct fee rate from a ConstantFeeRateProvider" in { diff --git a/fee-provider/src/main/scala/org/bitcoins/feeprovider/BitGoFeeRateProvider.scala b/fee-provider/src/main/scala/org/bitcoins/feeprovider/BitGoFeeRateProvider.scala index c9fe296cd1..c02749dcd5 100644 --- a/fee-provider/src/main/scala/org/bitcoins/feeprovider/BitGoFeeRateProvider.scala +++ b/fee-provider/src/main/scala/org/bitcoins/feeprovider/BitGoFeeRateProvider.scala @@ -11,12 +11,13 @@ import play.api.libs.json.{JsError, JsSuccess, Json} import scala.util.{Failure, Success, Try} /** Fetches fee rate from BitGo's API - * @see [[https://www.bitgo.com/api/v2/#operation/v2.tx.getfeeestimate]] + * @see + * [[https://www.bitgo.com/api/v2/#operation/v2.tx.getfeeestimate]] */ case class BitGoFeeRateProvider( blockTargetOpt: Option[Int], - proxyParams: Option[Socks5ProxyParams])(implicit - override val system: ActorSystem) + proxyParams: Option[Socks5ProxyParams] +)(implicit override val system: ActorSystem) extends CachedHttpFeeRateProvider[SatoshisPerKiloByte] { override val uri: Uri = Uri("https://www.bitgo.com/api/v2/btc/tx/fee") @@ -35,13 +36,16 @@ case class BitGoFeeRateProvider( case JsError(error) => Failure( new RuntimeException( - s"Unexpected error when parsing response $str: $error")) + s"Unexpected error when parsing response $str: $error" + ) + ) } } private def extractFeerate( feeRanges: Map[Int, SatoshisPerKiloByte], - blockTarget: Int): SatoshisPerKiloByte = { + blockTarget: Int + ): SatoshisPerKiloByte = { // first we keep only fee ranges with a max block delay below the limit val belowLimit = feeRanges.filter(_._1 <= blockTarget) // out of all the remaining fee ranges, we select the one with the minimum higher bound @@ -53,8 +57,8 @@ object BitGoFeeRateProvider extends FeeProviderFactory[BitGoFeeRateProvider] { override def fromBlockTarget( blocks: Int, - proxyParams: Option[Socks5ProxyParams])(implicit - system: ActorSystem): BitGoFeeRateProvider = { + proxyParams: Option[Socks5ProxyParams] + )(implicit system: ActorSystem): BitGoFeeRateProvider = { BitGoFeeRateProvider(Some(blocks), proxyParams) } } diff --git a/fee-provider/src/main/scala/org/bitcoins/feeprovider/BitcoinerLiveFeeRateProvider.scala b/fee-provider/src/main/scala/org/bitcoins/feeprovider/BitcoinerLiveFeeRateProvider.scala index 862c5485c8..6257a505fc 100644 --- a/fee-provider/src/main/scala/org/bitcoins/feeprovider/BitcoinerLiveFeeRateProvider.scala +++ b/fee-provider/src/main/scala/org/bitcoins/feeprovider/BitcoinerLiveFeeRateProvider.scala @@ -13,12 +13,14 @@ import scala.util.{Failure, Success, Try} case class BitcoinerLiveFeeRateProvider( minutes: Int, - proxyParams: Option[Socks5ProxyParams])(implicit - override val system: ActorSystem) + proxyParams: Option[Socks5ProxyParams] +)(implicit override val system: ActorSystem) extends CachedHttpFeeRateProvider[SatoshisPerVirtualByte] { - require(validMinutes.contains(minutes), - s"$minutes is not a valid selection, must be from $validMinutes") + require( + validMinutes.contains(minutes), + s"$minutes is not a valid selection, must be from $validMinutes" + ) override val uri: Uri = Uri("https://bitcoiner.live/api/fees/estimates/latest") @@ -31,7 +33,9 @@ case class BitcoinerLiveFeeRateProvider( case JsError(error) => Failure( new RuntimeException( - s"Unexpected error when parsing response: $error")) + s"Unexpected error when parsing response: $error" + ) + ) } } } @@ -44,10 +48,12 @@ object BitcoinerLiveFeeRateProvider override def fromBlockTarget( blocks: Int, - proxyParams: Option[Socks5ProxyParams])(implicit - system: ActorSystem): BitcoinerLiveFeeRateProvider = { - require(blocks > 0, - s"Cannot have a negative or zero block target, got $blocks") + proxyParams: Option[Socks5ProxyParams] + )(implicit system: ActorSystem): BitcoinerLiveFeeRateProvider = { + require( + blocks > 0, + s"Cannot have a negative or zero block target, got $blocks" + ) val blockTargets = validMinutes.map(_ / 10) diff --git a/fee-provider/src/main/scala/org/bitcoins/feeprovider/FallbackFeeRateApi.scala b/fee-provider/src/main/scala/org/bitcoins/feeprovider/FallbackFeeRateApi.scala index bc36cd2a7b..e0c20985e5 100644 --- a/fee-provider/src/main/scala/org/bitcoins/feeprovider/FallbackFeeRateApi.scala +++ b/fee-provider/src/main/scala/org/bitcoins/feeprovider/FallbackFeeRateApi.scala @@ -7,12 +7,12 @@ import org.bitcoins.core.wallet.fee.FeeUnit import scala.concurrent.{ExecutionContext, Future} import scala.util.control.NonFatal -/** Takes multiple [[FeeRateApi FeeRateApis]] and attempts to get a fee rate from - * one in order until one succeeds. +/** Takes multiple [[FeeRateApi FeeRateApis]] and attempts to get a fee rate + * from one in order until one succeeds. */ case class FallbackFeeRateApi(providers: Vector[FeeRateApi])(implicit - ec: ExecutionContext) - extends FeeRateApi { + ec: ExecutionContext +) extends FeeRateApi { override def getFeeRate(): Future[FeeUnit] = { val init: Option[FeeUnit] = None diff --git a/fee-provider/src/main/scala/org/bitcoins/feeprovider/FeeProviderFactory.scala b/fee-provider/src/main/scala/org/bitcoins/feeprovider/FeeProviderFactory.scala index 3ea6df132d..ec07abdab2 100644 --- a/fee-provider/src/main/scala/org/bitcoins/feeprovider/FeeProviderFactory.scala +++ b/fee-provider/src/main/scala/org/bitcoins/feeprovider/FeeProviderFactory.scala @@ -17,20 +17,22 @@ import org.bitcoins.feeprovider.MempoolSpaceTarget.HourFeeTarget trait FeeProviderFactory[T <: FeeRateApi] { def fromBlockTarget(blocks: Int, proxyParams: Option[Socks5ProxyParams])( - implicit system: ActorSystem): T + implicit system: ActorSystem + ): T } object FeeProviderFactory extends BitcoinSLogger { - /** Gets a Fee Provider from the given wallet app config - * Returns default if there is no config set + /** Gets a Fee Provider from the given wallet app config Returns default if + * there is no config set */ def getFeeProviderOrElse( default: => FeeRateApi, feeProviderNameStrOpt: Option[String], feeProviderTargetOpt: Option[Int], proxyParamsOpt: Option[Socks5ProxyParams], - network: BitcoinNetwork)(implicit system: ActorSystem): FeeRateApi = { + network: BitcoinNetwork + )(implicit system: ActorSystem): FeeRateApi = { val feeProviderNameOpt = feeProviderNameStrOpt.flatMap(FeeProviderName.fromStringOpt) @@ -53,7 +55,8 @@ object FeeProviderFactory extends BitcoinSLogger { ConstantFeeRateProvider(SatoshisPerVirtualByte.fromLong(num)) case (Some(Constant), None) => throw new IllegalArgumentException( - "Missing a target for a ConstantFeeRateProvider") + "Missing a target for a ConstantFeeRateProvider" + ) } logger.info(s"Using fee provider: $feeProvider") diff --git a/fee-provider/src/main/scala/org/bitcoins/feeprovider/HttpFeeRateProvider.scala b/fee-provider/src/main/scala/org/bitcoins/feeprovider/HttpFeeRateProvider.scala index 076df7d7ff..b892b7b62f 100644 --- a/fee-provider/src/main/scala/org/bitcoins/feeprovider/HttpFeeRateProvider.scala +++ b/fee-provider/src/main/scala/org/bitcoins/feeprovider/HttpFeeRateProvider.scala @@ -18,7 +18,8 @@ import scala.util.Try object HttpFeeRateProvider { def makeApiCall(uri: Uri, proxyParam: Option[Socks5ProxyParams])(implicit - system: ActorSystem): Future[String] = { + system: ActorSystem + ): Future[String] = { implicit val ec: ExecutionContextExecutor = system.dispatcher val connectionPoolSettings = Socks5ClientTransport.createConnectionPoolSettings(proxyParam) diff --git a/fee-provider/src/main/scala/org/bitcoins/feeprovider/MempoolSpaceProvider.scala b/fee-provider/src/main/scala/org/bitcoins/feeprovider/MempoolSpaceProvider.scala index 43fa63c921..7cd508db96 100644 --- a/fee-provider/src/main/scala/org/bitcoins/feeprovider/MempoolSpaceProvider.scala +++ b/fee-provider/src/main/scala/org/bitcoins/feeprovider/MempoolSpaceProvider.scala @@ -12,14 +12,14 @@ import play.api.libs.json.{JsError, JsSuccess, Json} import scala.util.{Failure, Success, Try} -/** Fetches fee rate from mempool.space's API - * Documentation found here: https://mempool.space/about +/** Fetches fee rate from mempool.space's API Documentation found here: + * https://mempool.space/about */ case class MempoolSpaceProvider( target: MempoolSpaceTarget, network: BitcoinNetwork, - proxyParams: Option[Socks5ProxyParams])(implicit - override val system: ActorSystem) + proxyParams: Option[Socks5ProxyParams] +)(implicit override val system: ActorSystem) extends CachedHttpFeeRateProvider[SatoshisPerVirtualByte] { override val uri: Uri = network match { @@ -49,7 +49,9 @@ case class MempoolSpaceProvider( case JsError(error) => Failure( new RuntimeException( - s"Unexpected error when parsing response: $error")) + s"Unexpected error when parsing response: $error" + ) + ) } } } @@ -58,8 +60,8 @@ object MempoolSpaceProvider extends FeeProviderFactory[MempoolSpaceProvider] { override def fromBlockTarget( blocks: Int, - proxyParams: Option[Socks5ProxyParams])(implicit - system: ActorSystem): MempoolSpaceProvider = { + proxyParams: Option[Socks5ProxyParams] + )(implicit system: ActorSystem): MempoolSpaceProvider = { val target = MempoolSpaceTarget.fromBlockTarget(blocks) MempoolSpaceProvider(target, MainNet, proxyParams) } @@ -67,8 +69,8 @@ object MempoolSpaceProvider extends FeeProviderFactory[MempoolSpaceProvider] { def fromBlockTarget( blocks: Int, network: BitcoinNetwork, - proxyParams: Option[Socks5ProxyParams])(implicit - system: ActorSystem): MempoolSpaceProvider = { + proxyParams: Option[Socks5ProxyParams] + )(implicit system: ActorSystem): MempoolSpaceProvider = { val target = MempoolSpaceTarget.fromBlockTarget(blocks) MempoolSpaceProvider(target, network, proxyParams) } @@ -87,7 +89,8 @@ object MempoolSpaceTarget { def fromBlockTarget(blocks: Int): MempoolSpaceTarget = { if (blocks <= 0) { throw new IllegalArgumentException( - s"Cannot have a negative or zero block target, got $blocks") + s"Cannot have a negative or zero block target, got $blocks" + ) } else if (blocks < 3) { FastestFeeTarget } else if (blocks < 6) { diff --git a/key-manager-test/src/test/scala/org/bitcoins/keymanager/WalletStorageTest.scala b/key-manager-test/src/test/scala/org/bitcoins/keymanager/WalletStorageTest.scala index 5ab50108e7..2166784ff9 100644 --- a/key-manager-test/src/test/scala/org/bitcoins/keymanager/WalletStorageTest.scala +++ b/key-manager-test/src/test/scala/org/bitcoins/keymanager/WalletStorageTest.scala @@ -31,10 +31,12 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { behavior of "WalletStorage" val passphrase: Some[AesPassword] = Some( - AesPassword.fromNonEmptyString("this_is_secret")) + AesPassword.fromNonEmptyString("this_is_secret") + ) val badPassphrase: Some[AesPassword] = Some( - AesPassword.fromNonEmptyString("this_is_also_secret")) + AesPassword.fromNonEmptyString("this_is_also_secret") + ) def getAndWriteMnemonic(walletConf: WalletAppConfig): DecryptedMnemonic = { val mnemonicCode = CryptoGenerators.mnemonicCode.sampleSome @@ -73,7 +75,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { // Need to compare using getEpochSecond because when reading an epoch second // it will not include the milliseconds that writtenMnemonic will have assert( - writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond) + writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond + ) assert(writtenMnemonic.backupTimeOpt.isEmpty) case Right(xprv: DecryptedExtPrivKey) => fail(s"Parsed unexpected type of seed $xprv") @@ -98,7 +101,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { // Need to compare using getEpochSecond because when reading an epoch second // it will not include the milliseconds that writtenMnemonic will have assert( - writtenXprv.creationTime.getEpochSecond == readXprv.creationTime.getEpochSecond) + writtenXprv.creationTime.getEpochSecond == readXprv.creationTime.getEpochSecond + ) case Right(readMnemonic: DecryptedMnemonic) => fail(s"Parsed unexpected type of seed $readMnemonic") case Left(err) => fail(err.toString) @@ -124,7 +128,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { // Need to compare using getEpochSecond because when reading an epoch second // it will not include the milliseconds that writtenMnemonic will have assert( - writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond) + writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond + ) case Right(xprv: DecryptedExtPrivKey) => fail(s"Parsed unexpected type of seed $xprv") case Left(err) => fail(err.toString) @@ -149,7 +154,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { // Need to compare using getEpochSecond because when reading an epoch second // it will not include the milliseconds that writtenMnemonic will have assert( - writtenXprv.creationTime.getEpochSecond == readXprv.creationTime.getEpochSecond) + writtenXprv.creationTime.getEpochSecond == readXprv.creationTime.getEpochSecond + ) case Right(readMnemonic: DecryptedMnemonic) => fail(s"Parsed unexpected type of seed $readMnemonic") case Left(err) => fail(err.toString) @@ -165,9 +171,11 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { assert(walletConf.kmConf.seedExists()) val seedPath = getSeedPath(walletConf) - WalletStorage.changeAesPassword(seedPath = seedPath, - oldPasswordOpt = passphrase, - newPasswordOpt = badPassphrase) + WalletStorage.changeAesPassword( + seedPath = seedPath, + oldPasswordOpt = passphrase, + newPasswordOpt = badPassphrase + ) val read = WalletStorage.decryptSeedFromDisk(seedPath, badPassphrase) @@ -177,7 +185,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { // Need to compare using getEpochSecond because when reading an epoch second // it will not include the milliseconds that writtenMnemonic will have assert( - writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond) + writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond + ) case Right(xprv: DecryptedExtPrivKey) => fail(s"Parsed unexpected type of seed $xprv") case Left(err) => fail(err.toString) @@ -195,9 +204,11 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { assert(walletConf.kmConf.seedExists()) - WalletStorage.changeAesPassword(seedPath = seedPath, - oldPasswordOpt = None, - newPasswordOpt = badPassphrase) + WalletStorage.changeAesPassword( + seedPath = seedPath, + oldPasswordOpt = None, + newPasswordOpt = badPassphrase + ) val read = WalletStorage.decryptSeedFromDisk(seedPath, badPassphrase) @@ -207,7 +218,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { // Need to compare using getEpochSecond because when reading an epoch second // it will not include the milliseconds that writtenMnemonic will have assert( - writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond) + writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond + ) case Right(xprv: DecryptedExtPrivKey) => fail(s"Parsed unexpected type of seed $xprv") case Left(err) => fail(err.toString) @@ -223,9 +235,11 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { assert(walletConf.kmConf.seedExists()) val seedPath = getSeedPath(walletConf) - WalletStorage.changeAesPassword(seedPath = seedPath, - oldPasswordOpt = passphrase, - newPasswordOpt = None) + WalletStorage.changeAesPassword( + seedPath = seedPath, + oldPasswordOpt = passphrase, + newPasswordOpt = None + ) val read = WalletStorage.decryptSeedFromDisk(seedPath, None) @@ -235,7 +249,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { // Need to compare using getEpochSecond because when reading an epoch second // it will not include the milliseconds that writtenMnemonic will have assert( - writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond) + writtenMnemonic.creationTime.getEpochSecond == readMnemonic.creationTime.getEpochSecond + ) case Right(xprv: DecryptedExtPrivKey) => fail(s"Parsed unexpected type of seed $xprv") case Left(err) => fail(err.toString) @@ -252,9 +267,12 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { val seedPath = getSeedPath(walletConf) assertThrows[RuntimeException]( - WalletStorage.changeAesPassword(seedPath = seedPath, - oldPasswordOpt = badPassphrase, - newPasswordOpt = badPassphrase)) + WalletStorage.changeAesPassword( + seedPath = seedPath, + oldPasswordOpt = badPassphrase, + newPasswordOpt = badPassphrase + ) + ) } it must "fail to change the aes password when given no password" in { @@ -267,9 +285,12 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { val seedPath = getSeedPath(walletConf) assertThrows[RuntimeException]( - WalletStorage.changeAesPassword(seedPath = seedPath, - oldPasswordOpt = None, - newPasswordOpt = badPassphrase)) + WalletStorage.changeAesPassword( + seedPath = seedPath, + oldPasswordOpt = None, + newPasswordOpt = badPassphrase + ) + ) } it must "fail to set the aes password when given an oldPassword" in { @@ -284,9 +305,12 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { assert(walletConf.kmConf.seedExists()) assertThrows[RuntimeException]( - WalletStorage.changeAesPassword(seedPath = seedPath, - oldPasswordOpt = passphrase, - newPasswordOpt = badPassphrase)) + WalletStorage.changeAesPassword( + seedPath = seedPath, + oldPasswordOpt = passphrase, + newPasswordOpt = badPassphrase + ) + ) } it must "read an encrypted mnemonic without a creation time" in { @@ -304,13 +328,16 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { Files.write(seedPath, badJson.getBytes()) val read = - WalletStorage.decryptSeedFromDisk(seedPath, - Some(BIP39KeyManager.badPassphrase)) + WalletStorage.decryptSeedFromDisk( + seedPath, + Some(BIP39KeyManager.badPassphrase) + ) read match { case Right(readMnemonic) => assert( - readMnemonic.creationTime.getEpochSecond == WalletStorage.FIRST_BITCOIN_S_WALLET_TIME) + readMnemonic.creationTime.getEpochSecond == WalletStorage.FIRST_BITCOIN_S_WALLET_TIME + ) case Left(err) => fail(err.toString) } } @@ -332,7 +359,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { read match { case Right(readMnemonic) => assert( - readMnemonic.creationTime.getEpochSecond == WalletStorage.FIRST_BITCOIN_S_WALLET_TIME) + readMnemonic.creationTime.getEpochSecond == WalletStorage.FIRST_BITCOIN_S_WALLET_TIME + ) case Left(err) => fail(err.toString) } } @@ -593,7 +621,7 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { assert(walletConf.kmConf.seedExists()) assertThrows[RuntimeException] { - //attempt to write another mnemonic + // attempt to write another mnemonic getAndWriteMnemonic(walletConf) } } @@ -607,8 +635,10 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { val writtenMnemonic = getAndWriteMnemonic(walletConf) val expected = BIP39Seed - .fromMnemonic(mnemonic = writtenMnemonic.mnemonicCode, - password = password) + .fromMnemonic( + mnemonic = writtenMnemonic.mnemonicCode, + password = password + ) .toExtPrivateKey(keyVersion) .toHardened @@ -616,10 +646,12 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { assert(walletConf.kmConf.seedExists()) val seedPath = getSeedPath(walletConf) val read = - WalletStorage.getPrivateKeyFromDisk(seedPath, - keyVersion, - passphrase, - Some(password)) + WalletStorage.getPrivateKeyFromDisk( + seedPath, + keyVersion, + passphrase, + Some(password) + ) assert(read == expected) } @@ -637,18 +669,22 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { val keyVersion = SegWitMainNetPriv val expected = BIP39Seed - .fromMnemonic(mnemonic = writtenMnemonic.mnemonicCode, - password = password) + .fromMnemonic( + mnemonic = writtenMnemonic.mnemonicCode, + password = password + ) .toExtPrivateKey(keyVersion) .toHardened // should have been written by now assert(walletConf.kmConf.seedExists()) val read = - WalletStorage.getPrivateKeyFromDisk(seedPath, - keyVersion, - None, - Some(password)) + WalletStorage.getPrivateKeyFromDisk( + seedPath, + keyVersion, + None, + Some(password) + ) assert(read == expected) } @@ -660,7 +696,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { val keyVersion = SegWitMainNetPriv assertThrows[RuntimeException]( - WalletStorage.getPrivateKeyFromDisk(seedPath, keyVersion, None, None)) + WalletStorage.getPrivateKeyFromDisk(seedPath, keyVersion, None, None) + ) } @@ -674,7 +711,9 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { val walletConfB = walletConfA.withOverrides( ConfigFactory.parseString( - s"bitcoin-s.wallet.walletName = $otherWalletName")) + s"bitcoin-s.wallet.walletName = $otherWalletName" + ) + ) assert(!walletConfB.kmConf.seedExists()) getAndWriteXprv(walletConfB) @@ -725,7 +764,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { assertThrows[AlreadyBackedUpException]( WalletStorage .readDecryptedSeedPhraseForBackup(walletConf.seedPath, None) - .get) + .get + ) } it must "backup an encrypted seed" in { walletConf: WalletAppConfig => @@ -754,7 +794,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { assertThrows[AlreadyBackedUpException]( WalletStorage .readDecryptedSeedPhraseForBackup(walletConf.seedPath, passphrase) - .get) + .get + ) } it must "set imported flag for an encrypted seed" in { @@ -763,10 +804,10 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { val seedPath = getSeedPath(walletConf) val mnemonicCode = CryptoGenerators.mnemonicCode.sampleSome - val writtenMnemonic = DecryptedMnemonic(mnemonicCode, - TimeUtil.now, - None, - false).encrypt(passphrase.get) + val writtenMnemonic = + DecryptedMnemonic(mnemonicCode, TimeUtil.now, None, false).encrypt( + passphrase.get + ) WalletStorage.writeSeedToDisk(seedPath, writtenMnemonic) WalletStorage.decryptSeedFromDisk(walletConf.seedPath, passphrase) match { @@ -778,7 +819,8 @@ class WalletStorageTest extends BitcoinSWalletTest with BeforeAndAfterEach { val importedWrittenMnemonic = DecryptedMnemonic(mnemonicCode, TimeUtil.now, None, true).encrypt( - passphrase.get) + passphrase.get + ) WalletStorage.writeSeedToDisk(seedPath, importedWrittenMnemonic) WalletStorage.decryptSeedFromDisk(walletConf.seedPath, passphrase) match { diff --git a/key-manager-test/src/test/scala/org/bitcoins/keymanager/bip39/BIP39KeyManagerApiTest.scala b/key-manager-test/src/test/scala/org/bitcoins/keymanager/bip39/BIP39KeyManagerApiTest.scala index 13da0882f2..ee69805e3b 100644 --- a/key-manager-test/src/test/scala/org/bitcoins/keymanager/bip39/BIP39KeyManagerApiTest.scala +++ b/key-manager-test/src/test/scala/org/bitcoins/keymanager/bip39/BIP39KeyManagerApiTest.scala @@ -25,7 +25,7 @@ import java.nio.file.Files class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val purpose = HDPurposes.Legacy - //this is taken from 'trezor-addresses.json' which give us test cases that conform with trezor + // this is taken from 'trezor-addresses.json' which give us test cases that conform with trezor val mnemonicStr = "stage boring net gather radar radio arrest eye ask risk girl country" val mnemonic = MnemonicCode.fromWords(mnemonicStr.split(" ").toVector) @@ -48,25 +48,32 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val entropy = MnemonicCode.getEntropy256Bits val aesPasswordOpt = KeyManagerTestUtil.aesPasswordOpt val keyManager = - withInitializedKeyManager(aesPasswordOpt = aesPasswordOpt, - entropy = entropy) + withInitializedKeyManager( + aesPasswordOpt = aesPasswordOpt, + entropy = entropy + ) val seedPath = keyManager.kmParams.seedPath - //verify we wrote the seed - assert(WalletStorage.seedExists(seedPath), - "KeyManager did not write the seed to disk!") + // verify we wrote the seed + assert( + WalletStorage.seedExists(seedPath), + "KeyManager did not write the seed to disk!" + ) val decryptedE = WalletStorage.decryptSeedFromDisk(seedPath, aesPasswordOpt) decryptedE match { case Right(mnemonic: DecryptedMnemonic) => - assert(mnemonic.mnemonicCode.toEntropy == entropy, - s"We did not read the same entropy that we wrote!") + assert( + mnemonic.mnemonicCode.toEntropy == entropy, + s"We did not read the same entropy that we wrote!" + ) case Right(xprv: DecryptedExtPrivKey) => fail(s"Parsed unexpected type of seed $xprv") case Left(err) => fail( - s"Failed to read mnemonic that was written by key manager with err=$err") + s"Failed to read mnemonic that was written by key manager with err=$err" + ) } } @@ -74,38 +81,47 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val kmParams = buildParams() - val keyManager = withInitializedKeyManager(kmParams = kmParams, - entropy = mnemonic.toEntropy, - bip39PasswordOpt = None) + val keyManager = withInitializedKeyManager( + kmParams = kmParams, + entropy = mnemonic.toEntropy, + bip39PasswordOpt = None + ) keyManager.deriveXPub(hdAccount).get.toString must be( - "xpub6D36zpm3tLPy3dBCpiScEpmmgsivFBcHxX5oXmPBW982BmLiEkjBEDdswxFUoeXpp272QuSpNKZ3f2TdEMkAHyCz1M7P3gFkYJJVEsM66SE") + "xpub6D36zpm3tLPy3dBCpiScEpmmgsivFBcHxX5oXmPBW982BmLiEkjBEDdswxFUoeXpp272QuSpNKZ3f2TdEMkAHyCz1M7P3gFkYJJVEsM66SE" + ) } it must "initialize a key manager to the same xpub if we call constructor directly or use CreateKeyManagerApi" in { val kmParams = buildParams() val direct = - BIP39KeyManager.fromMnemonic(mnemonic, - kmParams, - None, - TimeUtil.now, - false) + BIP39KeyManager.fromMnemonic( + mnemonic, + kmParams, + None, + TimeUtil.now, + false + ) val directXpub = direct.getRootXPub val api = BIP39KeyManager - .initializeWithEntropy(aesPasswordOpt = KeyManagerTestUtil.aesPasswordOpt, - entropy = mnemonic.toEntropy, - bip39PasswordOpt = None, - kmParams = kmParams) + .initializeWithEntropy( + aesPasswordOpt = KeyManagerTestUtil.aesPasswordOpt, + entropy = mnemonic.toEntropy, + bip39PasswordOpt = None, + kmParams = kmParams + ) .getOrElse(fail()) val apiXpub = api.getRootXPub - assert(apiXpub == directXpub, - s"We don't have initialization symmetry between our constructors!") + assert( + apiXpub == directXpub, + s"We don't have initialization symmetry between our constructors!" + ) - //we should be able to derive the same child xpub + // we should be able to derive the same child xpub assert(api.deriveXPub(hdAccount) == direct.deriveXPub(hdAccount)) } @@ -113,27 +129,33 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val kmParams = buildParams() val bip39Pw = KeyManagerTestUtil.bip39Password val direct = - BIP39KeyManager.fromMnemonic(mnemonic, - kmParams, - Some(bip39Pw), - TimeUtil.now, - false) + BIP39KeyManager.fromMnemonic( + mnemonic, + kmParams, + Some(bip39Pw), + TimeUtil.now, + false + ) val directXpub = direct.getRootXPub val api = BIP39KeyManager - .initializeWithEntropy(aesPasswordOpt = KeyManagerTestUtil.aesPasswordOpt, - mnemonic.toEntropy, - Some(bip39Pw), - kmParams) + .initializeWithEntropy( + aesPasswordOpt = KeyManagerTestUtil.aesPasswordOpt, + mnemonic.toEntropy, + Some(bip39Pw), + kmParams + ) .getOrElse(fail()) val apiXpub = api.getRootXPub - assert(apiXpub == directXpub, - s"We don't have initialization symmetry between our constructors!") + assert( + apiXpub == directXpub, + s"We don't have initialization symmetry between our constructors!" + ) - //we should be able to derive the same child xpub + // we should be able to derive the same child xpub assert(api.deriveXPub(hdAccount) == direct.deriveXPub(hdAccount)) } @@ -141,17 +163,21 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val kmParams = buildParams() val bip39Pw = KeyManagerTestUtil.bip39Password val direct = - BIP39KeyManager.fromMnemonic(mnemonic, - kmParams, - Some(bip39Pw), - TimeUtil.now, - false) + BIP39KeyManager.fromMnemonic( + mnemonic, + kmParams, + Some(bip39Pw), + TimeUtil.now, + false + ) val decryptedMnemonic = DecryptedMnemonic(mnemonic, direct.creationTime, None, false) val password = AesPassword.fromNonEmptyString("password") - WalletStorage.writeSeedToDisk(kmParams.seedPath, - decryptedMnemonic.encrypt(password)) + WalletStorage.writeSeedToDisk( + kmParams.seedPath, + decryptedMnemonic.encrypt(password) + ) val directXpub = direct.getRootXPub val api = @@ -161,10 +187,12 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val apiXpub = api.getRootXPub - assert(apiXpub == directXpub, - s"We don't have initialization symmetry between our constructors!") + assert( + apiXpub == directXpub, + s"We don't have initialization symmetry between our constructors!" + ) - //we should be able to derive the same child xpub + // we should be able to derive the same child xpub assert(api.deriveXPub(hdAccount) == direct.deriveXPub(hdAccount)) } @@ -173,11 +201,13 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val bip39Pw = KeyManagerTestUtil.bip39Password val direct = - BIP39KeyManager.fromMnemonic(mnemonic, - kmParams, - Some(bip39Pw), - TimeUtil.now, - false) + BIP39KeyManager.fromMnemonic( + mnemonic, + kmParams, + Some(bip39Pw), + TimeUtil.now, + false + ) val seed = BIP39Seed.fromMnemonic(mnemonic, Some(bip39Pw)) val privVersion = HDUtil.getXprivVersion(kmParams.purpose, kmParams.network) val rootExtPrivKey = seed.toExtPrivateKey(privVersion) @@ -185,8 +215,10 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val decryptedXprv = DecryptedExtPrivKey(rootExtPrivKey, direct.creationTime, None, false) val password = AesPassword.fromNonEmptyString("password") - WalletStorage.writeSeedToDisk(kmParams.seedPath, - decryptedXprv.encrypt(password)) + WalletStorage.writeSeedToDisk( + kmParams.seedPath, + decryptedXprv.encrypt(password) + ) val directXpub = direct.getRootXPub val api = @@ -196,10 +228,12 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val apiXpub = api.getRootXPub - assert(apiXpub == directXpub, - s"We don't have initialization symmetry between our constructors!") + assert( + apiXpub == directXpub, + s"We don't have initialization symmetry between our constructors!" + ) - //we should be able to derive the same child xpub + // we should be able to derive the same child xpub assert(api.deriveXPub(hdAccount) == direct.deriveXPub(hdAccount)) } @@ -207,28 +241,33 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val kmParams = buildParams() val bip39Pw = KeyManagerTestUtil.bip39Password val direct = - BIP39KeyManager.fromMnemonic(mnemonic, - kmParams, - Some(bip39Pw), - TimeUtil.now, - false) + BIP39KeyManager.fromMnemonic( + mnemonic, + kmParams, + Some(bip39Pw), + TimeUtil.now, + false + ) val directXpub = direct.getRootXPub val api = BIP39KeyManager - .initializeWithMnemonic(aesPasswordOpt = - KeyManagerTestUtil.aesPasswordOpt, - mnemonic, - Some(bip39Pw), - kmParams) + .initializeWithMnemonic( + aesPasswordOpt = KeyManagerTestUtil.aesPasswordOpt, + mnemonic, + Some(bip39Pw), + kmParams + ) .getOrElse(fail()) val apiXpub = api.getRootXPub - assert(apiXpub == directXpub, - s"We don't have initialization symmetry between our constructors!") + assert( + apiXpub == directXpub, + s"We don't have initialization symmetry between our constructors!" + ) - //we should be able to derive the same child xpub + // we should be able to derive the same child xpub assert(api.deriveXPub(hdAccount) == direct.deriveXPub(hdAccount)) } @@ -237,34 +276,40 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { val bip39Pw = KeyManagerTestUtil.bip39PasswordNonEmpty val withPassword = - BIP39KeyManager.fromMnemonic(mnemonic, - kmParams, - Some(bip39Pw), - TimeUtil.now, - false) + BIP39KeyManager.fromMnemonic( + mnemonic, + kmParams, + Some(bip39Pw), + TimeUtil.now, + false + ) val withPasswordXpub = withPassword.getRootXPub val noPassword = - BIP39KeyManager.fromMnemonic(mnemonic, - kmParams, - None, - TimeUtil.now, - false) + BIP39KeyManager.fromMnemonic( + mnemonic, + kmParams, + None, + TimeUtil.now, + false + ) val noPwXpub = noPassword.getRootXPub assert( withPasswordXpub != noPwXpub, - s"A key manager with a BIP39 password should not generate the same xpub as a key manager without a password!") + s"A key manager with a BIP39 password should not generate the same xpub as a key manager without a password!" + ) } it must "return a mnemonic not found if we have not initialized the key manager" in { val kmParams = buildParams() - val kmE = BIP39KeyManager.fromParams(kmParams = kmParams, - passwordOpt = - Some(BIP39KeyManager.badPassphrase), - bip39PasswordOpt = None) + val kmE = BIP39KeyManager.fromParams( + kmParams = kmParams, + passwordOpt = Some(BIP39KeyManager.badPassphrase), + bip39PasswordOpt = None + ) assert(kmE == Left(ReadMnemonicError.NotFoundError)) } @@ -284,7 +329,8 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { aesPasswordOpt = KeyManagerTestUtil.aesPasswordOpt, entropy = badEntropy, bip39PasswordOpt = KeyManagerTestUtil.bip39PasswordOpt, - kmParams = buildParams()) + kmParams = buildParams() + ) assert(init == Left(InitializeKeyManagerError.BadEntropy)) } @@ -296,21 +342,27 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { keymanagement.KeyManagerParams(seedPath, HDPurposes.SegWit, RegTest) val entropy = MnemonicCode.getEntropy256Bits val passwordOpt = Some(KeyManagerTestUtil.bip39Password) - val keyManager = withInitializedKeyManager(aesPasswordOpt = aesPasswordOpt, - kmParams = kmParams, - entropy = entropy, - bip39PasswordOpt = passwordOpt) + val keyManager = withInitializedKeyManager( + aesPasswordOpt = aesPasswordOpt, + kmParams = kmParams, + entropy = entropy, + bip39PasswordOpt = passwordOpt + ) - assert(Files.exists(keyManager.kmParams.seedPath), - s"Seed path must exist after calling withInitializedKeyManager") + assert( + Files.exists(keyManager.kmParams.seedPath), + s"Seed path must exist after calling withInitializedKeyManager" + ) val firstXpub = keyManager.getRootXPub - //now let's try to initialize again, our xpub should be exactly the same + // now let's try to initialize again, our xpub should be exactly the same val keyManager2E = - BIP39KeyManager.initialize(aesPasswordOpt = aesPasswordOpt, - kmParams, - bip39PasswordOpt = passwordOpt) + BIP39KeyManager.initialize( + aesPasswordOpt = aesPasswordOpt, + kmParams, + bip39PasswordOpt = passwordOpt + ) keyManager2E match { case Left(_) => fail(s"Must have been able to intiialize the key manager for test") @@ -327,22 +379,28 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { keymanagement.KeyManagerParams(seedPath, HDPurposes.SegWit, RegTest) val entropy = MnemonicCode.getEntropy256Bits val passwordOpt = Some(KeyManagerTestUtil.bip39Password) - val keyManager = withInitializedKeyManager(aesPasswordOpt = aesPasswordOpt, - kmParams = kmParams, - entropy = entropy, - bip39PasswordOpt = passwordOpt) + val keyManager = withInitializedKeyManager( + aesPasswordOpt = aesPasswordOpt, + kmParams = kmParams, + entropy = entropy, + bip39PasswordOpt = passwordOpt + ) - assert(Files.exists(keyManager.kmParams.seedPath), - s"Seed path must exist after calling withInitializedKeyManager") + assert( + Files.exists(keyManager.kmParams.seedPath), + s"Seed path must exist after calling withInitializedKeyManager" + ) // change the data to not be json format Files.write(kmParams.seedPath, "now this is the wrong format".getBytes) - //now let's try to initialize again, it should fail with a JsonParsingError + // now let's try to initialize again, it should fail with a JsonParsingError val keyManager2E = - BIP39KeyManager.initialize(aesPasswordOpt, - kmParams, - bip39PasswordOpt = passwordOpt) + BIP39KeyManager.initialize( + aesPasswordOpt, + kmParams, + bip39PasswordOpt = passwordOpt + ) keyManager2E match { case Left(InitializeKeyManagerError.FailedToReadWrittenSeed(unlockErr)) => unlockErr match { @@ -350,18 +408,22 @@ class BIP39KeyManagerApiTest extends KeyManagerApiUnitTest { case result @ (KeyManagerUnlockError.BadPassword | KeyManagerUnlockError.MnemonicNotFound) => fail( - s"Expected to fail test with ${KeyManagerUnlockError.JsonParsingError} got $result") + s"Expected to fail test with ${KeyManagerUnlockError.JsonParsingError} got $result" + ) } case result @ (Left(_) | Right(_)) => fail( - s"Expected to fail test with ${KeyManagerUnlockError.JsonParsingError} got $result") + s"Expected to fail test with ${KeyManagerUnlockError.JsonParsingError} got $result" + ) } } private def buildParams(): KeyManagerParams = { - keymanagement.KeyManagerParams(seedPath = KeyManagerTestUtil.tmpSeedPath, - purpose = purpose, - network = MainNet) + keymanagement.KeyManagerParams( + seedPath = KeyManagerTestUtil.tmpSeedPath, + purpose = purpose, + network = MainNet + ) } } diff --git a/key-manager-test/src/test/scala/org/bitcoins/keymanager/bip39/BIP39LockedKeyManagerApiTest.scala b/key-manager-test/src/test/scala/org/bitcoins/keymanager/bip39/BIP39LockedKeyManagerApiTest.scala index 8d592a9c50..52c6d73c81 100644 --- a/key-manager-test/src/test/scala/org/bitcoins/keymanager/bip39/BIP39LockedKeyManagerApiTest.scala +++ b/key-manager-test/src/test/scala/org/bitcoins/keymanager/bip39/BIP39LockedKeyManagerApiTest.scala @@ -14,35 +14,44 @@ class BIP39LockedKeyManagerApiTest extends KeyManagerApiUnitTest { it must "be able to read a locked mnemonic from disk" in { val bip39PwOpt = KeyManagerTestUtil.bip39PasswordOpt val aesPasswordOpt = KeyManagerTestUtil.aesPasswordOpt - val km = withInitializedKeyManager(aesPasswordOpt = aesPasswordOpt, - bip39PasswordOpt = bip39PwOpt) + val km = withInitializedKeyManager( + aesPasswordOpt = aesPasswordOpt, + bip39PasswordOpt = bip39PwOpt + ) val unlockedE = - BIP39LockedKeyManager.unlock(aesPasswordOpt, - bip39PasswordOpt = bip39PwOpt, - km.kmParams) + BIP39LockedKeyManager.unlock( + aesPasswordOpt, + bip39PasswordOpt = bip39PwOpt, + km.kmParams + ) val unlockedKm = unlockedE match { case Right(km) => km case Left(err) => fail(s"Failed to unlock key manager ${err}") } - assert(km == unlockedKm, - s"Unlocked key manager must be the same was the pre-locked one") + assert( + km == unlockedKm, + s"Unlocked key manager must be the same was the pre-locked one" + ) } it must "fail to read bad json in the seed file" in { val km = withInitializedKeyManager() val badPassword = Some(AesPassword.fromString("other bad password")) - val unlockedE = BIP39LockedKeyManager.unlock(passphraseOpt = badPassword, - bip39PasswordOpt = None, - kmParams = km.kmParams) + val unlockedE = BIP39LockedKeyManager.unlock( + passphraseOpt = badPassword, + bip39PasswordOpt = None, + kmParams = km.kmParams + ) unlockedE match { case Left(KeyManagerUnlockError.BadPassword) => succeed case result @ (Left(_) | Right(_)) => fail( - s"Expected to fail test with ${KeyManagerUnlockError.BadPassword} got ${result}") + s"Expected to fail test with ${KeyManagerUnlockError.BadPassword} got ${result}" + ) } } @@ -58,7 +67,8 @@ class BIP39LockedKeyManagerApiTest extends KeyManagerApiUnitTest { case Left(KeyManagerUnlockError.MnemonicNotFound) => succeed case result @ (Left(_) | Right(_)) => fail( - s"Expected to fail test with ${KeyManagerUnlockError.MnemonicNotFound} got ${result}") + s"Expected to fail test with ${KeyManagerUnlockError.MnemonicNotFound} got ${result}" + ) } } @@ -73,7 +83,8 @@ class BIP39LockedKeyManagerApiTest extends KeyManagerApiUnitTest { case Left(KeyManagerUnlockError.JsonParsingError(_)) => succeed case result @ (Left(_) | Right(_)) => fail( - s"Expected to fail test with ${KeyManagerUnlockError.JsonParsingError} got $result") + s"Expected to fail test with ${KeyManagerUnlockError.JsonParsingError} got $result" + ) } } } diff --git a/key-manager-test/src/test/scala/org/bitcoins/keymanager/config/KeyManagerAppConfigTest.scala b/key-manager-test/src/test/scala/org/bitcoins/keymanager/config/KeyManagerAppConfigTest.scala index bb6a74a84a..a28b2a9624 100644 --- a/key-manager-test/src/test/scala/org/bitcoins/keymanager/config/KeyManagerAppConfigTest.scala +++ b/key-manager-test/src/test/scala/org/bitcoins/keymanager/config/KeyManagerAppConfigTest.scala @@ -107,7 +107,9 @@ class KeyManagerAppConfigTest extends BitcoinSAsyncTest { Files.exists( tempDir .resolve(WalletStorage.SEED_FOLDER_NAME) - .resolve(WalletStorage.ENCRYPTED_SEED_FILE_NAME))) + .resolve(WalletStorage.ENCRYPTED_SEED_FILE_NAME) + ) + ) } } @@ -131,11 +133,12 @@ class KeyManagerAppConfigTest extends BitcoinSAsyncTest { _ <- started1F _ <- started2F } yield { - //make sure they are internally consistent + // make sure they are internally consistent assert( - appConfig1.toBip39KeyManager.getRootXPub == appConfig2.toBip39KeyManager.getRootXPub) + appConfig1.toBip39KeyManager.getRootXPub == appConfig2.toBip39KeyManager.getRootXPub + ) - //manually build the xpub to make sure we are correct + // manually build the xpub to make sure we are correct val mnemonic = MnemonicCode.fromEntropy(entropy) val bip39Seed = BIP39Seed.fromMnemonic(mnemonic, None) val xpriv = bip39Seed.toExtPrivateKey(ExtKeyVersion.LegacyTestNet3Priv) @@ -219,11 +222,11 @@ class KeyManagerAppConfigTest extends BitcoinSAsyncTest { assert(KeyManagerAppConfig.validateWalletName("")) assert(KeyManagerAppConfig.validateWalletName("old_wallet")) - //weird whitespace + // weird whitespace assert(!KeyManagerAppConfig.validateWalletName(" ")) assert(!KeyManagerAppConfig.validateWalletName(" old_wallet")) - //no non alpha-numeric + // no non alpha-numeric assert(!KeyManagerAppConfig.validateWalletName("@@@")) assert(!KeyManagerAppConfig.validateWalletName("old-wallet.")) diff --git a/key-manager-test/src/test/scala/org/bitcoins/keymanager/util/HdUtilTest.scala b/key-manager-test/src/test/scala/org/bitcoins/keymanager/util/HdUtilTest.scala index 859c9a009d..d07734ef11 100644 --- a/key-manager-test/src/test/scala/org/bitcoins/keymanager/util/HdUtilTest.scala +++ b/key-manager-test/src/test/scala/org/bitcoins/keymanager/util/HdUtilTest.scala @@ -25,19 +25,29 @@ class HdUtilTest extends KeyManagerApiUnitTest { it must "get the correct version for a public key" in { assert( - HDUtil.getXpubVersion(HDPurposes.Legacy, MainNet) == LegacyMainNetPub) + HDUtil.getXpubVersion(HDPurposes.Legacy, MainNet) == LegacyMainNetPub + ) assert( - HDUtil.getXpubVersion(HDPurposes.Legacy, TestNet3) == LegacyTestNet3Pub) + HDUtil.getXpubVersion(HDPurposes.Legacy, TestNet3) == LegacyTestNet3Pub + ) assert( - HDUtil.getXpubVersion(HDPurposes.SegWit, MainNet) == SegWitMainNetPub) + HDUtil.getXpubVersion(HDPurposes.SegWit, MainNet) == SegWitMainNetPub + ) assert( - HDUtil.getXpubVersion(HDPurposes.SegWit, TestNet3) == SegWitTestNet3Pub) + HDUtil.getXpubVersion(HDPurposes.SegWit, TestNet3) == SegWitTestNet3Pub + ) assert( - HDUtil.getXpubVersion(HDPurposes.NestedSegWit, - MainNet) == NestedSegWitMainNetPub) + HDUtil.getXpubVersion( + HDPurposes.NestedSegWit, + MainNet + ) == NestedSegWitMainNetPub + ) assert( - HDUtil.getXpubVersion(HDPurposes.NestedSegWit, - TestNet3) == NestedSegWitTestNet3Pub) + HDUtil.getXpubVersion( + HDPurposes.NestedSegWit, + TestNet3 + ) == NestedSegWitTestNet3Pub + ) assertThrows[IllegalArgumentException] { HDUtil.getXpubVersion(HDPurpose(1), TestNet3) @@ -46,19 +56,29 @@ class HdUtilTest extends KeyManagerApiUnitTest { it must "get the correct version for a private key" in { assert( - HDUtil.getXprivVersion(HDPurposes.Legacy, MainNet) == LegacyMainNetPriv) + HDUtil.getXprivVersion(HDPurposes.Legacy, MainNet) == LegacyMainNetPriv + ) assert( - HDUtil.getXprivVersion(HDPurposes.Legacy, TestNet3) == LegacyTestNet3Priv) + HDUtil.getXprivVersion(HDPurposes.Legacy, TestNet3) == LegacyTestNet3Priv + ) assert( - HDUtil.getXprivVersion(HDPurposes.SegWit, MainNet) == SegWitMainNetPriv) + HDUtil.getXprivVersion(HDPurposes.SegWit, MainNet) == SegWitMainNetPriv + ) assert( - HDUtil.getXprivVersion(HDPurposes.SegWit, TestNet3) == SegWitTestNet3Priv) + HDUtil.getXprivVersion(HDPurposes.SegWit, TestNet3) == SegWitTestNet3Priv + ) assert( - HDUtil.getXprivVersion(HDPurposes.NestedSegWit, - MainNet) == NestedSegWitMainNetPriv) + HDUtil.getXprivVersion( + HDPurposes.NestedSegWit, + MainNet + ) == NestedSegWitMainNetPriv + ) assert( - HDUtil.getXprivVersion(HDPurposes.NestedSegWit, - TestNet3) == NestedSegWitTestNet3Priv) + HDUtil.getXprivVersion( + HDPurposes.NestedSegWit, + TestNet3 + ) == NestedSegWitTestNet3Priv + ) assertThrows[IllegalArgumentException] { HDUtil.getXprivVersion(HDPurpose(1), MainNet) @@ -71,36 +91,52 @@ class HdUtilTest extends KeyManagerApiUnitTest { it must "find the corresponding priv version for a pubkey" in { assert( - HDUtil.getMatchingExtKeyVersion(LegacyMainNetPub) == LegacyMainNetPriv) + HDUtil.getMatchingExtKeyVersion(LegacyMainNetPub) == LegacyMainNetPriv + ) assert( - HDUtil.getMatchingExtKeyVersion(LegacyTestNet3Pub) == LegacyTestNet3Priv) + HDUtil.getMatchingExtKeyVersion(LegacyTestNet3Pub) == LegacyTestNet3Priv + ) assert( - HDUtil.getMatchingExtKeyVersion(SegWitMainNetPub) == SegWitMainNetPriv) + HDUtil.getMatchingExtKeyVersion(SegWitMainNetPub) == SegWitMainNetPriv + ) assert( - HDUtil.getMatchingExtKeyVersion(SegWitTestNet3Pub) == SegWitTestNet3Priv) + HDUtil.getMatchingExtKeyVersion(SegWitTestNet3Pub) == SegWitTestNet3Priv + ) assert( HDUtil.getMatchingExtKeyVersion( - NestedSegWitMainNetPub) == NestedSegWitMainNetPriv) + NestedSegWitMainNetPub + ) == NestedSegWitMainNetPriv + ) assert( HDUtil.getMatchingExtKeyVersion( - NestedSegWitTestNet3Pub) == NestedSegWitTestNet3Priv) + NestedSegWitTestNet3Pub + ) == NestedSegWitTestNet3Priv + ) } it must "find the corresponding pub version for a privkey" in { assert( - HDUtil.getMatchingExtKeyVersion(LegacyMainNetPriv) == LegacyMainNetPub) + HDUtil.getMatchingExtKeyVersion(LegacyMainNetPriv) == LegacyMainNetPub + ) assert( - HDUtil.getMatchingExtKeyVersion(LegacyTestNet3Priv) == LegacyTestNet3Pub) + HDUtil.getMatchingExtKeyVersion(LegacyTestNet3Priv) == LegacyTestNet3Pub + ) assert( - HDUtil.getMatchingExtKeyVersion(SegWitMainNetPriv) == SegWitMainNetPub) + HDUtil.getMatchingExtKeyVersion(SegWitMainNetPriv) == SegWitMainNetPub + ) assert( - HDUtil.getMatchingExtKeyVersion(SegWitTestNet3Priv) == SegWitTestNet3Pub) + HDUtil.getMatchingExtKeyVersion(SegWitTestNet3Priv) == SegWitTestNet3Pub + ) assert( HDUtil.getMatchingExtKeyVersion( - NestedSegWitMainNetPriv) == NestedSegWitMainNetPub) + NestedSegWitMainNetPriv + ) == NestedSegWitMainNetPub + ) assert( HDUtil.getMatchingExtKeyVersion( - NestedSegWitTestNet3Priv) == NestedSegWitTestNet3Pub) + NestedSegWitTestNet3Priv + ) == NestedSegWitTestNet3Pub + ) } it must "get the right coin type" in { diff --git a/key-manager/src/main/scala/org/bitcoins/keymanager/EncryptedMnemonic.scala b/key-manager/src/main/scala/org/bitcoins/keymanager/EncryptedMnemonic.scala index 4e858d7789..4b3be67c2d 100644 --- a/key-manager/src/main/scala/org/bitcoins/keymanager/EncryptedMnemonic.scala +++ b/key-manager/src/main/scala/org/bitcoins/keymanager/EncryptedMnemonic.scala @@ -35,8 +35,8 @@ case class DecryptedMnemonic( private[keymanager] val mnemonicCode: MnemonicCode, creationTime: Instant, backupTimeOpt: Option[Instant], - imported: Boolean) - extends DecryptedSeedState { + imported: Boolean +) extends DecryptedSeedState { override protected val strToEncrypt: String = mnemonicCode.words.mkString(" ") override def withBackupTime(backupTime: Instant): SeedState = { @@ -48,8 +48,8 @@ case class DecryptedExtPrivKey( private[keymanager] val xprv: ExtPrivateKey, creationTime: Instant, backupTimeOpt: Option[Instant], - imported: Boolean) - extends DecryptedSeedState { + imported: Boolean +) extends DecryptedSeedState { override protected val strToEncrypt: String = xprv.toStringSensitive override def withBackupTime(backupTime: Instant): SeedState = { @@ -62,8 +62,8 @@ case class EncryptedSeed( salt: AesSalt, creationTime: Instant, backupTimeOpt: Option[Instant], - imported: Boolean) - extends SeedState { + imported: Boolean +) extends SeedState { private def decryptStr(password: AesPassword): Try[String] = { val key = password.toKey(salt) diff --git a/key-manager/src/main/scala/org/bitcoins/keymanager/WalletStorage.scala b/key-manager/src/main/scala/org/bitcoins/keymanager/WalletStorage.scala index 4d2fcfc346..42fa60defb 100644 --- a/key-manager/src/main/scala/org/bitcoins/keymanager/WalletStorage.scala +++ b/key-manager/src/main/scala/org/bitcoins/keymanager/WalletStorage.scala @@ -22,7 +22,8 @@ object WalletStorage extends KeyManagerLogger { /** Epoch time of the mainnet Genesis Block */ val GENESIS_TIME = 1231006505L - /** Start of bitcoin-s wallet project, Block 555,990 block time on 2018-12-28 */ + /** Start of bitcoin-s wallet project, Block 555,990 block time on 2018-12-28 + */ val FIRST_BITCOIN_S_WALLET_TIME = 1546042867L /** Checks if a wallet seed exists in datadir */ @@ -41,9 +42,8 @@ object WalletStorage extends KeyManagerLogger { val IMPORTED = "imported" } - /** Writes the mnemonic to disk. - * If we encounter a file in the place we're about - * to write to, an error will be thrown. + /** Writes the mnemonic to disk. If we encounter a file in the place we're + * about to write to, an error will be thrown. */ def writeSeedToDisk(seedPath: Path, seed: SeedState): Path = { seed match { @@ -56,9 +56,8 @@ object WalletStorage extends KeyManagerLogger { } } - /** Writes the encrypted mnemonic to disk. - * If we encounter a file in the place we're about - * to write to, an error will be thrown. + /** Writes the encrypted mnemonic to disk. If we encounter a file in the place + * we're about to write to, an error will be thrown. */ def writeSeedToDisk(seedPath: Path, seed: EncryptedSeed): Path = { val encrypted = seed.value @@ -79,9 +78,8 @@ object WalletStorage extends KeyManagerLogger { writeSeedJsonToDisk(seedPath, jsObject) } - /** Writes the unencrypted mnemonic to disk. - * If we encounter a file in the place we're about - * to write to, an error will be thrown. + /** Writes the unencrypted mnemonic to disk. If we encounter a file in the + * place we're about to write to, an error will be thrown. */ def writeSeedToDisk(seedPath: Path, mnemonic: DecryptedMnemonic): Path = { val mnemonicCode = mnemonic.mnemonicCode @@ -90,7 +88,8 @@ object WalletStorage extends KeyManagerLogger { ujson.Obj( MNEMONIC_SEED -> mnemonicCode.toVector, CREATION_TIME -> ujson.Num( - mnemonic.creationTime.getEpochSecond.toDouble), + mnemonic.creationTime.getEpochSecond.toDouble + ), BACKUP_TIME -> mnemonic.backupTimeOpt .map(ts => ujson.Num(ts.getEpochSecond.toDouble)) .getOrElse(ujson.Null), @@ -101,9 +100,8 @@ object WalletStorage extends KeyManagerLogger { writeSeedJsonToDisk(seedPath, jsObject) } - /** Writes the unencrypted xprv to disk. - * If we encounter a file in the place we're about - * to write to, an error will be thrown. + /** Writes the unencrypted xprv to disk. If we encounter a file in the place + * we're about to write to, an error will be thrown. */ def writeSeedToDisk(seedPath: Path, extKey: DecryptedExtPrivKey): Path = { val jsObject = { @@ -117,9 +115,8 @@ object WalletStorage extends KeyManagerLogger { writeSeedJsonToDisk(seedPath, jsObject) } - /** Writes a seed's json output to disk. - * If we encounter a file in the place we're about - * to write to, an error will be thrown. + /** Writes a seed's json output to disk. If we encounter a file in the place + * we're about to write to, an error will be thrown. */ private def writeSeedJsonToDisk(seedPath: Path, jsObject: Obj): Path = { logger.info(s"Writing seed to $seedPath") @@ -140,7 +137,8 @@ object WalletStorage extends KeyManagerLogger { if (hasMnemonic) { logger.info(s"$seedPath already exists") throw new RuntimeException( - s"Attempting to overwrite an existing seed, this is dangerous! path: $seedPath") + s"Attempting to overwrite an existing seed, this is dangerous! path: $seedPath" + ) } else { logger.trace(s"$seedPath does not exist") writeJsToDisk() @@ -181,7 +179,8 @@ object WalletStorage extends KeyManagerLogger { } private def readJsonFromDisk( - seedPath: Path): Either[ReadMnemonicError, Value] = { + seedPath: Path + ): Either[ReadMnemonicError, Value] = { if (Files.isRegularFile(seedPath)) { val rawJson = Files.readAllLines(seedPath).asScala.mkString("\n") logger.debug(s"Read raw mnemonic from $seedPath") @@ -206,13 +205,14 @@ object WalletStorage extends KeyManagerLogger { rawSalt: String, rawCreationTime: Long, rawBackupTime: Option[Long], - rawImported: Boolean) + rawImported: Boolean + ) - /** Reads the raw encrypted mnemonic from json, - * performing no decryption + /** Reads the raw encrypted mnemonic from json, performing no decryption */ private def readEncryptedMnemonicFromJson( - json: Value): Either[ReadMnemonicError, EncryptedSeed] = { + json: Value + ): Either[ReadMnemonicError, EncryptedSeed] = { import MnemonicJsonKeys._ import ReadMnemonicError._ @@ -225,12 +225,14 @@ object WalletStorage extends KeyManagerLogger { val cipherTextString = json(CIPHER_TEXT).str val rawSaltString = json(SALT).str val imported = parseImported(json) - RawEncryptedSeed(ivString, - cipherTextString, - rawSaltString, - creationTimeNum, - backupTimeOpt, - imported) + RawEncryptedSeed( + ivString, + cipherTextString, + rawSaltString, + creationTimeNum, + backupTimeOpt, + imported + ) } match { case Success(value) => Right(value) case Failure(exception) => @@ -239,23 +241,27 @@ object WalletStorage extends KeyManagerLogger { } readJsonTupleEither.flatMap { - case RawEncryptedSeed(rawIv, - rawCipherText, - rawSalt, - rawCreationTime, - rawBackupTime, - rawImported) => + case RawEncryptedSeed( + rawIv, + rawCipherText, + rawSalt, + rawCreationTime, + rawBackupTime, + rawImported + ) => val encryptedOpt = for { iv <- ByteVector.fromHex(rawIv).map(AesIV.fromValidBytes) cipherText <- ByteVector.fromHex(rawCipherText) salt <- ByteVector.fromHex(rawSalt).map(AesSalt(_)) } yield { logger.debug(s"Parsed contents into an EncryptedMnemonic") - EncryptedSeed(AesEncryptedData(cipherText, iv), - salt, - Instant.ofEpochSecond(rawCreationTime), - rawBackupTime.map(Instant.ofEpochSecond), - rawImported) + EncryptedSeed( + AesEncryptedData(cipherText, iv), + salt, + Instant.ofEpochSecond(rawCreationTime), + rawBackupTime.map(Instant.ofEpochSecond), + rawImported + ) } encryptedOpt match { @@ -268,14 +274,16 @@ object WalletStorage extends KeyManagerLogger { /** Reads the raw unencrypted mnemonic from json */ private def readUnencryptedMnemonicFromJson( - json: Value): Either[ReadMnemonicError, DecryptedMnemonic] = { + json: Value + ): Either[ReadMnemonicError, DecryptedMnemonic] = { import MnemonicJsonKeys._ import ReadMnemonicError._ val readJsonTupleEither: Either[ ReadMnemonicError, - (Vector[String], Long, Option[Long], Boolean)] = { + (Vector[String], Long, Option[Long], Boolean) + ] = { logger.trace(s"Read mnemonic JSON: Masked(json)") Try { val creationTimeNum = parseCreationTime(json) @@ -298,10 +306,12 @@ object WalletStorage extends KeyManagerLogger { case Success(mnemonicCode) => logger.debug(s"Parsed contents into a DecryptedMnemonic") val decrypted = - DecryptedMnemonic(mnemonicCode, - Instant.ofEpochSecond(rawCreationTime), - rawBackupTimeOpt.map(Instant.ofEpochSecond), - rawImported) + DecryptedMnemonic( + mnemonicCode, + Instant.ofEpochSecond(rawCreationTime), + rawBackupTimeOpt.map(Instant.ofEpochSecond), + rawImported + ) Right(decrypted) } } @@ -309,14 +319,14 @@ object WalletStorage extends KeyManagerLogger { /** Reads the raw unencrypted xprv from json */ private def readUnencryptedSeedFromJson( - json: Value): Either[ReadMnemonicError, DecryptedExtPrivKey] = { + json: Value + ): Either[ReadMnemonicError, DecryptedExtPrivKey] = { import MnemonicJsonKeys._ import ReadMnemonicError._ - val readJsonTupleEither: Either[ - ReadMnemonicError, - (String, Long, Option[Long], Boolean)] = { + val readJsonTupleEither + : Either[ReadMnemonicError, (String, Long, Option[Long], Boolean)] = { logger.trace(s"Read mnemonic JSON: Masked(json)") Try { val creationTimeNum = parseCreationTime(json) @@ -339,10 +349,12 @@ object WalletStorage extends KeyManagerLogger { case Success(xprv) => logger.debug(s"Parsed contents into a DecryptedMnemonic") val decrypted = - DecryptedExtPrivKey(xprv, - Instant.ofEpochSecond(rawCreationTime), - rawBackupTimeOpt.map(Instant.ofEpochSecond), - rawImported) + DecryptedExtPrivKey( + xprv, + Instant.ofEpochSecond(rawCreationTime), + rawBackupTimeOpt.map(Instant.ofEpochSecond), + rawImported + ) Right(decrypted) } } @@ -350,9 +362,8 @@ object WalletStorage extends KeyManagerLogger { private def decryptSeed( encrypted: EncryptedSeed, - passphrase: AesPassword): Either[ - ReadMnemonicError, - DecryptedSeedState] = { + passphrase: AesPassword + ): Either[ReadMnemonicError, DecryptedSeedState] = { // attempt to decrypt as mnemonic encrypted.toMnemonic(passphrase) match { case Failure(_) => @@ -364,31 +375,33 @@ object WalletStorage extends KeyManagerLogger { case Success(xprv) => logger.debug(s"Decrypted $encrypted successfully") val decryptedExtPrivKey = - DecryptedExtPrivKey(xprv, - encrypted.creationTime, - encrypted.backupTimeOpt, - encrypted.imported) + DecryptedExtPrivKey( + xprv, + encrypted.creationTime, + encrypted.backupTimeOpt, + encrypted.imported + ) Right(decryptedExtPrivKey) } case Success(mnemonic) => logger.debug(s"Decrypted $encrypted successfully") val decryptedMnemonic = - DecryptedMnemonic(mnemonic, - encrypted.creationTime, - encrypted.backupTimeOpt, - encrypted.imported) + DecryptedMnemonic( + mnemonic, + encrypted.creationTime, + encrypted.backupTimeOpt, + encrypted.imported + ) Right(decryptedMnemonic) } } - /** Reads the wallet mnemonic from disk and tries to parse and - * decrypt it + /** Reads the wallet mnemonic from disk and tries to parse and decrypt it */ def decryptSeedFromDisk( seedPath: Path, - passphraseOpt: Option[AesPassword]): Either[ - ReadMnemonicError, - DecryptedSeedState] = { + passphraseOpt: Option[AesPassword] + ): Either[ReadMnemonicError, DecryptedSeedState] = { import MnemonicJsonKeys._ import ReadMnemonicError._ @@ -431,7 +444,8 @@ object WalletStorage extends KeyManagerLogger { def readDecryptedSeedPhraseForBackup( seedPath: Path, - passphraseOpt: Option[AesPassword]): Try[Vector[String]] = Try { + passphraseOpt: Option[AesPassword] + ): Try[Vector[String]] = Try { decryptSeedFromDisk(seedPath, passphraseOpt) match { case Right(seedState) => seedState match { @@ -441,7 +455,8 @@ object WalletStorage extends KeyManagerLogger { throw new AlreadyBackedUpException(s"The seed is already backed up") case unknown: DecryptedSeedState => throw new SecurityException( - s"Unknown seed type: ${unknown.getClass.getName}") + s"Unknown seed type: ${unknown.getClass.getName}" + ) } case Left(err) => throw new SecurityException(err.toString) } @@ -449,7 +464,8 @@ object WalletStorage extends KeyManagerLogger { def markSeedAsBackedUp( seedPath: Path, - passphraseOpt: Option[AesPassword]): Try[Unit] = { + passphraseOpt: Option[AesPassword] + ): Try[Unit] = { decryptSeedFromDisk(seedPath, passphraseOpt) match { case Right(seedState) => Try { @@ -466,7 +482,8 @@ object WalletStorage extends KeyManagerLogger { val _ = writeSeedState(seedPath, toWrite) case Some(_) => logger.warn( - s"Seed has already been backed up, ignoring new request to mark it as backed up") + s"Seed has already been backed up, ignoring new request to mark it as backed up" + ) } } } @@ -477,7 +494,8 @@ object WalletStorage extends KeyManagerLogger { def getSeedBackupTime( seedPath: Path, - passphraseOpt: Option[AesPassword]): Try[Option[Instant]] = { + passphraseOpt: Option[AesPassword] + ): Try[Option[Instant]] = { decryptSeedFromDisk(seedPath, passphraseOpt) match { case Right(seedState) => Success(seedState.backupTimeOpt) @@ -489,7 +507,8 @@ object WalletStorage extends KeyManagerLogger { def changeAesPassword( seedPath: Path, oldPasswordOpt: Option[AesPassword], - newPasswordOpt: Option[AesPassword]): SeedState = { + newPasswordOpt: Option[AesPassword] + ): SeedState = { logger.info("Changing encryption password for seed") decryptSeedFromDisk(seedPath, oldPasswordOpt) match { case Left(err) => sys.error(err.toString) @@ -514,7 +533,8 @@ object WalletStorage extends KeyManagerLogger { Try(writeSeedToDisk(seedPath, toWrite)) match { case Failure(exception) => logger.error( - s"Failed to write new seed, backup of previous seed file can be found at $backup") + s"Failed to write new seed, backup of previous seed file can be found at $backup" + ) throw exception case Success(_) => logger.info("Successfully wrote to disk, deleting backup file") @@ -527,7 +547,8 @@ object WalletStorage extends KeyManagerLogger { seedPath: Path, privKeyVersion: ExtKeyPrivVersion, passphraseOpt: Option[AesPassword], - bip39PasswordOpt: Option[String]): ExtPrivateKeyHardened = { + bip39PasswordOpt: Option[String] + ): ExtPrivateKeyHardened = { val decryptedSeed = decryptSeedFromDisk(seedPath, passphraseOpt) match { case Left(error) => sys.error(error.toString) case Right(mnemonic) => mnemonic @@ -547,15 +568,14 @@ sealed trait ReadMnemonicError { self: Error => } object ReadMnemonicError { - /** Something went wrong while decrypting the mnemonic. - * Most likely the passphrase was bad + /** Something went wrong while decrypting the mnemonic. Most likely the + * passphrase was bad */ case object DecryptionError extends Error(s"Could not decrypt mnemonic!") with ReadMnemonicError - /** Something went wrong while parsing the encrypted - * mnemonic into valid JSON + /** Something went wrong while parsing the encrypted mnemonic into valid JSON */ case class JsonParsingError(message: String) extends Error(s"Error when parsing JSON: $message") diff --git a/key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39KeyManager.scala b/key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39KeyManager.scala index 051b07f8f8..fed74016b2 100644 --- a/key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39KeyManager.scala +++ b/key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39KeyManager.scala @@ -23,33 +23,36 @@ import java.nio.file.Files import java.time.Instant import scala.util.{Failure, Success, Try} -/** This is a key manager implementation meant to represent an in memory - * BIP39 key manager +/** This is a key manager implementation meant to represent an in memory BIP39 + * key manager * - * @param rootExtPrivKey the root seed used for this wallet - * @param kmParams the parameters used to generate the right keychain - * @see https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki + * @param rootExtPrivKey + * the root seed used for this wallet + * @param kmParams + * the parameters used to generate the right keychain + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki */ class BIP39KeyManager( private[this] val rootExtPrivKey: ExtPrivateKey, val kmParams: KeyManagerParams, val creationTime: Instant, - val imported: Boolean) - extends BIP39KeyManagerApi + val imported: Boolean +) extends BIP39KeyManagerApi with KeyManagerLogger { override def equals(other: Any): Boolean = other match { case bip39Km: BIP39KeyManager => getRootXPub == bip39Km.getRootXPub && - kmParams == bip39Km.kmParams && - creationTime.getEpochSecond == bip39Km.creationTime.getEpochSecond + kmParams == bip39Km.kmParams && + creationTime.getEpochSecond == bip39Km.creationTime.getEpochSecond case _ => other.equals(this) } - /** Converts a non-sensitive DB representation of a UTXO into - * a signable (and sensitive) real-world UTXO + /** Converts a non-sensitive DB representation of a UTXO into a signable (and + * sensitive) real-world UTXO */ def toSign(privKeyPath: HDPath): AdaptorSign = { val xpriv = @@ -92,9 +95,8 @@ object BIP39KeyManager aesPasswordOpt: Option[AesPassword], entropy: BitVector, bip39PasswordOpt: Option[String], - kmParams: KeyManagerParams): Either[ - KeyManagerInitializeError, - BIP39KeyManager] = { + kmParams: KeyManagerParams + ): Either[KeyManagerInitializeError, BIP39KeyManager] = { val seedPath = kmParams.seedPath logger.info(s"Initializing wallet with seedPath=$seedPath") @@ -103,7 +105,8 @@ object BIP39KeyManager val writtenToDiskE: Either[KeyManagerInitializeError, KeyManagerApi] = { if (Files.notExists(seedPath)) { logger.info( - s"Seed path parent directory does not exist, creating ${seedPath.getParent}") + s"Seed path parent directory does not exist, creating ${seedPath.getParent}" + ) Files.createDirectories(seedPath.getParent) val mnemonicT = Try(MnemonicCode.fromEntropy(entropy)) @@ -120,10 +123,12 @@ object BIP39KeyManager val writableMnemonicE: Either[KeyManagerInitializeError, SeedState] = mnemonicE.map { mnemonic => val decryptedMnemonic = - DecryptedMnemonic(mnemonic, - time, - backupTimeOpt = None, - imported = false) + DecryptedMnemonic( + mnemonic, + time, + backupTimeOpt = None, + imported = false + ) aesPasswordOpt match { case Some(aesPassword) => decryptedMnemonic.encrypt(aesPassword) case None => @@ -139,44 +144,57 @@ object BIP39KeyManager WalletStorage.writeSeedToDisk(seedPath, writable) logger.info(s"Saved wallet mnemonic to $mnemonicPath") - fromMnemonic(mnemonic = mnemonic, - kmParams = kmParams, - bip39PasswordOpt = bip39PasswordOpt, - creationTime = time, - imported = writable.imported) + fromMnemonic( + mnemonic = mnemonic, + kmParams = kmParams, + bip39PasswordOpt = bip39PasswordOpt, + creationTime = time, + imported = writable.imported + ) } } else { logger.info( - s"Seed file already exists, attempting to initialize form existing seed file=$seedPath.") + s"Seed file already exists, attempting to initialize form existing seed file=$seedPath." + ) - WalletStorage.decryptSeedFromDisk(kmParams.seedPath, - aesPasswordOpt) match { + WalletStorage.decryptSeedFromDisk( + kmParams.seedPath, + aesPasswordOpt + ) match { case Right(mnemonic: DecryptedMnemonic) => Right( - fromMnemonic(mnemonic = mnemonic.mnemonicCode, - kmParams = kmParams, - bip39PasswordOpt = bip39PasswordOpt, - creationTime = mnemonic.creationTime, - imported = mnemonic.imported)) + fromMnemonic( + mnemonic = mnemonic.mnemonicCode, + kmParams = kmParams, + bip39PasswordOpt = bip39PasswordOpt, + creationTime = mnemonic.creationTime, + imported = mnemonic.imported + ) + ) case Right(xprv: DecryptedExtPrivKey) => - val km = new BIP39KeyManager(xprv.xprv, - kmParams, - xprv.creationTime, - xprv.imported) + val km = new BIP39KeyManager( + xprv.xprv, + kmParams, + xprv.creationTime, + xprv.imported + ) Right(km) case Left(err) => Left( InitializeKeyManagerError.FailedToReadWrittenSeed( - JsonParsingError(err.toString))) + JsonParsingError(err.toString) + ) + ) } } } - //verify we can unlock it for a sanity check - val unlocked = BIP39LockedKeyManager.unlock(passphraseOpt = aesPasswordOpt, - bip39PasswordOpt = - bip39PasswordOpt, - kmParams = kmParams) + // verify we can unlock it for a sanity check + val unlocked = BIP39LockedKeyManager.unlock( + passphraseOpt = aesPasswordOpt, + bip39PasswordOpt = bip39PasswordOpt, + kmParams = kmParams + ) val biasedFinalE: Either[KeyManagerInitializeError, BIP39KeyManager] = for { @@ -210,25 +228,29 @@ object BIP39KeyManager def fromParams( kmParams: KeyManagerParams, passwordOpt: Option[AesPassword], - bip39PasswordOpt: Option[String]): Either[ - ReadMnemonicError, - BIP39KeyManager] = { + bip39PasswordOpt: Option[String] + ): Either[ReadMnemonicError, BIP39KeyManager] = { val mnemonicCodeE = WalletStorage.decryptSeedFromDisk(kmParams.seedPath, passwordOpt) mnemonicCodeE match { case Right(mnemonic: DecryptedMnemonic) => Right( - fromMnemonic(mnemonic.mnemonicCode, - kmParams, - bip39PasswordOpt, - mnemonic.creationTime, - mnemonic.imported)) + fromMnemonic( + mnemonic.mnemonicCode, + kmParams, + bip39PasswordOpt, + mnemonic.creationTime, + mnemonic.imported + ) + ) case Right(xprv: DecryptedExtPrivKey) => - val km = new BIP39KeyManager(xprv.xprv, - kmParams, - xprv.creationTime, - xprv.imported) + val km = new BIP39KeyManager( + xprv.xprv, + kmParams, + xprv.creationTime, + xprv.imported + ) Right(km) case Left(v) => Left(v) } diff --git a/key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39LockedKeyManager.scala b/key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39LockedKeyManager.scala index ed0afcfdfe..be602e8e0e 100644 --- a/key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39LockedKeyManager.scala +++ b/key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39LockedKeyManager.scala @@ -16,32 +16,38 @@ import org.bitcoins.keymanager._ object BIP39LockedKeyManager extends BitcoinSLogger { /** Unlock the wallet by decrypting the [[EncryptedMnemonic]] seed - * @param passphrase the password to decrypt the wallet - * @param kmParams parameters needed to create the key manager + * @param passphrase + * the password to decrypt the wallet + * @param kmParams + * parameters needed to create the key manager */ def unlock( passphraseOpt: Option[AesPassword], bip39PasswordOpt: Option[String], - kmParams: KeyManagerParams): Either[ - KeyManagerUnlockError, - BIP39KeyManager] = { + kmParams: KeyManagerParams + ): Either[KeyManagerUnlockError, BIP39KeyManager] = { logger.debug(s"Trying to unlock wallet with seedPath=${kmParams.seedPath}") val resultE = WalletStorage.decryptSeedFromDisk(kmParams.seedPath, passphraseOpt) resultE match { case Right(mnemonic: DecryptedMnemonic) => Right( - BIP39KeyManager.fromMnemonic(mnemonic.mnemonicCode, - kmParams, - bip39PasswordOpt, - mnemonic.creationTime, - mnemonic.imported)) + BIP39KeyManager.fromMnemonic( + mnemonic.mnemonicCode, + kmParams, + bip39PasswordOpt, + mnemonic.creationTime, + mnemonic.imported + ) + ) case Right(xprv: DecryptedExtPrivKey) => - val km = new BIP39KeyManager(xprv.xprv, - kmParams, - xprv.creationTime, - xprv.imported) + val km = new BIP39KeyManager( + xprv.xprv, + kmParams, + xprv.creationTime, + xprv.imported + ) Right(km) case Left(result) => @@ -54,7 +60,8 @@ object BIP39LockedKeyManager extends BitcoinSLogger { Left(KeyManagerUnlockError.JsonParsingError(message)) case ReadMnemonicError.NotFoundError => logger.error( - s"Encrypted mnemonic not found when unlocking the wallet!") + s"Encrypted mnemonic not found when unlocking the wallet!" + ) Left(KeyManagerUnlockError.MnemonicNotFound) } } diff --git a/key-manager/src/main/scala/org/bitcoins/keymanager/config/KeyManagerAppConfig.scala b/key-manager/src/main/scala/org/bitcoins/keymanager/config/KeyManagerAppConfig.scala index 6c72761787..c4a017a9a9 100644 --- a/key-manager/src/main/scala/org/bitcoins/keymanager/config/KeyManagerAppConfig.scala +++ b/key-manager/src/main/scala/org/bitcoins/keymanager/config/KeyManagerAppConfig.scala @@ -23,8 +23,8 @@ case class KeyManagerAppConfig( configOverrides: Vector[Config], walletNameOverride: Option[ArgumentSource[String]] = None, aesPasswordOverride: Option[ArgumentSource[AesPassword]] = None, - bip39PasswordOverride: Option[String] = None)(implicit - val ec: ExecutionContext) + bip39PasswordOverride: Option[String] = None +)(implicit val ec: ExecutionContext) extends AppConfig { override type ConfigType = KeyManagerAppConfig @@ -44,8 +44,10 @@ case class KeyManagerAppConfig( case Some(ArgumentSource.RpcArgument(walletName)) => Some(walletName) case Some(ArgumentSource.NoArgument) | None => configWalletName } - require(nameOpt.map(KeyManagerAppConfig.validateWalletName).getOrElse(true), - s"Invalid wallet name, only alphanumeric with _, got=$nameOpt") + require( + nameOpt.map(KeyManagerAppConfig.validateWalletName).getOrElse(true), + s"Invalid wallet name, only alphanumeric with _, got=$nameOpt" + ) nameOpt.getOrElse(KeyManagerAppConfig.DEFAULT_WALLET_NAME) } @@ -76,9 +78,9 @@ case class KeyManagerAppConfig( throw new RuntimeException(s"$other is not a valid account type!") } - /** Entropy provided by the a user in their bitcoin-s.conf - * configuration file. This should be used to seed the keymanager - * rather than randomly generating entropy. + /** Entropy provided by the a user in their bitcoin-s.conf configuration file. + * This should be used to seed the keymanager rather than randomly generating + * entropy. */ private lazy val externalEntropy: Option[String] = { val opt = config.getStringOrNone("bitcoin-s.keymanager.entropy") @@ -105,39 +107,46 @@ case class KeyManagerAppConfig( Files.createDirectories(newDefaultFile.getParent) Files.copy(oldDefaultFile, newDefaultFile) logger.info( - s"Migrated keymanager seed from=${oldDefaultFile.toAbsolutePath} to=${newDefaultFile.toAbsolutePath}") + s"Migrated keymanager seed from=${oldDefaultFile.toAbsolutePath} to=${newDefaultFile.toAbsolutePath}" + ) Future.unit } else if (!Files.exists(newDefaultFile)) { logger.info(s"No seed file found at=${newDefaultFile.toAbsolutePath}") initializeKeyManager() } else if (externalEntropy.isDefined && seedExists()) { - //means we have a seed saved on disk and external entropy - //provided. We should make sure the entropy provided generates - //the seed on disk to prevent internal inconsistencies + // means we have a seed saved on disk and external entropy + // provided. We should make sure the entropy provided generates + // the seed on disk to prevent internal inconsistencies val bitVec = BitVector.fromValidHex(externalEntropy.get) - //make sure external entropy provided to us is consistent + // make sure external entropy provided to us is consistent if (!CryptoUtil.checkEntropy(bitVec)) { sys.error( - s"The entropy used by bitcoin-s does not pass basic entropy sanity checks, got=${externalEntropy}") + s"The entropy used by bitcoin-s does not pass basic entropy sanity checks, got=${externalEntropy}" + ) } val mnemonicEntropy = MnemonicCode.fromEntropy(entropy = bitVec) val kmEntropy = BIP39KeyManager - .fromMnemonic(mnemonic = mnemonicEntropy, - kmParams = kmParams, - bip39PasswordOpt = bip39PasswordOpt, - creationTime = Instant.now, - imported = false) + .fromMnemonic( + mnemonic = mnemonicEntropy, + kmParams = kmParams, + bip39PasswordOpt = bip39PasswordOpt, + creationTime = Instant.now, + imported = false + ) val kmRootXpub = toBip39KeyManager.getRootXPub require( kmEntropy.getRootXPub == kmRootXpub, - s"Xpubs were different, generated from entropy=${kmEntropy.getRootXPub} keymanager xpub on disk=$kmRootXpub") + s"Xpubs were different, generated from entropy=${kmEntropy.getRootXPub} keymanager xpub on disk=$kmRootXpub" + ) logger.info( - s"Starting key manager with seedPath=${seedPath.toAbsolutePath}, rootXpub=${kmRootXpub}") + s"Starting key manager with seedPath=${seedPath.toAbsolutePath}, rootXpub=${kmRootXpub}" + ) Future.unit } else { val kmRootXpub = toBip39KeyManager.getRootXPub logger.info( - s"Starting keymanager with seedPath=${seedPath.toAbsolutePath}, rootXpub=${kmRootXpub}") + s"Starting keymanager with seedPath=${seedPath.toAbsolutePath}, rootXpub=${kmRootXpub}" + ) Future.unit } } @@ -168,18 +177,21 @@ case class KeyManagerAppConfig( WalletStorage.seedExists(seedPath) } - /** Creates a [[BIP39KeyManager]] from the seed referenced by this [[KeyManagerAppConfig]] - * with the given wallet purpose + /** Creates a [[BIP39KeyManager]] from the seed referenced by this + * [[KeyManagerAppConfig]] with the given wallet purpose */ def toBip39KeyManager: BIP39KeyManager = { val kmE: Either[ReadMnemonicError, BIP39KeyManager] = - BIP39KeyManager.fromParams(kmParams = kmParams, - passwordOpt = aesPasswordOpt, - bip39PasswordOpt = bip39PasswordOpt) + BIP39KeyManager.fromParams( + kmParams = kmParams, + passwordOpt = aesPasswordOpt, + bip39PasswordOpt = bip39PasswordOpt + ) kmE match { case Left(err) => sys.error( - s"Could not create a BIP39KeyManager from the KeyManagerAppConfig, err=$err") + s"Could not create a BIP39KeyManager from the KeyManagerAppConfig, err=$err" + ) case Right(km) => km } @@ -192,44 +204,52 @@ case class KeyManagerAppConfig( val entropy: BitVector = externalEntropy match { case Some(entropy) => logger.info( - s"Initializing new mnemonic seed at path=${seedPath.toAbsolutePath} with external entropy") + s"Initializing new mnemonic seed at path=${seedPath.toAbsolutePath} with external entropy" + ) val hexOpt = BitVector.fromHex(entropy) hexOpt match { case Some(hex) => hex case None => sys.error( - s"Entropy provided by bitcoin-s.keymanager.entropy was not valid hex, got=${entropy}") + s"Entropy provided by bitcoin-s.keymanager.entropy was not valid hex, got=${entropy}" + ) } case None => logger.info( - s"Initializing new mnemonic seed at path=${seedPath.toAbsolutePath}") + s"Initializing new mnemonic seed at path=${seedPath.toAbsolutePath}" + ) MnemonicCode.getEntropy256Bits } if (!CryptoUtil.checkEntropy(entropy)) { sys.error( - s"The entropy used by bitcoin-s does not pass basic entropy sanity checks, got=$entropy") + s"The entropy used by bitcoin-s does not pass basic entropy sanity checks, got=$entropy" + ) } val initE = BIP39KeyManager.initializeWithEntropy( aesPasswordOpt = aesPasswordOpt, entropy = entropy, bip39PasswordOpt = bip39PasswordOpt, - kmParams = kmParams) + kmParams = kmParams + ) initE match { case Right(km) => logger.info( - s"Successfully initialize seed at path with root xpub=${km.getRootXPub}") + s"Successfully initialize seed at path with root xpub=${km.getRootXPub}" + ) Future.unit case Left(err) => Future.failed( new RuntimeException( - s"Failed to initialize mnemonic seed in keymanager with err=$err")) + s"Failed to initialize mnemonic seed in keymanager with err=$err" + ) + ) } } - /** The creation time of the mnemonic seed - * If we cannot decrypt the seed because of invalid passwords, we return None + /** The creation time of the mnemonic seed If we cannot decrypt the seed + * because of invalid passwords, we return None */ def creationTime: Instant = { toBip39KeyManager.creationTime @@ -244,7 +264,8 @@ object KeyManagerAppConfig extends AppConfigFactory[KeyManagerAppConfig] { override val moduleName: String = "keymanager" override def fromDatadir(datadir: Path, confs: Vector[Config])(implicit - ec: ExecutionContext): KeyManagerAppConfig = + ec: ExecutionContext + ): KeyManagerAppConfig = KeyManagerAppConfig(datadir, confs) def validateWalletName(walletName: String): Boolean = diff --git a/lnd-rpc-test/src/test/scala/org/bitcoins/lnd/rpc/LndRpcClientPairTest.scala b/lnd-rpc-test/src/test/scala/org/bitcoins/lnd/rpc/LndRpcClientPairTest.scala index 300290c784..a0a48bb300 100644 --- a/lnd-rpc-test/src/test/scala/org/bitcoins/lnd/rpc/LndRpcClientPairTest.scala +++ b/lnd-rpc-test/src/test/scala/org/bitcoins/lnd/rpc/LndRpcClientPairTest.scala @@ -53,11 +53,19 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { .channelAcceptor(source) .mapAsyncUnordered(1) { req => if (req.pushAmt == UInt64.zero) { - queue.offer(ChannelAcceptResponse(error = "give me money", - pendingChanId = req.pendingChanId)) + queue.offer( + ChannelAcceptResponse( + error = "give me money", + pendingChanId = req.pendingChanId + ) + ) } else { - queue.offer(ChannelAcceptResponse(accept = true, - pendingChanId = req.pendingChanId)) + queue.offer( + ChannelAcceptResponse( + accept = true, + pendingChanId = req.pendingChanId + ) + ) } } .runWith(Sink.ignore) @@ -66,17 +74,22 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { nodeId <- lndA.nodeId // reject channel with no push amount _ <- recoverToSucceededIf[Exception]( - lndB.openChannel(nodeId = nodeId, - fundingAmount = Satoshis(50000), - satPerVByte = SatoshisPerVirtualByte.one, - privateChannel = false)) + lndB.openChannel( + nodeId = nodeId, + fundingAmount = Satoshis(50000), + satPerVByte = SatoshisPerVirtualByte.one, + privateChannel = false + ) + ) // accept channel with push amount - outpointOpt <- lndB.openChannel(nodeId = nodeId, - fundingAmount = Satoshis(50000), - pushAmt = Satoshis(10), - satPerVByte = SatoshisPerVirtualByte.one, - privateChannel = false) + outpointOpt <- lndB.openChannel( + nodeId = nodeId, + fundingAmount = Satoshis(50000), + pushAmt = Satoshis(10), + satPerVByte = SatoshisPerVirtualByte.one, + privateChannel = false + ) pendingA <- lndA.listPendingChannels() pendingB <- lndB.listPendingChannels() @@ -87,10 +100,14 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { assert( pendingA.pendingOpenChannels.exists( - _.channel.get.channelPoint == expectedOutpoint)) + _.channel.get.channelPoint == expectedOutpoint + ) + ) assert( pendingB.pendingOpenChannels.exists( - _.channel.get.channelPoint == expectedOutpoint)) + _.channel.get.channelPoint == expectedOutpoint + ) + ) } } @@ -102,7 +119,8 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { channel = channels.head (txIdStr, voutStr) = channel.channelPoint.splitAt( - channel.channelPoint.indexOf(":")) + channel.channelPoint.indexOf(":") + ) txId = DoubleSha256DigestBE(txIdStr) vout = UInt32(voutStr.tail.toLong) channelPoint = TransactionOutPoint(txId, vout) @@ -127,15 +145,19 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { utxo <- lnd.listUnspent.map(_.head) prevOut = TransactionOutput(utxo.amount, utxo.spk) - input = TransactionInput(utxo.outPointOpt.get, - EmptyScriptSignature, - TransactionConstants.sequence) + input = TransactionInput( + utxo.outPointOpt.get, + EmptyScriptSignature, + TransactionConstants.sequence + ) output = TransactionOutput(Bitcoins(0.5), bitcoindAddr.scriptPubKey) - unsigned = BaseTransaction(Int32.two, - Vector(input), - Vector(output), - UInt32.zero) + unsigned = BaseTransaction( + Int32.two, + Vector(input), + Vector(output), + UInt32.zero + ) (scriptSig, wit) <- lnd.computeInputScript(unsigned, 0, prevOut) } yield { @@ -160,19 +182,26 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { bitcoindAddr <- bitcoind.getNewAddress utxo <- lnd.listUnspent.map( - _.find(_.spk.isInstanceOf[TaprootScriptPubKey]).get) + _.find(_.spk.isInstanceOf[TaprootScriptPubKey]).get + ) prevOut = TransactionOutput(utxo.amount, utxo.spk) - input = TransactionInput(utxo.outPointOpt.get, - EmptyScriptSignature, - TransactionConstants.sequence) - output = TransactionOutput(utxo.amount - Satoshis(1_000), - bitcoindAddr.scriptPubKey) + input = TransactionInput( + utxo.outPointOpt.get, + EmptyScriptSignature, + TransactionConstants.sequence + ) + output = TransactionOutput( + utxo.amount - Satoshis(1_000), + bitcoindAddr.scriptPubKey + ) - unsigned = BaseTransaction(Int32.two, - Vector(input), - Vector(output), - UInt32.zero) + unsigned = BaseTransaction( + Int32.two, + Vector(input), + Vector(output), + UInt32.zero + ) (script, wit) <- lnd.computeInputScript( tx = unsigned, @@ -206,26 +235,36 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { bitcoindAddr <- bitcoind.getNewAddress utxo <- lnd.listUnspent.map( - _.find(_.spk.isInstanceOf[TaprootScriptPubKey]).get) + _.find(_.spk.isInstanceOf[TaprootScriptPubKey]).get + ) prevOut = TransactionOutput(utxo.amount, utxo.spk) - input = TransactionInput(utxo.outPointOpt.get, - EmptyScriptSignature, - TransactionConstants.sequence) + input = TransactionInput( + utxo.outPointOpt.get, + EmptyScriptSignature, + TransactionConstants.sequence + ) utxo2 <- lnd2.listUnspent.map( - _.find(_.spk.isInstanceOf[TaprootScriptPubKey]).get) + _.find(_.spk.isInstanceOf[TaprootScriptPubKey]).get + ) prevOut2 = TransactionOutput(utxo2.amount, utxo2.spk) - input2 = TransactionInput(utxo2.outPointOpt.get, - EmptyScriptSignature, - TransactionConstants.sequence) + input2 = TransactionInput( + utxo2.outPointOpt.get, + EmptyScriptSignature, + TransactionConstants.sequence + ) - output = TransactionOutput(utxo.amount + utxo2.amount - Satoshis(1_000), - bitcoindAddr.scriptPubKey) + output = TransactionOutput( + utxo.amount + utxo2.amount - Satoshis(1_000), + bitcoindAddr.scriptPubKey + ) - unsigned = BaseTransaction(Int32.two, - Vector(input, input2), - Vector(output), - UInt32.zero) + unsigned = BaseTransaction( + Int32.two, + Vector(input, input2), + Vector(output), + UInt32.zero + ) (scriptSig, wit) <- lnd.computeInputScript( tx = unsigned, @@ -305,10 +344,12 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { tx <- lndA.sendOutputs(Vector(output), feeRate, spendUnconfirmed = false) _ <- lndA.publishTransaction(tx) height <- bitcoind.getBlockCount() - confirmedF = lndB.subscribeTxConfirmation(txId = tx.txId, - script = addr.scriptPubKey, - requiredConfs = 6, - heightHint = height) + confirmedF = lndB.subscribeTxConfirmation( + txId = tx.txId, + script = addr.scriptPubKey, + requiredConfs = 6, + heightHint = height + ) _ <- bitcoind.generate(6) // await so if this fails the test doesn't hang forever @@ -342,15 +383,19 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { val spk = P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey) val output = TransactionOutput(Satoshis(10000), spk) - val unsignedTx = BaseTransaction(version = Int32.one, - inputs = Vector.empty, - outputs = Vector(output), - lockTime = UInt32.zero) + val unsignedTx = BaseTransaction( + version = Int32.one, + inputs = Vector.empty, + outputs = Vector(output), + lockTime = UInt32.zero + ) for { - unsignedPsbt <- lnd.fundPSBT(PSBT.fromUnsignedTx(unsignedTx), - SatoshisPerVirtualByte.one, - spendUnconfirmed = true) + unsignedPsbt <- lnd.fundPSBT( + PSBT.fromUnsignedTx(unsignedTx), + SatoshisPerVirtualByte.one, + spendUnconfirmed = true + ) signed <- lnd.finalizePSBT(unsignedPsbt) transaction <- Future.fromTry(signed.extractTransactionAndValidate) errorOpt <- lnd.publishTransaction(transaction) @@ -365,21 +410,26 @@ class LndRpcClientPairTest extends DualLndFixture with LndUtils { val messageBytes = ByteVector(message.getBytes) val asm = OP_RETURN +: BitcoinScriptUtil.calculatePushOp( - messageBytes) :+ ScriptConstant.fromBytes(messageBytes) + messageBytes + ) :+ ScriptConstant.fromBytes(messageBytes) ScriptPubKey(asm.toVector) } val output = TransactionOutput(Satoshis.zero, spk) - val unsignedTx = BaseTransaction(version = Int32.one, - inputs = Vector.empty, - outputs = Vector(output), - lockTime = UInt32.zero) + val unsignedTx = BaseTransaction( + version = Int32.one, + inputs = Vector.empty, + outputs = Vector(output), + lockTime = UInt32.zero + ) for { - unsignedPsbt <- lnd.fundPSBT(PSBT.fromUnsignedTx(unsignedTx), - SatoshisPerVirtualByte.one, - spendUnconfirmed = true) + unsignedPsbt <- lnd.fundPSBT( + PSBT.fromUnsignedTx(unsignedTx), + SatoshisPerVirtualByte.one, + spendUnconfirmed = true + ) signed <- lnd.finalizePSBT(unsignedPsbt) transaction <- Future.fromTry(signed.extractTransactionAndValidate) errorOpt <- lnd.publishTransaction(transaction) diff --git a/lnd-rpc-test/src/test/scala/org/bitcoins/lnd/rpc/LndRpcClientTest.scala b/lnd-rpc-test/src/test/scala/org/bitcoins/lnd/rpc/LndRpcClientTest.scala index b9d3013166..c3b0278555 100644 --- a/lnd-rpc-test/src/test/scala/org/bitcoins/lnd/rpc/LndRpcClientTest.scala +++ b/lnd-rpc-test/src/test/scala/org/bitcoins/lnd/rpc/LndRpcClientTest.scala @@ -164,10 +164,12 @@ class LndRpcClientTest extends LndFixture { cltvExpiryDelta = UInt32.zero ) - val invoice = Invoice("memo", - value = 100000, - expiry = 1000, - routeHints = Vector(RouteHint(Vector(hopHint)))) + val invoice = Invoice( + "memo", + value = 100000, + expiry = 1000, + routeHints = Vector(RouteHint(Vector(hopHint))) + ) for { res <- lnd.addInvoice(invoice) diff --git a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/LndRpcClient.scala b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/LndRpcClient.scala index 3ef3b93c86..f46efb2a08 100644 --- a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/LndRpcClient.scala +++ b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/LndRpcClient.scala @@ -59,19 +59,22 @@ import scala.concurrent.duration.{DurationInt, FiniteDuration} import scala.concurrent.{Await, ExecutionContext, Future, Promise} import scala.util.Try -/** @param binaryOpt Path to lnd executable +/** @param binaryOpt + * Path to lnd executable */ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( - implicit val system: ActorSystem) - extends NativeProcessFactory + implicit val system: ActorSystem +) extends NativeProcessFactory with LndUtils with LndRouterClient with StartStopAsync[LndRpcClient] with BitcoinSLogger { instance match { case _: LndInstanceLocal => - require(binaryOpt.isDefined, - s"Binary must be defined with a local instance of lnd") + require( + binaryOpt.isDefined, + s"Binary must be defined with a local instance of lnd" + ) case _: LndInstanceRemote => () } @@ -94,7 +97,9 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( case Some(cert) => Some( new ByteArrayInputStream( - cert.getBytes(java.nio.charset.StandardCharsets.UTF_8.name))) + cert.getBytes(java.nio.charset.StandardCharsets.UTF_8.name) + ) + ) case None => None } } @@ -152,7 +157,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( lazy val versionerClient: VersionerClient = VersionerClient(clientSettings) lazy val chainClient: ChainNotifierClient = ChainNotifierClient( - clientSettings) + clientSettings + ) def genSeed(): Future[GenSeedResponse] = { logger.trace("lnd calling genseed") @@ -169,8 +175,10 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( for { seed <- genSeed() - req = InitWalletRequest(walletPassword = passwordByteStr, - cipherSeedMnemonic = seed.cipherSeedMnemonic) + req = InitWalletRequest( + walletPassword = passwordByteStr, + cipherSeedMnemonic = seed.cipherSeedMnemonic + ) res <- unlocker.initWallet(req).map(_.adminMacaroon) } yield res } @@ -230,7 +238,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def addInvoice( memo: String, value: Satoshis, - expiry: Long): Future[AddInvoiceResult] = { + expiry: Long + ): Future[AddInvoiceResult] = { val invoice: Invoice = Invoice(memo = memo, value = value.toLong, expiry = expiry) @@ -240,11 +249,14 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def addInvoice( descriptionHash: Sha256Digest, value: Satoshis, - expiry: Long): Future[AddInvoiceResult] = { + expiry: Long + ): Future[AddInvoiceResult] = { val invoice: Invoice = - Invoice(value = value.toLong, - expiry = expiry, - descriptionHash = descriptionHash.bytes) + Invoice( + value = value.toLong, + expiry = expiry, + descriptionHash = descriptionHash.bytes + ) addInvoice(invoice) } @@ -252,7 +264,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def addInvoice( memo: String, value: MilliSatoshis, - expiry: Long): Future[AddInvoiceResult] = { + expiry: Long + ): Future[AddInvoiceResult] = { val invoice: Invoice = Invoice(memo = memo, valueMsat = value.toLong, expiry = expiry) @@ -262,11 +275,14 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def addInvoice( descriptionHash: Sha256Digest, value: MilliSatoshis, - expiry: Long): Future[AddInvoiceResult] = { + expiry: Long + ): Future[AddInvoiceResult] = { val invoice: Invoice = - Invoice(valueMsat = value.toLong, - expiry = expiry, - descriptionHash = descriptionHash.bytes) + Invoice( + valueMsat = value.toLong, + expiry = expiry, + descriptionHash = descriptionHash.bytes + ) addInvoice(invoice) } @@ -350,11 +366,13 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( val spkBytes = ByteVector.fromValidHex(utxo.pkScript) - UTXOResult(BitcoinAddress.fromString(utxo.address), - Satoshis(utxo.amountSat), - ScriptPubKey.fromAsmBytes(spkBytes), - outPointOpt, - utxo.confirmations) + UTXOResult( + BitcoinAddress.fromString(utxo.address), + Satoshis(utxo.amountSat), + ScriptPubKey.fromAsmBytes(spkBytes), + outPointOpt, + utxo.confirmations + ) }) } @@ -371,7 +389,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def connectPeer( nodeId: NodeId, addr: InetSocketAddress, - permanent: Boolean): Future[Unit] = { + permanent: Boolean + ): Future[Unit] = { val lnAddr: LightningAddress = LightningAddress(nodeId.hex, s"${addr.getHostName}:${addr.getPort}") @@ -409,7 +428,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( nodeId: NodeId, fundingAmount: CurrencyUnit, satPerVByte: SatoshisPerVirtualByte, - privateChannel: Boolean): Future[Option[TransactionOutPoint]] = { + privateChannel: Boolean + ): Future[Option[TransactionOutPoint]] = { val request = OpenChannelRequest( nodePubkey = nodeId.bytes, localFundingAmount = fundingAmount.satoshis.toLong, @@ -425,7 +445,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( fundingAmount: CurrencyUnit, pushAmt: CurrencyUnit, satPerVByte: SatoshisPerVirtualByte, - privateChannel: Boolean): Future[Option[TransactionOutPoint]] = { + privateChannel: Boolean + ): Future[Option[TransactionOutPoint]] = { val request = OpenChannelRequest( nodePubkey = nodeId.bytes, localFundingAmount = fundingAmount.satoshis.toLong, @@ -438,7 +459,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( } def openChannel( - request: OpenChannelRequest): Future[Option[TransactionOutPoint]] = { + request: OpenChannelRequest + ): Future[Option[TransactionOutPoint]] = { logger.trace("lnd calling openchannel") lnd @@ -456,25 +478,31 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def closeChannel( outPoint: TransactionOutPoint, force: Boolean, - feeRate: SatoshisPerVirtualByte): Future[DoubleSha256DigestBE] = { + feeRate: SatoshisPerVirtualByte + ): Future[DoubleSha256DigestBE] = { val channelPoint = ChannelPoint(FundingTxidBytes(outPoint.txId.bytes), outPoint.vout) closeChannel( - CloseChannelRequest(channelPoint = Some(channelPoint), - force = force, - satPerVbyte = UInt64(feeRate.toLong))) + CloseChannelRequest( + channelPoint = Some(channelPoint), + force = force, + satPerVbyte = UInt64(feeRate.toLong) + ) + ) } def closeChannel( - outPoint: TransactionOutPoint): Future[DoubleSha256DigestBE] = { + outPoint: TransactionOutPoint + ): Future[DoubleSha256DigestBE] = { val channelPoint = ChannelPoint(FundingTxidBytes(outPoint.txId.bytes), outPoint.vout) closeChannel(CloseChannelRequest(Some(channelPoint))) } def closeChannel( - request: CloseChannelRequest): Future[DoubleSha256DigestBE] = { + request: CloseChannelRequest + ): Future[DoubleSha256DigestBE] = { logger.trace("lnd calling closechannel") lnd @@ -498,12 +526,15 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def abandonChannel( outPoint: TransactionOutPoint, - pendingFundingShimOnly: Boolean): Future[Unit] = { + pendingFundingShimOnly: Boolean + ): Future[Unit] = { val channelPoint: ChannelPoint = outPoint val request = - AbandonChannelRequest(Some(channelPoint), - pendingFundingShimOnly = pendingFundingShimOnly, - iKnowWhatIAmDoing = true) + AbandonChannelRequest( + Some(channelPoint), + pendingFundingShimOnly = pendingFundingShimOnly, + iKnowWhatIAmDoing = true + ) abandonChannel(request) } @@ -514,8 +545,9 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( lnd.abandonChannel(request).map(_ => ()) } - def listChannels(request: ListChannelsRequest = - ListChannelsRequest()): Future[Vector[Channel]] = { + def listChannels( + request: ListChannelsRequest = ListChannelsRequest() + ): Future[Vector[Channel]] = { logger.trace("lnd calling listchannels") lnd @@ -530,10 +562,12 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( } def findChannel( - channelPoint: TransactionOutPoint): Future[Option[Channel]] = { + channelPoint: TransactionOutPoint + ): Future[Option[Channel]] = { listChannels().map { channels => channels.find( - _.channelPoint == s"${channelPoint.txId.hex}:${channelPoint.vout.toLong}") + _.channelPoint == s"${channelPoint.txId.hex}:${channelPoint.vout.toLong}" + ) } } @@ -549,9 +583,11 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( lnd .walletBalance(WalletBalanceRequest()) .map { bals => - WalletBalances(balance = Satoshis(bals.totalBalance), - unconfirmedBalance = Satoshis(bals.unconfirmedBalance), - confirmedBalance = Satoshis(bals.confirmedBalance)) + WalletBalances( + balance = Satoshis(bals.totalBalance), + unconfirmedBalance = Satoshis(bals.unconfirmedBalance), + confirmedBalance = Satoshis(bals.confirmedBalance) + ) } } @@ -567,24 +603,31 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( remoteBalance = Satoshis(bals.remoteBalance.map(_.sat).getOrElse(UInt64.zero)), unsettledLocalBalance = Satoshis( - bals.unsettledLocalBalance.map(_.sat).getOrElse(UInt64.zero)), + bals.unsettledLocalBalance.map(_.sat).getOrElse(UInt64.zero) + ), unsettledRemoteBalance = Satoshis( - bals.unsettledRemoteBalance.map(_.sat).getOrElse(UInt64.zero)), + bals.unsettledRemoteBalance.map(_.sat).getOrElse(UInt64.zero) + ), pendingOpenLocalBalance = Satoshis( - bals.pendingOpenLocalBalance.map(_.sat).getOrElse(UInt64.zero)), + bals.pendingOpenLocalBalance.map(_.sat).getOrElse(UInt64.zero) + ), pendingOpenRemoteBalance = Satoshis( - bals.pendingOpenRemoteBalance.map(_.sat).getOrElse(UInt64.zero)) + bals.pendingOpenRemoteBalance.map(_.sat).getOrElse(UInt64.zero) + ) ) } } def sendPayment( invoice: LnInvoice, - timeout: FiniteDuration): Future[Payment] = { + timeout: FiniteDuration + ): Future[Payment] = { val request: SendPaymentRequest = - SendPaymentRequest(paymentRequest = invoice.toString, - timeoutSeconds = timeout.toSeconds.toInt, - noInflightUpdates = true) + SendPaymentRequest( + paymentRequest = invoice.toString, + timeoutSeconds = timeout.toSeconds.toInt, + noInflightUpdates = true + ) sendPayment(request) } @@ -592,12 +635,15 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def sendPayment( invoice: LnInvoice, feeLimit: Satoshis, - timeout: FiniteDuration): Future[Payment] = { + timeout: FiniteDuration + ): Future[Payment] = { val request: SendPaymentRequest = - SendPaymentRequest(paymentRequest = invoice.toString, - timeoutSeconds = timeout.toSeconds.toInt, - feeLimitSat = feeLimit.toLong, - noInflightUpdates = true) + SendPaymentRequest( + paymentRequest = invoice.toString, + timeoutSeconds = timeout.toSeconds.toInt, + feeLimitSat = feeLimit.toLong, + noInflightUpdates = true + ) sendPayment(request) } @@ -605,12 +651,15 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def sendPayment( nodeId: NodeId, amount: CurrencyUnit, - timeout: FiniteDuration): Future[Payment] = { + timeout: FiniteDuration + ): Future[Payment] = { val request: SendPaymentRequest = - SendPaymentRequest(dest = nodeId.bytes, - amt = amount.satoshis.toLong, - timeoutSeconds = timeout.toSeconds.toInt, - noInflightUpdates = true) + SendPaymentRequest( + dest = nodeId.bytes, + amt = amount.satoshis.toLong, + timeoutSeconds = timeout.toSeconds.toInt, + noInflightUpdates = true + ) sendPayment(request) } @@ -627,18 +676,22 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def sendOutputs( outputs: Vector[TransactionOutput], feeRate: SatoshisPerVirtualByte, - spendUnconfirmed: Boolean): Future[Tx] = { + spendUnconfirmed: Boolean + ): Future[Tx] = { sendOutputs(outputs, feeRate.toSatoshisPerKW, spendUnconfirmed) } def sendOutputs( outputs: Vector[TransactionOutput], feeRate: SatoshisPerKW, - spendUnconfirmed: Boolean): Future[Tx] = { + spendUnconfirmed: Boolean + ): Future[Tx] = { - val request = SendOutputsRequest(satPerKw = feeRate.toLong, - outputs = outputs, - spendUnconfirmed = spendUnconfirmed) + val request = SendOutputsRequest( + satPerKw = feeRate.toLong, + outputs = outputs, + spendUnconfirmed = spendUnconfirmed + ) sendOutputs(request) } @@ -654,16 +707,19 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( inputs: Vector[TransactionOutPoint], outputs: Map[BitcoinAddress, CurrencyUnit], feeRate: SatoshisPerVirtualByte, - spendUnconfirmed: Boolean): Future[PSBT] = { + spendUnconfirmed: Boolean + ): Future[PSBT] = { val outputMap = outputs.map { case (addr, amt) => addr.toString -> amt.satoshis.toUInt64 } val template = TxTemplate(inputs, outputMap) val rawTemplate = FundPsbtRequest.Template.Raw(template) val fees = SatPerVbyte(UInt64(feeRate.toLong)) - val request = FundPsbtRequest(template = rawTemplate, - fees = fees, - spendUnconfirmed = spendUnconfirmed) + val request = FundPsbtRequest( + template = rawTemplate, + fees = fees, + spendUnconfirmed = spendUnconfirmed + ) fundPSBT(request) } @@ -673,17 +729,20 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( outputs: Map[BitcoinAddress, CurrencyUnit], feeRate: SatoshisPerVirtualByte, account: String, - spendUnconfirmed: Boolean): Future[PSBT] = { + spendUnconfirmed: Boolean + ): Future[PSBT] = { val outputMap = outputs.map { case (addr, amt) => addr.toString -> amt.satoshis.toUInt64 } val template = TxTemplate(inputs, outputMap) val rawTemplate = FundPsbtRequest.Template.Raw(template) val fees = SatPerVbyte(UInt64(feeRate.toLong)) - val request = FundPsbtRequest(template = rawTemplate, - fees = fees, - account = account, - spendUnconfirmed = spendUnconfirmed) + val request = FundPsbtRequest( + template = rawTemplate, + fees = fees, + account = account, + spendUnconfirmed = spendUnconfirmed + ) fundPSBT(request) } @@ -692,13 +751,16 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( psbt: PSBT, feeRate: SatoshisPerVirtualByte, account: String, - spendUnconfirmed: Boolean): Future[PSBT] = { + spendUnconfirmed: Boolean + ): Future[PSBT] = { val template = Psbt(psbt.bytes) val fees = SatPerVbyte(UInt64(feeRate.toLong)) - val request = FundPsbtRequest(template = template, - fees = fees, - account = account, - spendUnconfirmed = spendUnconfirmed) + val request = FundPsbtRequest( + template = template, + fees = fees, + account = account, + spendUnconfirmed = spendUnconfirmed + ) fundPSBT(request) } @@ -706,12 +768,15 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def fundPSBT( psbt: PSBT, feeRate: SatoshisPerVirtualByte, - spendUnconfirmed: Boolean): Future[PSBT] = { + spendUnconfirmed: Boolean + ): Future[PSBT] = { val template = Psbt(psbt.bytes) val fees = SatPerVbyte(UInt64(feeRate.toLong)) - val request = FundPsbtRequest(template = template, - fees = fees, - spendUnconfirmed = spendUnconfirmed) + val request = FundPsbtRequest( + template = template, + fees = fees, + spendUnconfirmed = spendUnconfirmed + ) fundPSBT(request) } @@ -765,13 +830,15 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( hashType: HashType, output: TransactionOutput, signMethod: SignMethod, - prevOuts: Vector[TransactionOutput]): Future[ - (ScriptSignature, ScriptWitness)] = { + prevOuts: Vector[TransactionOutput] + ): Future[(ScriptSignature, ScriptWitness)] = { val signDescriptor = - SignDescriptor(output = Some(output), - sighash = UInt32(hashType.num), - inputIndex = inputIdx, - signMethod = signMethod) + SignDescriptor( + output = Some(output), + sighash = UInt32(hashType.num), + inputIndex = inputIdx, + signMethod = signMethod + ) val request: SignReq = SignReq(tx.bytes, Vector(signDescriptor), prevOuts) @@ -783,12 +850,15 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( tx: Tx, inputIdx: Int, output: TransactionOutput, - signMethod: SignMethod): Future[(ScriptSignature, ScriptWitness)] = { + signMethod: SignMethod + ): Future[(ScriptSignature, ScriptWitness)] = { val signDescriptor = - SignDescriptor(output = Some(output), - sighash = UInt32(HashType.sigHashAll.num), - inputIndex = inputIdx, - signMethod = signMethod) + SignDescriptor( + output = Some(output), + sighash = UInt32(HashType.sigHashAll.num), + inputIndex = inputIdx, + signMethod = signMethod + ) computeInputScript(tx, Vector(signDescriptor)).map(_.head) } @@ -796,19 +866,22 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def computeInputScript( tx: Tx, inputIdx: Int, - output: TransactionOutput): Future[(ScriptSignature, ScriptWitness)] = { + output: TransactionOutput + ): Future[(ScriptSignature, ScriptWitness)] = { val signDescriptor = - SignDescriptor(output = Some(output), - sighash = UInt32(HashType.sigHashAll.num), - inputIndex = inputIdx) + SignDescriptor( + output = Some(output), + sighash = UInt32(HashType.sigHashAll.num), + inputIndex = inputIdx + ) computeInputScript(tx, Vector(signDescriptor)).map(_.head) } def computeInputScript( tx: Tx, - signDescriptors: Vector[SignDescriptor]): Future[ - Vector[(ScriptSignature, ScriptWitness)]] = { + signDescriptors: Vector[SignDescriptor] + ): Future[Vector[(ScriptSignature, ScriptWitness)]] = { val request: SignReq = SignReq(tx.bytes, signDescriptors) @@ -816,7 +889,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( } def computeInputScript( - request: SignReq): Future[Vector[(ScriptSignature, ScriptWitness)]] = { + request: SignReq + ): Future[Vector[(ScriptSignature, ScriptWitness)]] = { logger.trace("lnd calling computeinputscript") signer.computeInputScript(request).map { res => @@ -848,22 +922,28 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def leaseOutput( outpoint: TransactionOutPoint, - leaseSeconds: Long): Future[UInt64] = { + leaseSeconds: Long + ): Future[UInt64] = { val outPoint = OutPoint(outpoint.txId.bytes, outputIndex = outpoint.vout) - val request = LeaseOutputRequest(id = LndRpcClient.leaseId, - outpoint = Some(outPoint), - expirationSeconds = UInt64(leaseSeconds)) + val request = LeaseOutputRequest( + id = LndRpcClient.leaseId, + outpoint = Some(outPoint), + expirationSeconds = UInt64(leaseSeconds) + ) leaseOutput(request) } - /** LeaseOutput locks an output to the given ID, preventing it from being available for any future coin selection attempts. - * The absolute time of the lock's expiration is returned. - * The expiration of the lock can be extended by successive invocations of this RPC. - * @param request LeaseOutputRequest - * @return Unix timestamp for when the lease expires + /** LeaseOutput locks an output to the given ID, preventing it from being + * available for any future coin selection attempts. The absolute time of the + * lock's expiration is returned. The expiration of the lock can be extended + * by successive invocations of this RPC. + * @param request + * LeaseOutputRequest + * @return + * Unix timestamp for when the lease expires */ def leaseOutput(request: LeaseOutputRequest): Future[UInt64] = { logger.trace("lnd calling leaseoutput") @@ -889,7 +969,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def sendCustomMessage( peer: NodeId, - lnMessage: LnMessage[TLV]): Future[Unit] = { + lnMessage: LnMessage[TLV] + ): Future[Unit] = { sendCustomMessage(peer, lnMessage.tlv) } @@ -900,11 +981,14 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def sendCustomMessage( peer: NodeId, tpe: BigSizeUInt, - data: ByteVector): Future[Unit] = { + data: ByteVector + ): Future[Unit] = { val request = - SendCustomMessageRequest(peer = peer.bytes, - `type` = UInt32(tpe.toBigInt), - data = data) + SendCustomMessageRequest( + peer = peer.bytes, + `type` = UInt32(tpe.toBigInt), + data = data + ) sendCustomMessage(request) } @@ -926,7 +1010,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( } /** Broadcasts the given transaction - * @return None if no error, otherwise the error string + * @return + * None if no error, otherwise the error string */ def publishTransaction(tx: Tx): Future[Option[String]] = { logger.trace("lnd calling publishtransaction") @@ -956,12 +1041,14 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def getTransactions( startHeight: Int, - endHeight: Int): Future[Vector[TxDetails]] = { + endHeight: Int + ): Future[Vector[TxDetails]] = { getTransactions(GetTransactionsRequest(startHeight, endHeight)) } def getTransactions( - request: GetTransactionsRequest): Future[Vector[TxDetails]] = { + request: GetTransactionsRequest + ): Future[Vector[TxDetails]] = { logger.trace("lnd calling gettransactions") lnd @@ -972,15 +1059,20 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def subscribeTxConfirmation( script: ScriptPubKey, requiredConfs: Int, - heightHint: Int): Future[ConfDetails] = { - require(heightHint > 0, - s"heightHint must be greater than 0, got $heightHint") + heightHint: Int + ): Future[ConfDetails] = { + require( + heightHint > 0, + s"heightHint must be greater than 0, got $heightHint" + ) val request = - ConfRequest(txid = DoubleSha256Digest.empty.bytes, - script = script.asmBytes, - numConfs = UInt32(requiredConfs), - heightHint = UInt32(heightHint)) + ConfRequest( + txid = DoubleSha256Digest.empty.bytes, + script = script.asmBytes, + numConfs = UInt32(requiredConfs), + heightHint = UInt32(heightHint) + ) registerConfirmationsNotification(request) .filter(_.event.isConf) @@ -992,15 +1084,20 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( txId: DoubleSha256Digest, script: ScriptPubKey, requiredConfs: Int, - heightHint: Int): Future[ConfDetails] = { - require(heightHint > 0, - s"heightHint must be greater than 0, got $heightHint") + heightHint: Int + ): Future[ConfDetails] = { + require( + heightHint > 0, + s"heightHint must be greater than 0, got $heightHint" + ) val request = - ConfRequest(txid = txId.bytes, - script = script.asmBytes, - numConfs = UInt32(requiredConfs), - heightHint = UInt32(heightHint)) + ConfRequest( + txid = txId.bytes, + script = script.asmBytes, + numConfs = UInt32(requiredConfs), + heightHint = UInt32(heightHint) + ) registerConfirmationsNotification(request) .filter(_.event.isConf) @@ -1009,7 +1106,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( } def registerConfirmationsNotification( - request: ConfRequest): Source[ConfEvent, NotUsed] = { + request: ConfRequest + ): Source[ConfEvent, NotUsed] = { logger.trace("lnd calling RegisterConfirmationsNtfn") chainClient.registerConfirmationsNtfn(request) @@ -1018,7 +1116,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def monitorInvoice( rHash: PaymentHashTag, interval: FiniteDuration = 1.second, - maxAttempts: Int = 60): Future[Invoice] = { + maxAttempts: Int = 60 + ): Future[Invoice] = { val p: Promise[Invoice] = Promise[Invoice]() val attempts = new AtomicInteger(0) val runnable = new Runnable() { @@ -1026,17 +1125,17 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( def run(): Unit = { val receivedInfoF = lookupInvoice(rHash) - //register callback that publishes a payment to our actor system's - //event stream, + // register callback that publishes a payment to our actor system's + // event stream, receivedInfoF.foreach { info: Invoice => if (info.state.isSettled) { - //invoice has been paid, let's publish to event stream - //so subscribers so the even stream can see that a payment - //was received - //we need to create a `PaymentSucceeded` + // invoice has been paid, let's publish to event stream + // so subscribers so the even stream can see that a payment + // was received + // we need to create a `PaymentSucceeded` system.eventStream.publish(info) - //complete the promise so the runnable will be canceled + // complete the promise so the runnable will be canceled p.success(info) } else if (attempts.incrementAndGet() >= maxAttempts) { // too many tries to get info about a payment @@ -1045,7 +1144,9 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( p.failure( new RuntimeException( s"LndApi.monitorInvoice() [$instance] too many attempts: ${attempts - .get()} for invoice=${rHash.hash.hex}")) + .get()} for invoice=${rHash.hash.hex}" + ) + ) } } } @@ -1066,7 +1167,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( } /** Boolean check to verify the state of the client - * @return Future Boolean representing if client has started + * @return + * Future Boolean representing if client has started */ def isStarted: Future[Boolean] = { val p = Promise[Boolean]() @@ -1092,9 +1194,10 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( p.future } - /** Returns a Future LndRpcClient if able to shut down - * Lnd instance, inherits from the StartStop trait - * @return A future LndRpcClient that is stopped + /** Returns a Future LndRpcClient if able to shut down Lnd instance, inherits + * from the StartStop trait + * @return + * A future LndRpcClient that is stopped */ override def stop(): Future[LndRpcClient] = { logger.trace("lnd calling stop daemon") @@ -1125,8 +1228,8 @@ class LndRpcClient(val instance: LndInstance, binaryOpt: Option[File] = None)( object LndRpcClient { - /** Lease id should be unique per application - * this is the sha256 of "lnd bitcoin-s" + /** Lease id should be unique per application this is the sha256 of "lnd + * bitcoin-s" */ val leaseId: ByteString = hex"8c45ee0b90e3afd0fb4d6f39afa3c5d551ee5f2c7ac2d06820ed3d16582186d2" @@ -1137,26 +1240,27 @@ object LndRpcClient { /** Key used for adding the macaroon to the gRPC header */ private[lnd] val macaroonKey = "macaroon" - /** THe name we use to create actor systems. We use this to know which - * actor systems to shut down on node shutdown + /** THe name we use to create actor systems. We use this to know which actor + * systems to shut down on node shutdown */ private[lnd] val ActorSystemName = "lnd-rpc-client-created-by-bitcoin-s" - /** Creates an RPC client from the given instance, - * together with the given actor system. This is for - * advanced users, where you need fine grained control - * over the RPC client. + /** Creates an RPC client from the given instance, together with the given + * actor system. This is for advanced users, where you need fine grained + * control over the RPC client. */ def apply( instance: LndInstance, - binary: Option[File] = None): LndRpcClient = { + binary: Option[File] = None + ): LndRpcClient = { implicit val system: ActorSystem = ActorSystem.create(ActorSystemName) withActorSystem(instance, binary) } - /** Constructs a RPC client from the given datadir, or - * the default datadir if no directory is provided + /** Constructs a RPC client from the given datadir, or the default datadir if + * no directory is provided */ def withActorSystem(instance: LndInstance, binary: Option[File] = None)( - implicit system: ActorSystem) = new LndRpcClient(instance, binary) + implicit system: ActorSystem + ) = new LndRpcClient(instance, binary) } diff --git a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/LndUtils.scala b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/LndUtils.scala index 20f4cb4326..961b07ac1f 100644 --- a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/LndUtils.scala +++ b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/LndUtils.scala @@ -30,8 +30,10 @@ trait LndUtils { TxOut(output.value.satoshis.toLong, output.scriptPubKey.asmBytes) implicit def txOutToTxOutput(txOut: TxOut): TransactionOutput = - TransactionOutput(Satoshis(txOut.value), - ScriptPubKey.fromAsmBytes(txOut.pkScript)) + TransactionOutput( + Satoshis(txOut.value), + ScriptPubKey.fromAsmBytes(txOut.pkScript) + ) implicit def outpointToTxOutPoint(op: OutPoint): TransactionOutPoint = TransactionOutPoint(DoubleSha256DigestBE(op.txidStr), op.outputIndex) @@ -42,35 +44,42 @@ trait LndUtils { // If other kinds of Iterables are needed, there's a fancy thing to do // that is done all over the Seq code using params and an implicit CanBuildFrom implicit def outputVecToTxOuts( - outputs: Vector[TransactionOutput]): Vector[TxOut] = + outputs: Vector[TransactionOutput] + ): Vector[TxOut] = outputs.map(outputToTxOut) implicit def outpointVecToTxOutPointVec( - ops: Vector[OutPoint]): Vector[TransactionOutPoint] = + ops: Vector[OutPoint] + ): Vector[TransactionOutPoint] = ops.map(outpointToTxOutPoint) implicit def txOutpointToOutpointVec( - ops: Vector[TransactionOutPoint]): Vector[OutPoint] = + ops: Vector[TransactionOutPoint] + ): Vector[OutPoint] = ops.map(txOutpointToOutpoint) implicit def byteStringVecToByteVecs( - byteStrings: Vector[ByteString]): Vector[ByteVector] = + byteStrings: Vector[ByteString] + ): Vector[ByteVector] = byteStrings.map(byteStringToByteVec) implicit def channelPointToOutpoint( - channelPoint: ChannelPoint): TransactionOutPoint = { + channelPoint: ChannelPoint + ): TransactionOutPoint = { val txIdBytes = channelPoint.fundingTxid.fundingTxidBytes.get TransactionOutPoint(DoubleSha256Digest(txIdBytes), channelPoint.outputIndex) } implicit def outPointToChannelPoint( - outPoint: TransactionOutPoint): ChannelPoint = { + outPoint: TransactionOutPoint + ): ChannelPoint = { val txId = FundingTxidBytes(outPoint.txIdBE.bytes) ChannelPoint(txId, outPoint.vout) } implicit def lndOutputDetailToOutputDetails( - detail: lnrpc.OutputDetail): OutputDetails = { + detail: lnrpc.OutputDetail + ): OutputDetails = { OutputDetails( addressOpt = BitcoinAddress.fromStringOpt(detail.address), spk = ScriptPubKey.fromAsmHex(detail.pkScript), @@ -81,7 +90,8 @@ trait LndUtils { } implicit def LndTransactionToTxDetails( - details: lnrpc.Transaction): TxDetails = { + details: lnrpc.Transaction + ): TxDetails = { val blockHashOpt = if (details.blockHash.isEmpty) { None } else Some(DoubleSha256DigestBE(details.blockHash)) diff --git a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndConfig.scala b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndConfig.scala index 2b5f00c70b..e8a13854a4 100644 --- a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndConfig.scala +++ b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndConfig.scala @@ -10,54 +10,54 @@ import java.net.URI import java.nio.file.{Files, Path, Paths} import scala.util.Properties -/** This class represents a parsed `lnd.conf` file. It - * respects the different ways of writing options in - * `lnd.conf`: Raw options, network-prefixed options - * and options within network sections. It also tries to - * conform to the way lnd gives precedence to the - * different properties. +/** This class represents a parsed `lnd.conf` file. It respects the different + * ways of writing options in `lnd.conf`: Raw options, network-prefixed options + * and options within network sections. It also tries to conform to the way lnd + * gives precedence to the different properties. * - * Not all options are exposed from this class. We only - * expose those that are of relevance when making RPC - * requests. + * Not all options are exposed from this class. We only expose those that are + * of relevance when making RPC requests. */ case class LndConfig(private[bitcoins] val lines: Seq[String], datadir: File) extends BitcoinSLogger { - //create datadir and config if it DNE on disk + // create datadir and config if it DNE on disk if (!datadir.exists()) { logger.debug( - s"datadir=${datadir.getAbsolutePath} does not exist, creating now") + s"datadir=${datadir.getAbsolutePath} does not exist, creating now" + ) datadir.mkdirs() LndConfig.writeConfigToFile(this, datadir) } private val confFile = datadir.toPath.resolve("lnd.conf") - //create lnd.conf file in datadir if it does not exist + // create lnd.conf file in datadir if it does not exist if (!Files.exists(confFile)) { logger.debug( - s"lnd.conf in datadir=${datadir.getAbsolutePath} does not exist, creating now") + s"lnd.conf in datadir=${datadir.getAbsolutePath} does not exist, creating now" + ) LndConfig.writeConfigToFile(this, datadir) } - /** Converts the config back to a string that can be written - * to file, and passed to `lnd` + /** Converts the config back to a string that can be written to file, and + * passed to `lnd` */ lazy val toWriteableString: String = lines.mkString("\n") - /** Splits the provided lines into pairs of keys/values - * based on `=`, and then applies the provided - * `collect` function on those pairs + /** Splits the provided lines into pairs of keys/values based on `=`, and then + * applies the provided `collect` function on those pairs */ - private def collectFrom(lines: Seq[String])( - collect: PartialFunction[(String, String), String]): Seq[String] = { + private def collectFrom( + lines: Seq[String] + )(collect: PartialFunction[(String, String), String]): Seq[String] = { val splittedPairs = { val splitLines = lines.map( _.split("=") .map(_.trim) - .toList) + .toList + ) splitLines.collect { case h :: t :: _ => h -> t @@ -133,7 +133,8 @@ case class LndConfig(private[bitcoins] val lines: Seq[String], datadir: File) val lines = newLine +: ourLines val newConfig = LndConfig(lines, datadir) logger.debug( - s"Appending new config with $key=$value to datadir=${datadir.getAbsolutePath}") + s"Appending new config with $key=$value to datadir=${datadir.getAbsolutePath}" + ) LndConfig.writeConfigToFile(newConfig, datadir) newConfig @@ -175,8 +176,8 @@ object LndConfig extends ConfigFactory[LndConfig] with BitcoinSLogger { /** The empty `lnd` config */ override lazy val empty: LndConfig = LndConfig("", DEFAULT_DATADIR) - /** Constructs a `lnd` config from the given string, - * by splitting it on newlines + /** Constructs a `lnd` config from the given string, by splitting it on + * newlines */ override def apply(config: String, datadir: File): LndConfig = apply(config.split("\n").toList, datadir) @@ -188,7 +189,8 @@ object LndConfig extends ConfigFactory[LndConfig] with BitcoinSLogger { /** Reads the given file and construct a `lnd` config from it */ override def apply( config: File, - datadir: File = DEFAULT_DATADIR): LndConfig = { + datadir: File = DEFAULT_DATADIR + ): LndConfig = { import org.bitcoins.core.compat.JavaConverters._ val lines = Files .readAllLines(config.toPath) @@ -207,9 +209,8 @@ object LndConfig extends ConfigFactory[LndConfig] with BitcoinSLogger { apply(dir.toPath.resolve("lnd.conf")) } - /** If there is a `lnd.conf` in the default - * data directory, this is read. Otherwise, the - * default configuration is returned. + /** If there is a `lnd.conf` in the default data directory, this is read. + * Otherwise, the default configuration is returned. */ override def fromDefaultDatadir: LndConfig = { if (DEFAULT_CONF_FILE.isFile) { @@ -235,8 +236,8 @@ object LndConfig extends ConfigFactory[LndConfig] with BitcoinSLogger { .resolve("lnd.conf") .toFile - /** Writes the config to the data directory within it, if it doesn't - * exist. Returns the written file. + /** Writes the config to the data directory within it, if it doesn't exist. + * Returns the written file. */ override def writeConfigToFile(config: LndConfig, datadir: File): Path = { @@ -247,7 +248,8 @@ object LndConfig extends ConfigFactory[LndConfig] with BitcoinSLogger { if (datadir == DEFAULT_DATADIR && confFile == DEFAULT_CONF_FILE.toPath) { logger.warn( - s"We will not overwrite the existing lnd.conf in default datadir") + s"We will not overwrite the existing lnd.conf in default datadir" + ) } else { Files.write(confFile, confStr.getBytes) } diff --git a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndInstance.scala b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndInstance.scala index 2ebce138ef..eef4d4731a 100644 --- a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndInstance.scala +++ b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/config/LndInstance.scala @@ -23,8 +23,8 @@ case class LndInstanceLocal( listenBinding: URI, restUri: URI, rpcUri: URI, - debugLevel: LogLevel) - extends LndInstance { + debugLevel: LogLevel +) extends LndInstance { override val certificateOpt: Option[String] = None override val certFileOpt: Option[File] = Some(certFile) @@ -78,8 +78,9 @@ object LndInstanceLocal } } - override def fromConfigFile(file: File = DEFAULT_CONF_FILE.toFile)(implicit - system: ActorSystem): LndInstanceLocal = { + override def fromConfigFile( + file: File = DEFAULT_CONF_FILE.toFile + )(implicit system: ActorSystem): LndInstanceLocal = { require(file.exists, s"${file.getPath} does not exist!") require(file.isFile, s"${file.getPath} is not a file!") @@ -88,8 +89,9 @@ object LndInstanceLocal fromConfig(config) } - override def fromDataDir(dir: File = DEFAULT_DATADIR.toFile)(implicit - system: ActorSystem): LndInstanceLocal = { + override def fromDataDir( + dir: File = DEFAULT_DATADIR.toFile + )(implicit system: ActorSystem): LndInstanceLocal = { require(dir.exists, s"${dir.getPath} does not exist!") require(dir.isDirectory, s"${dir.getPath} is not a directory!") @@ -108,22 +110,24 @@ case class LndInstanceRemote( rpcUri: URI, macaroon: String, certFileOpt: Option[File], - certificateOpt: Option[String]) - extends LndInstance + certificateOpt: Option[String] +) extends LndInstance object LndInstanceRemote { def apply( rpcUri: URI, macaroon: String, - certFile: File): LndInstanceRemote = { + certFile: File + ): LndInstanceRemote = { LndInstanceRemote(rpcUri, macaroon, Some(certFile), None) } def apply( rpcUri: URI, macaroon: String, - certificate: String): LndInstanceRemote = { + certificate: String + ): LndInstanceRemote = { LndInstanceRemote(rpcUri, macaroon, None, Some(certificate)) } } diff --git a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/internal/LndRouterClient.scala b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/internal/LndRouterClient.scala index 0a2be6b9b6..b789596534 100644 --- a/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/internal/LndRouterClient.scala +++ b/lnd-rpc/src/main/scala/org/bitcoins/lnd/rpc/internal/LndRouterClient.scala @@ -27,20 +27,25 @@ trait LndRouterClient { self: LndRpcClient => def queryRoutes( amount: CurrencyUnit, node: NodeId, - routeHints: Vector[LnRoute]): Future[QueryRoutesResponse] = { + routeHints: Vector[LnRoute] + ): Future[QueryRoutesResponse] = { val hopHints = routeHints.map { hint => - HopHint(hint.pubkey.hex, - hint.shortChannelID.u64, - UInt32(hint.feeBaseMsat.msat.toLong), - hint.feePropMilli.u32, - UInt32(hint.cltvExpiryDelta)) + HopHint( + hint.pubkey.hex, + hint.shortChannelID.u64, + UInt32(hint.feeBaseMsat.msat.toLong), + hint.feePropMilli.u32, + UInt32(hint.cltvExpiryDelta) + ) } val request = - QueryRoutesRequest(pubKey = node.pubKey.hex, - amt = amount.satoshis.toLong, - finalCltvDelta = 80, - useMissionControl = true, - routeHints = Vector(RouteHint(hopHints))) + QueryRoutesRequest( + pubKey = node.pubKey.hex, + amt = amount.satoshis.toLong, + finalCltvDelta = 80, + useMissionControl = true, + routeHints = Vector(RouteHint(hopHints)) + ) queryRoutes(request) } @@ -72,7 +77,8 @@ trait LndRouterClient { self: LndRpcClient => def probe( amount: Satoshis, node: NodeId, - routeHints: Vector[LnRoute]): Future[Vector[Route]] = { + routeHints: Vector[LnRoute] + ): Future[Vector[Route]] = { queryRoutes(amount, node, routeHints).map(_.routes).flatMap { routes => val fs = routes.toVector.map { route => val fakeHash = CryptoUtil.sha256(ECPrivateKey.freshPrivateKey.bytes) @@ -82,27 +88,33 @@ trait LndRouterClient { self: LndRpcClient => Future.sequence(fs).map { results => results .filter( - _._2.failure.exists(_.code == INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS)) + _._2.failure.exists(_.code == INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS) + ) .map(_._1) } } } def sendToRoute(invoice: LnInvoice, route: Route): Future[HTLCAttempt] = { - sendToRoute(invoice.lnTags.paymentHash.hash, - route, - invoice.lnTags.secret.map(_.secret)) + sendToRoute( + invoice.lnTags.paymentHash.hash, + route, + invoice.lnTags.secret.map(_.secret) + ) } def sendToRoute( paymentHash: Sha256Digest, route: Route, - secretOpt: Option[PaymentSecret]): Future[HTLCAttempt] = { + secretOpt: Option[PaymentSecret] + ): Future[HTLCAttempt] = { val updatedRoute = secretOpt match { case Some(secret) => val last = route.hops.last - val mpp = MPPRecord(paymentAddr = secret.bytes, - totalAmtMsat = route.totalAmtMsat) + val mpp = MPPRecord( + paymentAddr = secret.bytes, + totalAmtMsat = route.totalAmtMsat + ) val update = last.copy(mppRecord = Some(mpp), tlvPayload = true) val updatedHops = route.hops.init :+ update @@ -111,8 +123,10 @@ trait LndRouterClient { self: LndRpcClient => } val request = - SendToRouteRequest(paymentHash = paymentHash.bytes, - route = Some(updatedRoute)) + SendToRouteRequest( + paymentHash = paymentHash.bytes, + route = Some(updatedRoute) + ) sendToRoute(request) } @@ -126,7 +140,8 @@ trait LndRouterClient { self: LndRpcClient => def attemptToPayRoutes( invoice: LnInvoice, - routes: Vector[Route]): Future[Option[HTLCAttempt]] = { + routes: Vector[Route] + ): Future[Option[HTLCAttempt]] = { val init: Option[HTLCAttempt] = None FutureUtil.foldLeftAsync(init, routes) { case (ret, route) => ret match { diff --git a/lnurl-test/src/test/scala/org/bitcoins/lnurl/LnURLClientTest.scala b/lnurl-test/src/test/scala/org/bitcoins/lnurl/LnURLClientTest.scala index f6b288765f..b19a3a0284 100644 --- a/lnurl-test/src/test/scala/org/bitcoins/lnurl/LnURLClientTest.scala +++ b/lnurl-test/src/test/scala/org/bitcoins/lnurl/LnURLClientTest.scala @@ -10,7 +10,8 @@ class LnURLClientTest extends BitcoinSAsyncTest { it must "make a pay request" in { val lnurl = LnURL.fromString( - "LNURL1DP68GURN8GHJ7MRWW4EXCTNXD9SHG6NPVCHXXMMD9AKXUATJDSKHQCTE8AEK2UMND9HKU0TPXUCRJVEHXV6RYVEEX5CNSCESXYURSEP5VE3RWCNP89JRJD33XUEXGCFNX5URZCT9XYMRQDRXVVCKZVRPV43KYV3E8YMKZE3H89SNWEVZTNK") + "LNURL1DP68GURN8GHJ7MRWW4EXCTNXD9SHG6NPVCHXXMMD9AKXUATJDSKHQCTE8AEK2UMND9HKU0TPXUCRJVEHXV6RYVEEX5CNSCESXYURSEP5VE3RWCNP89JRJD33XUEXGCFNX5URZCT9XYMRQDRXVVCKZVRPV43KYV3E8YMKZE3H89SNWEVZTNK" + ) client.makeRequest(lnurl).map { case pay: LnURLPayResponse => @@ -23,7 +24,8 @@ class LnURLClientTest extends BitcoinSAsyncTest { it must "make a pay request and get the invoice" in { val lnurl = LnURL.fromString( - "LNURL1DP68GURN8GHJ7MRWW4EXCTNXD9SHG6NPVCHXXMMD9AKXUATJDSKHQCTE8AEK2UMND9HKU0TPXUCRJVEHXV6RYVEEX5CNSCESXYURSEP5VE3RWCNP89JRJD33XUEXGCFNX5URZCT9XYMRQDRXVVCKZVRPV43KYV3E8YMKZE3H89SNWEVZTNK") + "LNURL1DP68GURN8GHJ7MRWW4EXCTNXD9SHG6NPVCHXXMMD9AKXUATJDSKHQCTE8AEK2UMND9HKU0TPXUCRJVEHXV6RYVEEX5CNSCESXYURSEP5VE3RWCNP89JRJD33XUEXGCFNX5URZCT9XYMRQDRXVVCKZVRPV43KYV3E8YMKZE3H89SNWEVZTNK" + ) client.makeRequest(lnurl).flatMap { case pay: LnURLPayResponse => @@ -39,7 +41,8 @@ class LnURLClientTest extends BitcoinSAsyncTest { it must "make a withdrawal request" in { val lnurl = LnURL.fromString( - "LNURL1DP68GURN8GHJ7MRWW4EXCTNXD9SHG6NPVCHXXMMD9AKXUATJDSKHW6T5DPJ8YCTH8AEK2UMND9HKU0FJVSCNZDPHVYENVDTPVYCRSVMPXVMRSCEEXGERQVPSXV6X2C3KX9JXZVMZ8PNXZDR9VY6N2DRZVG6RWEPCVYMRZDMRV9SK2D3KV43XVCF58DT") + "LNURL1DP68GURN8GHJ7MRWW4EXCTNXD9SHG6NPVCHXXMMD9AKXUATJDSKHW6T5DPJ8YCTH8AEK2UMND9HKU0FJVSCNZDPHVYENVDTPVYCRSVMPXVMRSCEEXGERQVPSXV6X2C3KX9JXZVMZ8PNXZDR9VY6N2DRZVG6RWEPCVYMRZDMRV9SK2D3KV43XVCF58DT" + ) client.makeRequest(lnurl).map { case _: LnURLPayResponse => @@ -54,10 +57,12 @@ class LnURLClientTest extends BitcoinSAsyncTest { it must "make a withdrawal request and do withdrawal" in { val lnurl = LnURL.fromString( - "LNURL1DP68GURN8GHJ7MRWW4EXCTNXD9SHG6NPVCHXXMMD9AKXUATJDSKHW6T5DPJ8YCTH8AEK2UMND9HKU0FJVSCNZDPHVYENVDTPVYCRSVMPXVMRSCEEXGERQVPSXV6X2C3KX9JXZVMZ8PNXZDR9VY6N2DRZVG6RWEPCVYMRZDMRV9SK2D3KV43XVCF58DT") + "LNURL1DP68GURN8GHJ7MRWW4EXCTNXD9SHG6NPVCHXXMMD9AKXUATJDSKHW6T5DPJ8YCTH8AEK2UMND9HKU0FJVSCNZDPHVYENVDTPVYCRSVMPXVMRSCEEXGERQVPSXV6X2C3KX9JXZVMZ8PNXZDR9VY6N2DRZVG6RWEPCVYMRZDMRV9SK2D3KV43XVCF58DT" + ) val inv = LnInvoice.fromString( - "lnbc1302470n1p3x3ssapp5axqf6dsusf98895vdhw97rn0szk4z6cxa5hfw3s2q5ksn3575qssdzz2pskjepqw3hjqnmsv4h9xct5wvszsnmjv3jhygzfgsazqem9dejhyctvtan82mny9ycqzpgxqzuysp5q97feeev2tnjsc0qn9kezqlgs8eekwfkxsc28uwxp9elnzkj2n0s9qyyssq02hkrz7dr0adx09t6w2tr9k8nczvq094r7qx297tsdupgeg5t3m8hvmkl7mqhtvx94he3swlg2qzhqk2j39wehcmv9awc06gex82e8qq0u0pm6") + "lnbc1302470n1p3x3ssapp5axqf6dsusf98895vdhw97rn0szk4z6cxa5hfw3s2q5ksn3575qssdzz2pskjepqw3hjqnmsv4h9xct5wvszsnmjv3jhygzfgsazqem9dejhyctvtan82mny9ycqzpgxqzuysp5q97feeev2tnjsc0qn9kezqlgs8eekwfkxsc28uwxp9elnzkj2n0s9qyyssq02hkrz7dr0adx09t6w2tr9k8nczvq094r7qx297tsdupgeg5t3m8hvmkl7mqhtvx94he3swlg2qzhqk2j39wehcmv9awc06gex82e8qq0u0pm6" + ) client.makeRequest(lnurl).flatMap { case _: LnURLPayResponse => diff --git a/lnurl/src/main/scala/org/bitcoins/lnurl/LnURL.scala b/lnurl/src/main/scala/org/bitcoins/lnurl/LnURL.scala index 0b45eb5bfd..1c412e7c3a 100644 --- a/lnurl/src/main/scala/org/bitcoins/lnurl/LnURL.scala +++ b/lnurl/src/main/scala/org/bitcoins/lnurl/LnURL.scala @@ -29,8 +29,10 @@ object LnURL extends StringFactory[LnURL] { def decode(url: String): Try[String] = { Bech32.splitToHrpAndData(url, Bech32Encoding.Bech32).map { case (hrp, data) => - require(hrp.equalsIgnoreCase(lnurlHRP), - s"LNURL must start with $lnurlHRP") + require( + hrp.equalsIgnoreCase(lnurlHRP), + s"LNURL must start with $lnurlHRP" + ) val converted = NumberUtil.convertUInt5sToUInt8(data) val bytes = UInt8.toBytes(converted) new String(bytes.toArray, "UTF-8") diff --git a/lnurl/src/main/scala/org/bitcoins/lnurl/LnURLClient.scala b/lnurl/src/main/scala/org/bitcoins/lnurl/LnURLClient.scala index 2f81423523..78d65acf09 100644 --- a/lnurl/src/main/scala/org/bitcoins/lnurl/LnURLClient.scala +++ b/lnurl/src/main/scala/org/bitcoins/lnurl/LnURLClient.scala @@ -20,8 +20,8 @@ import java.net.{URI, URL} import scala.concurrent._ class LnURLClient(proxyParams: Option[Socks5ProxyParams])(implicit - system: ActorSystem) - extends BitcoinSLogger { + system: ActorSystem +) extends BitcoinSLogger { implicit protected val ec: ExecutionContext = system.dispatcher private val http = Http(system) @@ -30,7 +30,8 @@ class LnURLClient(proxyParams: Option[Socks5ProxyParams])(implicit val httpConnectionPoolSettings = Socks5ClientTransport.createConnectionPoolSettings( new URI(request.uri.toString), - proxyParams) + proxyParams + ) http .singleRequest(request, settings = httpConnectionPoolSettings) @@ -40,8 +41,9 @@ class LnURLClient(proxyParams: Option[Socks5ProxyParams])(implicit .map(payload => payload.decodeString(ByteString.UTF_8)) } - private def sendRequestAndParse[T <: LnURLJsonModel](request: HttpRequest)( - implicit reads: Reads[T]): Future[T] = { + private def sendRequestAndParse[T <: LnURLJsonModel]( + request: HttpRequest + )(implicit reads: Reads[T]): Future[T] = { val withAcceptHeader = request.addHeader(Accept(MediaTypes.`application/json`)) sendRequest(withAcceptHeader) @@ -53,10 +55,12 @@ class LnURLClient(proxyParams: Option[Socks5ProxyParams])(implicit json.validate[LnURLStatus] match { case JsSuccess(value, _) => throw new RuntimeException( - value.reason.getOrElse("Error parsing response")) + value.reason.getOrElse("Error parsing response") + ) case JsError(_) => throw new RuntimeException( - s"Error parsing json $str, got ${errors.mkString("\n")}") + s"Error parsing json $str, got ${errors.mkString("\n")}" + ) } } } @@ -77,21 +81,24 @@ class LnURLClient(proxyParams: Option[Socks5ProxyParams])(implicit def getInvoice( pay: LnURLPayResponse, amount: LnCurrencyUnit, - extraParams: Map[String, String]): Future[LnInvoice] = { + extraParams: Map[String, String] + ): Future[LnInvoice] = { getInvoice(pay, amount.toMSat, extraParams) } def getInvoice( pay: LnURLPayResponse, amount: CurrencyUnit, - extraParams: Map[String, String]): Future[LnInvoice] = { + extraParams: Map[String, String] + ): Future[LnInvoice] = { getInvoice(pay, MilliSatoshis(amount), extraParams) } def getInvoice( pay: LnURLPayResponse, amount: MilliSatoshis, - extraParams: Map[String, String]): Future[LnInvoice] = { + extraParams: Map[String, String] + ): Future[LnInvoice] = { val symbol = if (pay.callback.toString.contains("?")) "&" else "?" val queryStringParams = extraParams.map(kv => s"${kv._1}=${kv._2}").mkString("&") @@ -103,7 +110,8 @@ class LnURLClient(proxyParams: Option[Socks5ProxyParams])(implicit def doWithdrawal( withdraw: LnURLWithdrawResponse, - invoice: LnInvoice): Future[Boolean] = { + invoice: LnInvoice + ): Future[Boolean] = { val symbol = if (withdraw.callback.toString.contains("?")) "&" else "?" val url = s"${withdraw.callback}${symbol}k1=${withdraw.k1}&pr=$invoice" sendRequestAndParse[LnURLStatus](Get(url)).map(_.status.toUpperCase == "OK") diff --git a/lnurl/src/main/scala/org/bitcoins/lnurl/json/LnURLJsonModels.scala b/lnurl/src/main/scala/org/bitcoins/lnurl/json/LnURLJsonModels.scala index ba8e670b14..dd3ea9d8d0 100644 --- a/lnurl/src/main/scala/org/bitcoins/lnurl/json/LnURLJsonModels.scala +++ b/lnurl/src/main/scala/org/bitcoins/lnurl/json/LnURLJsonModels.scala @@ -34,7 +34,8 @@ object LnURLJsonModels { description: Option[String], url: Option[URL], ciphertext: Option[String], - iv: Option[String]) + iv: Option[String] + ) implicit val LnURLSuccessActionReads: Reads[LnURLSuccessAction] = Json.reads[LnURLSuccessAction] @@ -48,8 +49,8 @@ object LnURLJsonModels { minSendable: MilliSatoshis, private val metadata: String, nostrPubkey: Option[SchnorrPublicKey], - allowsNostr: Option[Boolean]) - extends LnURLResponse { + allowsNostr: Option[Boolean] + ) extends LnURLResponse { override val tag: LnURLTag = PayRequest lazy val metadataJs: JsValue = Json.parse(metadata) @@ -66,15 +67,16 @@ object LnURLJsonModels { case class LnURLPayInvoice( pr: LnInvoice, - successAction: Option[LnURLSuccessAction]) - extends LnURLJsonModel + successAction: Option[LnURLSuccessAction] + ) extends LnURLJsonModel implicit val LnURLPayInvoiceReads: Reads[LnURLPayInvoice] = Json.reads[LnURLPayInvoice] implicit val LnURLPayInvoiceWrites: OWrites[LnURLPayInvoice] = { o => Json.writes[LnURLPayInvoice].writes(o) ++ Json.obj( - "routes" -> JsArray.empty) + "routes" -> JsArray.empty + ) } case class LnURLWithdrawResponse( @@ -93,7 +95,8 @@ object LnURLJsonModels { implicit val LnURLWithdrawResponseWrites: OWrites[LnURLWithdrawResponse] = { o => Json.writes[LnURLWithdrawResponse].writes(o) ++ Json.obj( - "tag" -> "withdrawRequest") + "tag" -> "withdrawRequest" + ) } implicit val LnURLResponseReads: Reads[LnURLResponse] = { @@ -108,7 +111,8 @@ object LnURLJsonModels { tagJs.validate[LnURLTag] match { case JsError(errors) => throw new IllegalArgumentException( - s"Invalid json, got $obj, errors ${errors.mkString("\n")}") + s"Invalid json, got $obj, errors ${errors.mkString("\n")}" + ) case JsSuccess(tag, _) => tag match { case PayRequest => obj.validate[LnURLPayResponse] diff --git a/lnurl/src/main/scala/org/bitcoins/lnurl/json/LnURLTag.scala b/lnurl/src/main/scala/org/bitcoins/lnurl/json/LnURLTag.scala index 91d9018ac6..eb499f63c0 100644 --- a/lnurl/src/main/scala/org/bitcoins/lnurl/json/LnURLTag.scala +++ b/lnurl/src/main/scala/org/bitcoins/lnurl/json/LnURLTag.scala @@ -19,7 +19,8 @@ object LnURLTag extends StringFactory[LnURLTag] { override def fromString(string: String): LnURLTag = { fromStringOpt(string).getOrElse( - sys.error(s"Could not find a LnURLTag for string $string")) + sys.error(s"Could not find a LnURLTag for string $string") + ) } implicit val LnURLTagTagReads: Reads[LnURLTag] = (json: JsValue) => @@ -45,7 +46,8 @@ object SuccessActionTag extends StringFactory[SuccessActionTag] { override def fromString(string: String): SuccessActionTag = { fromStringOpt(string).getOrElse( - sys.error(s"Could not find a SuccessActionTag for string $string")) + sys.error(s"Could not find a SuccessActionTag for string $string") + ) } implicit val SuccessActionTagReads: Reads[SuccessActionTag] = diff --git a/node-test/src/test/scala/org/bitcoins/node/BroadcastTransactionTest.scala b/node-test/src/test/scala/org/bitcoins/node/BroadcastTransactionTest.scala index 7e6ec35830..258cb8642a 100644 --- a/node-test/src/test/scala/org/bitcoins/node/BroadcastTransactionTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/BroadcastTransactionTest.scala @@ -20,8 +20,10 @@ class BroadcastTransactionTest extends NodeTestWithCachedBitcoindNewest { /** Wallet config with data directory set to user temp directory */ override protected def getFreshConfig: BitcoinSAppConfig = - BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(() => pgUrl(), - Vector.empty) + BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig( + () => pgUrl(), + Vector.empty + ) override type FixtureParam = NeutrinoNodeConnectedWithBitcoind @@ -33,7 +35,8 @@ class BroadcastTransactionTest extends NodeTestWithCachedBitcoindNewest { bitcoind <- cachedBitcoindWithFundsF outcome = withNeutrinoNodeConnectedToBitcoindCached(test, bitcoind)( system, - getFreshConfig) + getFreshConfig + ) f <- outcome.toFuture } yield f new FutureOutcome(outcome) @@ -80,7 +83,8 @@ class BroadcastTransactionTest extends NodeTestWithCachedBitcoindNewest { false case other => logger.error( - s"Received unexpected error on getrawtransaction: $other") + s"Received unexpected error on getrawtransaction: $other" + ) throw other } } @@ -91,10 +95,13 @@ class BroadcastTransactionTest extends NodeTestWithCachedBitcoindNewest { txOpt <- node.txDAO.findByHash(tx.txId) _ = assert( txOpt.isDefined, - "Transaction was not added to BroadcastableTransaction database") - _ <- TestAsyncUtil.awaitConditionF(() => hasSeenTx(tx), - interval = 1.second, - maxTries = 25) + "Transaction was not added to BroadcastableTransaction database" + ) + _ <- TestAsyncUtil.awaitConditionF( + () => hasSeenTx(tx), + interval = 1.second, + maxTries = 25 + ) } yield () } @@ -112,6 +119,7 @@ class BroadcastTransactionTest extends NodeTestWithCachedBitcoindNewest { } yield assert( // pre-balance - sent amount + 1 block reward maturing +/- fees - (bitcoindBalancePreBroadcast - sendAmount + 50.bitcoins).satoshis.toLong === bitcoindBalancePostBroadcast.satoshis.toLong +- 5000) + (bitcoindBalancePreBroadcast - sendAmount + 50.bitcoins).satoshis.toLong === bitcoindBalancePostBroadcast.satoshis.toLong +- 5000 + ) } } diff --git a/node-test/src/test/scala/org/bitcoins/node/DisconnectedPeerTest.scala b/node-test/src/test/scala/org/bitcoins/node/DisconnectedPeerTest.scala index 33212c0155..88639c18e3 100644 --- a/node-test/src/test/scala/org/bitcoins/node/DisconnectedPeerTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/DisconnectedPeerTest.scala @@ -10,8 +10,10 @@ import org.scalatest.FutureOutcome class DisconnectedPeerTest extends NodeUnitTest { override protected def getFreshConfig: BitcoinSAppConfig = - BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(() => pgUrl(), - Vector.empty) + BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig( + () => pgUrl(), + Vector.empty + ) override type FixtureParam = NeutrinoNode diff --git a/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeTest.scala b/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeTest.scala index 03d99811ca..242790fa45 100644 --- a/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeTest.scala @@ -24,7 +24,8 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { override protected def getFreshConfig: BitcoinSAppConfig = { BitcoinSTestAppConfig.getMultiPeerNeutrinoWithEmbeddedDbTestConfig( () => pgUrl(), - Vector.empty) + Vector.empty + ) } override type FixtureParam = NeutrinoNodeConnectedWithBitcoinds @@ -37,7 +38,8 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { bitcoinds <- clientsF outcome = withUnsyncedNeutrinoNodeConnectedToBitcoinds( test, - bitcoinds.toVector)(system, getFreshConfig) + bitcoinds.toVector + )(system, getFreshConfig) f <- outcome.toFuture } yield f new FutureOutcome(outcomeF) @@ -74,12 +76,15 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { def peerManager = node.peerManager def peers = peerManager.peers val ourPeersF: Future[Vector[Peer]] = Future.sequence( - nodeConnectedWithBitcoind.bitcoinds.map(NodeTestUtil.getBitcoindPeer)) + nodeConnectedWithBitcoind.bitcoinds.map(NodeTestUtil.getBitcoindPeer) + ) def has2Peers: Future[Unit] = - AsyncUtil.retryUntilSatisfied(peers.size == 2, - interval = 1.second, - maxTries = 30) + AsyncUtil.retryUntilSatisfied( + peers.size == 2, + interval = 1.second, + maxTries = 30 + ) def bothOurs: Future[Assertion] = ourPeersF.map { ours => assert(ours.map(peers.contains(_)).forall(_ == true)) } @@ -106,7 +111,7 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { val peerManager = node.peerManager def peers = peerManager.peers - //is the database peer same as Peer + // is the database peer same as Peer def isSame(peerDb: PeerDb, peer: Peer): Boolean = { val dbSocket = NetworkUtil.parseInetSocketAddress(peerDb.address, peerDb.port) @@ -114,19 +119,20 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { val hostMatch: Boolean = { if (dbSocket.getHostString == peer.socket.getHostString) true else { - //checking if both are localhost - //a bit hacky way but resolution of localhost to address cannot be done so as to allow for tor - //addresses too + // checking if both are localhost + // a bit hacky way but resolution of localhost to address cannot be done so as to allow for tor + // addresses too val localhost = Vector("localhost", "127.0.0.1") localhost.contains(dbSocket.getHostString) && localhost.contains( - peer.socket.getHostString) + peer.socket.getHostString + ) } } hostMatch && dbSocket.getPort == peer.socket.getPort } - //assert connected to 2 peers and both initialised and connected + // assert connected to 2 peers and both initialised and connected val assertConnAndInit = for { _ <- Future .sequence(peers.map(peerManager.isConnected)) @@ -139,7 +145,8 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { for { _ <- assertConnAndInit ourPeers <- Future.sequence( - nodeConnectedWithBitcoind.bitcoinds.map(NodeTestUtil.getBitcoindPeer)) + nodeConnectedWithBitcoind.bitcoinds.map(NodeTestUtil.getBitcoindPeer) + ) peerDbs <- PeerDAO()(node.nodeAppConfig, executionContext).findAll() } yield { @@ -188,35 +195,35 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { val node = nodeConnectedWithBitcoind.node val bitcoind = nodeConnectedWithBitcoind.bitcoinds(0) - //we need to generate 1 block for bitcoind to consider - //itself out of IBD. bitcoind will not sendheaders - //when it believes itself, or it's peer is in IBD + // we need to generate 1 block for bitcoind to consider + // itself out of IBD. bitcoind will not sendheaders + // when it believes itself, or it's peer is in IBD val gen1F = for { _ <- NodeTestUtil.awaitSyncAndIBD(node, bitcoind) x <- bitcoind.generate(1) } yield x - //this needs to be called to get our peer to send us headers - //as they happen with the 'sendheaders' message - //both our spv node and our bitcoind node _should_ both be at the genesis block (regtest) - //at this point so no actual syncing is happening + // this needs to be called to get our peer to send us headers + // as they happen with the 'sendheaders' message + // both our spv node and our bitcoind node _should_ both be at the genesis block (regtest) + // at this point so no actual syncing is happening val initSyncF = gen1F.flatMap { _ => for { _ <- NodeTestUtil.awaitBestHash(node, bitcoind) } yield () } - //start generating a block every 10 seconds with bitcoind - //this should result in 5 blocks + // start generating a block every 10 seconds with bitcoind + // this should result in 5 blocks val startGenF: Future[Cancellable] = initSyncF.map { _ => - //generate a block every 5 seconds - //until we have generated 5 total blocks + // generate a block every 5 seconds + // until we have generated 5 total blocks genBlockInterval(bitcoind) } startGenF.flatMap { cancellable => - //we should expect 5 headers have been announced to us via - //the send headers message. + // we should expect 5 headers have been announced to us via + // the send headers message. for { _ <- NodeTestUtil.awaitSync(node, bitcoind) _ = { @@ -231,7 +238,7 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { } } - //intended for test fixtures + // intended for test fixtures it must "sync filters when multiple header messages are sent in succession" in { nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds => val node = nodeConnectedWithBitcoind.node @@ -240,10 +247,10 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { for { _ <- NodeTestUtil.awaitSyncAndIBD(node, bitcoind) _ <- PekkoUtil.nonBlockingSleep(3.seconds) - //have to generate the block headers independent of one another - //rather than just calling generateToAddress(2,junkAddress) - //because of this bitcoin core bug: https://github.com/bitcoin-s/bitcoin-s/issues/1098 - //hopefully they fix it some day... + // have to generate the block headers independent of one another + // rather than just calling generateToAddress(2,junkAddress) + // because of this bitcoin core bug: https://github.com/bitcoin-s/bitcoin-s/issues/1098 + // hopefully they fix it some day... _ <- bitcoind.generateToAddress(1, junkAddress) _ <- AsyncUtil.nonBlockingSleep(500.millis) _ <- bitcoind.generateToAddress(1, junkAddress) @@ -255,23 +262,23 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { it must "start syncing compact filter headers / compact filters when block header is seen" in { nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds => - //see: https://github.com/bitcoin-s/bitcoin-s/issues/4933 + // see: https://github.com/bitcoin-s/bitcoin-s/issues/4933 val node = nodeConnectedWithBitcoind.node val bitcoind = nodeConnectedWithBitcoind.bitcoinds(0) for { _ <- NodeTestUtil.awaitSyncAndIBD(node, bitcoind) _ <- node.stop() - //drop all compact filter headers / filters + // drop all compact filter headers / filters _ <- CompactFilterHeaderDAO()(executionContext, node.chainConfig) .deleteAll() _ <- CompactFilterDAO()(executionContext, node.chainConfig).deleteAll() _ <- bitcoind.generate(1) - //restart the node + // restart the node _ <- node.start() - //await for us to sync compact filter headers filters - //the sync process should get kicked off after we see the - //newly mined block header + // await for us to sync compact filter headers filters + // the sync process should get kicked off after we see the + // newly mined block header _ <- NodeTestUtil.awaitAllSync(node, bitcoind) } yield { succeed @@ -280,25 +287,25 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { it must "sync block headers that occurred while were syncing compact filters during IBD" in { nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds => - //see: https://github.com/bitcoin-s/bitcoin-s/issues/5017 + // see: https://github.com/bitcoin-s/bitcoin-s/issues/5017 - //problem: We are generating blocks with bitcoinds(0) - //but we are trying to sync these blocks with bitcoinds(1) - //this results in a race condition between the bitcoin-s node and bitcoinds(0) / bitcoinds(1) syncing with each other - //some cases, when we try to sync filters / filter headers from bitcoinds(1) we will get this error message saying we cannot find the block - //2023-05-01T21:46:46Z [net] Failed to find block filter hashes in index: filter_type=basic, start_height=208, stop_hash=303cc906bf99b5370581e7f23285378c18005745882c6112dbbf3e61a82aeddb + // problem: We are generating blocks with bitcoinds(0) + // but we are trying to sync these blocks with bitcoinds(1) + // this results in a race condition between the bitcoin-s node and bitcoinds(0) / bitcoinds(1) syncing with each other + // some cases, when we try to sync filters / filter headers from bitcoinds(1) we will get this error message saying we cannot find the block + // 2023-05-01T21:46:46Z [net] Failed to find block filter hashes in index: filter_type=basic, start_height=208, stop_hash=303cc906bf99b5370581e7f23285378c18005745882c6112dbbf3e61a82aeddb val node = nodeConnectedWithBitcoind.node val bitcoind = nodeConnectedWithBitcoind.bitcoinds(0) val bitcoind1 = nodeConnectedWithBitcoind.bitcoinds(1) - //start syncing node + // start syncing node val numBlocks = 5 val genBlocksF = { for { peer1 <- NodeTestUtil.getBitcoindPeer(bitcoind1) _ <- node.peerManager.disconnectPeer(peer1) _ <- NodeTestUtil.awaitConnectionCount(node, 1) - //generate blocks while sync is ongoing + // generate blocks while sync is ongoing _ <- bitcoind.generate(numBlocks) } yield { () @@ -307,9 +314,9 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { for { _ <- genBlocksF - //wait for sync to complete + // wait for sync to complete _ <- NodeTestUtil.awaitAllSync(node, bitcoind) - //generate another block and make sure it syncs it + // generate another block and make sure it syncs it _ <- bitcoind.generate(1) _ <- NodeTestUtil.awaitAllSync(node, bitcoind) } yield { @@ -330,14 +337,15 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { _ <- node.peerManager.disconnectPeer(peer0) _ <- AsyncUtil.retryUntilSatisfiedF( () => node.peerManager.isDisconnected(peer0), - 1.second) + 1.second + ) _ <- NodeTestUtil.awaitConnectionCount(node, 1) } yield succeed } it must "start syncing compact filters on startup when block headers / filter headers are synced" in { nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds => - //https://github.com/bitcoin-s/bitcoin-s/issues/5221 + // https://github.com/bitcoin-s/bitcoin-s/issues/5221 val node = nodeConnectedWithBitcoind.node val bitcoinds = nodeConnectedWithBitcoind.bitcoinds val bitcoind0 = bitcoinds(0) @@ -368,39 +376,42 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { it must "handle reorgs correctly" in { nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds => - //https://github.com/bitcoin-s/bitcoin-s/issues/5017 + // https://github.com/bitcoin-s/bitcoin-s/issues/5017 val node = nodeConnectedWithBitcoind.node val bitcoinds = nodeConnectedWithBitcoind.bitcoinds val bitcoind0 = bitcoinds(0) val bitcoind1 = bitcoinds(1) for { _ <- NodeTestUtil.awaitSyncAndIBD(node, bitcoind0) - //disconnect bitcoind1 as we don't need it + // disconnect bitcoind1 as we don't need it peer1 <- NodeTestUtil.getBitcoindPeer(bitcoind1) _ <- node.peerManager.disconnectPeer(peer1) bestBlockHash0 <- bitcoind0.getBestBlockHash() - //invalidate blockhash to force a reorg when next block is generated + // invalidate blockhash to force a reorg when next block is generated _ <- bitcoind0.invalidateBlock(bestBlockHash0) _ <- NodeTestUtil.awaitConnectionCount(node, 1) - //now generate a block, make sure we sync with them + // now generate a block, make sure we sync with them hashes0 <- bitcoind0.generate(1) chainApi <- node.chainApiFromDb() _ <- AsyncUtil.retryUntilSatisfiedF(() => chainApi.getHeader(hashes0.head).map(_.isDefined)) - //generate another block to make sure the reorg is complete + // generate another block to make sure the reorg is complete hashes1 <- bitcoind0.generate(1) - _ <- NodeTestUtil.awaitAllSync(node = node, - bitcoind = bitcoind0, - bestBlockHashBE = Some(hashes1.head)) + _ <- NodeTestUtil.awaitAllSync( + node = node, + bitcoind = bitcoind0, + bestBlockHashBE = Some(hashes1.head) + ) } yield succeed } it must "honor bitcoin-s.node.maxConnectedPeers" in { nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds => val max = 1 - val nodeF = getCustomMaxConnectedPeers(initNode = - nodeConnectedWithBitcoind.node, - maxConnectedPeers = max) + val nodeF = getCustomMaxConnectedPeers( + initNode = nodeConnectedWithBitcoind.node, + maxConnectedPeers = max + ) for { node <- nodeF @@ -415,12 +426,15 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair { private def getCustomMaxConnectedPeers( initNode: NeutrinoNode, - maxConnectedPeers: Int): Future[NeutrinoNode] = { + maxConnectedPeers: Int + ): Future[NeutrinoNode] = { - require(initNode.nodeConfig.maxConnectedPeers != maxConnectedPeers, - s"maxConnectedPeers must be different") - //make a custom config, set the inactivity timeout very low - //so we will disconnect our peer organically + require( + initNode.nodeConfig.maxConnectedPeers != maxConnectedPeers, + s"maxConnectedPeers must be different" + ) + // make a custom config, set the inactivity timeout very low + // so we will disconnect our peer organically val str = s""" |bitcoin-s.node.maxConnectedPeers = $maxConnectedPeers diff --git a/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeWithUncachedBitcoindTest.scala b/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeWithUncachedBitcoindTest.scala index 1bf2197551..f82b25485b 100644 --- a/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeWithUncachedBitcoindTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeWithUncachedBitcoindTest.scala @@ -33,12 +33,14 @@ class NeutrinoNodeWithUncachedBitcoindTest extends NodeUnitTest with CachedTor { } lazy val invalidHeader = BlockHeader.fromHex( - s"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f2003000000") + s"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff7f2003000000" + ) override protected def getFreshConfig: BitcoinSAppConfig = { BitcoinSTestAppConfig.getMultiPeerNeutrinoWithEmbeddedDbTestConfig( () => pgUrl(), - Vector.empty) + Vector.empty + ) } override type FixtureParam = NeutrinoNodeNotConnectedWithBitcoinds @@ -51,7 +53,8 @@ class NeutrinoNodeWithUncachedBitcoindTest extends NodeUnitTest with CachedTor { bitcoinds <- bitcoindsF outcome = withUnstartedNeutrinoNodeBitcoinds(test, bitcoinds)( system, - getFreshConfig) + getFreshConfig + ) f <- outcome.toFuture } yield f new FutureOutcome(outcomeF) @@ -68,13 +71,14 @@ class NeutrinoNodeWithUncachedBitcoindTest extends NodeUnitTest with CachedTor { bitcoindPeers <- bitcoinPeersF _ <- node.start() _ <- NodeTestUtil.awaitConnectionCount(node, bitcoinds.size) - //sync from first bitcoind + // sync from first bitcoind peer0 = bitcoindPeers(0) _ <- node.peerManager.disconnectPeer(peer0) _ = logger.debug( s"Disconnected $peer0 from node bitcoind(0).p2pPort=${peer0.socket.getPort} bitcoind(1).p2pPort=${bitcoinds( - 1).instance.p2pPort}") - //old peer we were syncing with that just disconnected us + 1).instance.p2pPort}" + ) + // old peer we were syncing with that just disconnected us _ <- NodeTestUtil.awaitAllSync(node, bitcoinds(1)) } yield { succeed @@ -92,14 +96,14 @@ class NeutrinoNodeWithUncachedBitcoindTest extends NodeUnitTest with CachedTor { _ <- bitcoinds(1).generateToAddress(1, junkAddress) h1 <- bitcoinds(0).getBestHashBlockHeight() h2 <- bitcoinds(1).getBestHashBlockHeight() - //out of sync by 1 block, h2 ahead + // out of sync by 1 block, h2 ahead _ = assert(h2 - h1 == 1) _ <- NodeTestUtil.awaitBestHash(node, bitcoinds(1)) } yield { succeed } } - //note: now bitcoinds(1) is ahead by 1 block compared to bitcoinds(0) + // note: now bitcoinds(1) is ahead by 1 block compared to bitcoinds(0) it must "re-query in case invalid headers are sent" in { nodeConnectedWithBitcoinds => @@ -107,14 +111,15 @@ class NeutrinoNodeWithUncachedBitcoindTest extends NodeUnitTest with CachedTor { val bitcoinds = nodeConnectedWithBitcoinds.bitcoinds for { _ <- node.start() - _ <- NodeTestUtil.awaitConnectionCount(node = node, - expectedConnectionCount = - bitcoinds.size) + _ <- NodeTestUtil.awaitConnectionCount( + node = node, + expectedConnectionCount = bitcoinds.size + ) peers <- bitcoinPeersF peer = peers.head _ <- NodeTestUtil.awaitAllSync(node, bitcoinds(1)) // generating 6 blocks will cause bitcoind(1) NOT to gossip them on the p2p network - //this means we can test our re-query logic by sending an invalid header from bitcoinds(0) + // this means we can test our re-query logic by sending an invalid header from bitcoinds(0) _ <- bitcoinds(1).generate(6) _ <- AsyncUtil.nonBlockingSleep(2.second) invalidHeaderMessage = HeadersMessage(headers = Vector(invalidHeader)) @@ -144,7 +149,7 @@ class NeutrinoNodeWithUncachedBitcoindTest extends NodeUnitTest with CachedTor { NodeStreamMessage.DataMessageWrapper(invalidHeaderMessage, peer) node .offer(msg) - //add a delay to not overwhelm queue so other messages can be processed + // add a delay to not overwhelm queue so other messages can be processed .flatMap(_ => AsyncUtil.nonBlockingSleep(100.millis)) } } @@ -154,9 +159,10 @@ class NeutrinoNodeWithUncachedBitcoindTest extends NodeUnitTest with CachedTor { for { _ <- node.start() - _ <- NodeTestUtil.awaitConnectionCount(node = node, - expectedConnectionCount = - bitcoinds.size) + _ <- NodeTestUtil.awaitConnectionCount( + node = node, + expectedConnectionCount = bitcoinds.size + ) peers <- bitcoinPeersF peer = peers(1) _ <- node.peerManager.isConnected(peer).map(assert(_)) @@ -164,14 +170,15 @@ class NeutrinoNodeWithUncachedBitcoindTest extends NodeUnitTest with CachedTor { bitcoind0 = bitcoinds(0) bitcoind1 = bitcoinds(1) _ <- NodeTestUtil.awaitAllSync(node, bitcoind1) - //disconnect bitcoind(0) as its not needed for this test + // disconnect bitcoind(0) as its not needed for this test peer0 <- NodeTestUtil.getBitcoindPeer(bitcoind0) _ <- node.peerManager.disconnectPeer(peer0) _ <- AsyncUtil.retryUntilSatisfied(peerManager.peers.size == 1) _ <- NodeTestUtil.awaitAllSync(node, bitcoind1) _ <- sendInvalidHeaders(peer) _ <- AsyncUtil.retryUntilSatisfied( - !node.peerManager.peers.contains(peer)) + !node.peerManager.peers.contains(peer) + ) } yield { succeed } diff --git a/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeWithWalletTest.scala b/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeWithWalletTest.scala index 56ee07be75..9ae0e29646 100644 --- a/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeWithWalletTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/NeutrinoNodeWithWalletTest.scala @@ -26,8 +26,10 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { /** Wallet config with data directory set to user temp directory */ override protected def getFreshConfig: BitcoinSAppConfig = - BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(() => pgUrl(), - Vector.empty) + BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig( + () => pgUrl(), + Vector.empty + ) override type FixtureParam = NeutrinoNodeFundedWalletBitcoind @@ -53,7 +55,8 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { def condition( expectedBalance: CurrencyUnit, expectedUtxos: Int, - expectedAddresses: Int): Future[Boolean] = { + expectedAddresses: Int + ): Future[Boolean] = { for { balance <- wallet.getBalance() addresses <- wallet.listAddresses() @@ -66,11 +69,11 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { } } - //default wallet utxos are 3BTC, 2BTC, 1BTC - //our coin selection algorithm seems to be selecting - //the 3BTC utxo to spend, so we should have - //confirmed = 2BTC + 1BTC - //unconfirmed = 3 BTC - TestAmount - TestFees + // default wallet utxos are 3BTC, 2BTC, 1BTC + // our coin selection algorithm seems to be selecting + // the 3BTC utxo to spend, so we should have + // confirmed = 2BTC + 1BTC + // unconfirmed = 3 BTC - TestAmount - TestFees val condition1 = () => { condition( expectedBalance = 6.bitcoin - TestAmount - TestFees, @@ -79,10 +82,10 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { ) } - //this is just sending TestAmount back to us - //so everything should stay the same as above - //expected we should have received TestAmount back - //and have 1 more address/utxo + // this is just sending TestAmount back to us + // so everything should stay the same as above + // expected we should have received TestAmount back + // and have 1 more address/utxo val condition2 = { () => condition( expectedBalance = (6.bitcoin - TestAmount - TestFees) + TestAmount, @@ -103,7 +106,7 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { bitcoind.getNewAddress .flatMap(bitcoind.generateToAddress(1, _)) _ <- NodeTestUtil.awaitSync(node, bitcoind) - _ <- AsyncUtil.awaitConditionF(condition1, maxTries = 100) //10 seconds + _ <- AsyncUtil.awaitConditionF(condition1, maxTries = 100) // 10 seconds // receive address <- wallet.getNewAddress() txId <- bitcoind.sendToAddress(address, TestAmount) @@ -113,9 +116,11 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { bitcoind.getNewAddress .flatMap(bitcoind.generateToAddress(1, _)) _ <- NodeTestUtil.awaitSync(node, bitcoind) - _ <- TestAsyncUtil.awaitConditionF(condition2, - interval = 1.second, - maxTries = 30) + _ <- TestAsyncUtil.awaitConditionF( + condition2, + interval = 1.second, + maxTries = 30 + ) // assert we got the full tx with witness data txs <- wallet.listTransactions() } yield assert(txs.exists(_.transaction == expectedTx)) @@ -211,9 +216,11 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { _ = assert(!rescan) rescanState <- wallet.fullRescanNeutrinoWallet(addressBatchSize = 7) - _ <- AsyncUtil.awaitConditionF(() => condition(), - maxTries = 200, - interval = 200.millis) + _ <- AsyncUtil.awaitConditionF( + () => condition(), + maxTries = 200, + interval = 200.millis + ) _ <- rescanState.asInstanceOf[RescanStarted].stop() } yield succeed } @@ -226,7 +233,7 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { val receivedAddrF = wallet.getNewAddress() val bitcoindAddrF = bitcoind.getNewAddress val sendAmt = Bitcoins.one - //stop the node to take us offline + // stop the node to take us offline val stopF = { for { _ <- NodeTestUtil.awaitAllSync(node, bitcoind) @@ -238,11 +245,11 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { receiveAddr <- receivedAddrF bitcoindAddr <- bitcoindAddrF stoppedNode <- stopF - //send money and generate a block to confirm the funds while we are offline + // send money and generate a block to confirm the funds while we are offline _ <- bitcoind.sendToAddress(receiveAddr, sendAmt) - //generate a block to confirm the tx + // generate a block to confirm the tx _ <- bitcoind.generateToAddress(1, bitcoindAddr) - //restart the node now that we have received funds + // restart the node now that we have received funds startedNode <- stoppedNode.start() _ <- NodeTestUtil.awaitSync(node = startedNode, rpc = bitcoind) _ <- AsyncUtil.retryUntilSatisfiedF(() => { @@ -259,28 +266,28 @@ class NeutrinoNodeWithWalletTest extends NodeTestWithCachedBitcoindNewest { } it must "recognize funds were spent while we were offline" in { param => - //useful test for the case where we are in a DLC - //and the counterparty broadcasts the funding tx or a CET + // useful test for the case where we are in a DLC + // and the counterparty broadcasts the funding tx or a CET val NeutrinoNodeFundedWalletBitcoind(node, wallet, bitcoind) = param val initBalanceF = wallet.getBalance() val bitcoindAddrF = bitcoind.getNewAddress val sendAmt = Bitcoins.one - //stop the node to take us offline + // stop the node to take us offline val stopF = node.stop() for { initBalance <- initBalanceF bitcoindAddr <- bitcoindAddrF stoppedNode <- stopF - //create a transaction that spends to bitcoind with our wallet + // create a transaction that spends to bitcoind with our wallet tx <- wallet.sendToAddress(bitcoindAddr, sendAmt, SatoshisPerByte.one) - //broadcast tx + // broadcast tx _ <- bitcoind.sendRawTransaction(tx) _ <- bitcoind.generateToAddress(1, bitcoindAddr) _ <- PekkoUtil.nonBlockingSleep(3.seconds) - //bring node back online + // bring node back online startedNode <- stoppedNode.start() _ <- NodeTestUtil.awaitSync(startedNode, bitcoind) balanceAfterSpend <- wallet.getBalance() diff --git a/node-test/src/test/scala/org/bitcoins/node/PeerManagerTest.scala b/node-test/src/test/scala/org/bitcoins/node/PeerManagerTest.scala index 4f57db9c01..cef846eebc 100644 --- a/node-test/src/test/scala/org/bitcoins/node/PeerManagerTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/PeerManagerTest.scala @@ -20,7 +20,8 @@ class PeerManagerTest extends NodeTestWithCachedBitcoindNewest { override protected def getFreshConfig: BitcoinSAppConfig = { BitcoinSTestAppConfig.getMultiPeerNeutrinoWithEmbeddedDbTestConfig( () => pgUrl(), - Vector.empty) + Vector.empty + ) } override type FixtureParam = NeutrinoNodeConnectedWithBitcoind @@ -31,8 +32,10 @@ class PeerManagerTest extends NodeTestWithCachedBitcoindNewest { val outcomeF: Future[Outcome] = for { _ <- torClientF bitcoind <- cachedBitcoindWithFundsF - outcome = withNeutrinoNodeUnstarted(test, bitcoind)(system, - getFreshConfig) + outcome = withNeutrinoNodeUnstarted(test, bitcoind)( + system, + getFreshConfig + ) f <- outcome.toFuture } yield f new FutureOutcome(outcomeF) @@ -48,13 +51,15 @@ class PeerManagerTest extends NodeTestWithCachedBitcoindNewest { _ <- node.start() peer <- peerF peerManager = node.peerManager - _ <- NodeTestUtil.awaitConnectionCount(node = node, - expectedConnectionCount = 1) + _ <- NodeTestUtil.awaitConnectionCount( + node = node, + expectedConnectionCount = 1 + ) } yield { assert(peerManager.peers.exists(_ == peer)) assert( peerManager.paramPeers.nonEmpty - ) //make sure we had a peer passed as a param + ) // make sure we had a peer passed as a param } } @@ -70,7 +75,7 @@ class PeerManagerTest extends NodeTestWithCachedBitcoindNewest { peerManager = node.peerManager _ <- NodeTestUtil.awaitSyncAndIBD(node = node, bitcoind = bitcoind) - //disconnect + // disconnect _ <- NodeTestUtil.disconnectNode(bitcoind, node) _ <- node.peerManager.connectPeer(peer) _ <- NodeTestUtil.awaitConnectionCount(node, 1) @@ -89,7 +94,7 @@ class PeerManagerTest extends NodeTestWithCachedBitcoindNewest { _ <- node.start() peer <- peerF _ <- NodeTestUtil.awaitSyncAndIBD(node = node, bitcoind = bitcoind) - //disconnect + // disconnect timestamp = Instant.now() _ <- NodeTestUtil.disconnectNode(bitcoind, node) addrBytes = PeerDAOHelper.getAddrBytes(peer) diff --git a/node-test/src/test/scala/org/bitcoins/node/networking/ReConnectionTest.scala b/node-test/src/test/scala/org/bitcoins/node/networking/ReConnectionTest.scala index 11fd1d4759..0d772f0699 100644 --- a/node-test/src/test/scala/org/bitcoins/node/networking/ReConnectionTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/networking/ReConnectionTest.scala @@ -18,8 +18,10 @@ import scala.concurrent.duration.{DurationInt, FiniteDuration} class ReConnectionTest extends NodeTestWithCachedBitcoindNewest { override protected def getFreshConfig: BitcoinSAppConfig = - BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(() => pgUrl(), - Vector.empty) + BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig( + () => pgUrl(), + Vector.empty + ) override type FixtureParam = NeutrinoNodeConnectedWithBitcoind @@ -28,7 +30,8 @@ class ReConnectionTest extends NodeTestWithCachedBitcoindNewest { bitcoind <- cachedBitcoindWithFundsF outcome <- withNeutrinoNodeUnstarted(test, bitcoind)( system, - getFreshConfig).toFuture + getFreshConfig + ).toFuture } yield outcome new FutureOutcome(f) @@ -44,14 +47,18 @@ class ReConnectionTest extends NodeTestWithCachedBitcoindNewest { getSmallHealthCheckNeutrinoNode(nodeConnectedWithBitcoind.node, timeout) for { started <- startedF - _ <- NodeTestUtil.awaitConnectionCount(node = started, - expectedConnectionCount = 1) - //let sync occur so we aren't receiving blockchain data over the network + _ <- NodeTestUtil.awaitConnectionCount( + node = started, + expectedConnectionCount = 1 + ) + // let sync occur so we aren't receiving blockchain data over the network _ <- NodeTestUtil.awaitAllSync(started, bitcoind) - //wait until there is a timeout for inactivity + // wait until there is a timeout for inactivity _ <- AsyncUtil.nonBlockingSleep(timeout) - _ <- NodeTestUtil.awaitConnectionCount(node = started, - expectedConnectionCount = 0) + _ <- NodeTestUtil.awaitConnectionCount( + node = started, + expectedConnectionCount = 0 + ) _ <- started.stop() _ <- started.nodeConfig.stop() } yield { @@ -61,7 +68,7 @@ class ReConnectionTest extends NodeTestWithCachedBitcoindNewest { it must "reconnect a peer when inactivity checks run and we have 0 peers" in { nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoind => - //see: https://github.com/bitcoin-s/bitcoin-s/issues/5162 + // see: https://github.com/bitcoin-s/bitcoin-s/issues/5162 val bitcoind = nodeConnectedWithBitcoind.bitcoind val timeout = 5.second val startedF = @@ -69,13 +76,13 @@ class ReConnectionTest extends NodeTestWithCachedBitcoindNewest { for { started <- startedF _ <- NodeTestUtil.awaitConnectionCount(started, 1) - //explicitly disconnect it + // explicitly disconnect it bitcoindPeer <- NodeTestUtil.getBitcoindPeer(bitcoind) _ <- started.peerManager.disconnectPeer(bitcoindPeer) - //wait until we have zero connections + // wait until we have zero connections _ <- NodeTestUtil.awaitConnectionCount(started, 0) - //wait until there is a timeout for inactivity + // wait until there is a timeout for inactivity _ <- NodeTestUtil.awaitConnectionCount(started, 1) _ <- started.peerManager.isConnected(bitcoindPeer) _ <- started.stop() @@ -87,10 +94,11 @@ class ReConnectionTest extends NodeTestWithCachedBitcoindNewest { private def getSmallHealthCheckNeutrinoNode( initNode: NeutrinoNode, - timeout: FiniteDuration): Future[NeutrinoNode] = { + timeout: FiniteDuration + ): Future[NeutrinoNode] = { - //make a custom config, set the inactivity timeout very low - //so we will disconnect our peer organically + // make a custom config, set the inactivity timeout very low + // so we will disconnect our peer organically val str = s""" |bitcoin-s.node.health-check-interval = ${timeout.toString()} diff --git a/node-test/src/test/scala/org/bitcoins/node/networking/peer/DataMessageHandlerTest.scala b/node-test/src/test/scala/org/bitcoins/node/networking/peer/DataMessageHandlerTest.scala index 21185871ae..400d02cd99 100644 --- a/node-test/src/test/scala/org/bitcoins/node/networking/peer/DataMessageHandlerTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/networking/peer/DataMessageHandlerTest.scala @@ -29,8 +29,10 @@ class DataMessageHandlerTest extends NodeTestWithCachedBitcoindNewest { /** Wallet config with data directory set to user temp directory */ override protected def getFreshConfig: BitcoinSAppConfig = - BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(() => pgUrl(), - Vector.empty) + BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig( + () => pgUrl(), + Vector.empty + ) override type FixtureParam = NeutrinoNodeConnectedWithBitcoind @@ -39,7 +41,8 @@ class DataMessageHandlerTest extends NodeTestWithCachedBitcoindNewest { bitcoind <- cachedBitcoindWithFundsF outcome = withNeutrinoNodeConnectedToBitcoindCached(test, bitcoind)( system, - getFreshConfig) + getFreshConfig + ) f <- outcome.toFuture } yield f new FutureOutcome(outcome) @@ -55,12 +58,11 @@ class DataMessageHandlerTest extends NodeTestWithCachedBitcoindNewest { peer = node.peerManager.peers.head chainApi <- node.chainApiFromDb() _ = require(peerManager.getPeerData(peer).isDefined) - peerFinder = PeerFinder(peerManagerApi = peerManager, - paramPeers = Vector.empty, - queue = node)(system.dispatcher, - system, - node.nodeConfig, - node.chainConfig) + peerFinder = PeerFinder( + peerManagerApi = peerManager, + paramPeers = Vector.empty, + queue = node + )(system.dispatcher, system, node.nodeConfig, node.chainConfig) dataMessageHandler = DataMessageHandler( chainApi = chainApi, walletCreationTimeOpt = None, @@ -80,7 +82,8 @@ class DataMessageHandlerTest extends NodeTestWithCachedBitcoindNewest { // Validate that it causes a failure _ <- recoverToSucceededIf[RuntimeException]( - chainApi.processHeaders(invalidPayload.headers)) + chainApi.processHeaders(invalidPayload.headers) + ) // Verify we handle the payload correctly peerData = peerManager.getPeerData(peer).get _ <- dataMessageHandler.handleDataPayload(invalidPayload, peerData) @@ -193,23 +196,26 @@ class DataMessageHandlerTest extends NodeTestWithCachedBitcoindNewest { val initNode = param.node val bitcoind = param.bitcoind val queryWaitTime = 5.second - val nodeF = getCustomQueryWaitTime(initNode = initNode, - queryWaitTime = queryWaitTime) + val nodeF = getCustomQueryWaitTime( + initNode = initNode, + queryWaitTime = queryWaitTime + ) for { node <- nodeF peerManager = node.peerManager _ <- bitcoind.generate(1) _ <- NodeTestUtil.awaitAllSync(node, bitcoind) peer = peerManager.peers.head - chainApi = ChainHandler.fromDatabase()(executionContext, - node.chainConfig) + chainApi = ChainHandler.fromDatabase()( + executionContext, + node.chainConfig + ) _ = require(peerManager.getPeerData(peer).isDefined) - peerFinder = PeerFinder(peerManagerApi = peerManager, - paramPeers = Vector.empty, - queue = node)(system.dispatcher, - system, - node.nodeConfig, - node.chainConfig) + peerFinder = PeerFinder( + peerManagerApi = peerManager, + paramPeers = Vector.empty, + queue = node + )(system.dispatcher, system, node.nodeConfig, node.chainConfig) dataMessageHandler = DataMessageHandler( chainApi = chainApi, walletCreationTimeOpt = None, @@ -223,11 +229,11 @@ class DataMessageHandlerTest extends NodeTestWithCachedBitcoindNewest { ) )(node.executionContext, node.nodeAppConfig, node.chainConfig) - //disconnect our node from bitcoind, then - //use bitcoind to generate 2 blocks, and then try to send the headers - //via directly via our queue. We should still be able to process - //the second header even though our NodeState is FilterHeaderSync - //this is because the getcfheaders timed out + // disconnect our node from bitcoind, then + // use bitcoind to generate 2 blocks, and then try to send the headers + // via directly via our queue. We should still be able to process + // the second header even though our NodeState is FilterHeaderSync + // this is because the getcfheaders timed out peerData = peerManager.getPeerData(peer).get _ <- NodeTestUtil.disconnectNode(bitcoind, node) initBlockCount <- chainApi.getBlockCount() @@ -240,28 +246,31 @@ class DataMessageHandlerTest extends NodeTestWithCachedBitcoindNewest { newDmh0 <- dataMessageHandler.handleDataPayload(payload0, peerData) _ = assert(newDmh0.state.isInstanceOf[FilterHeaderSync]) _ <- AsyncUtil.nonBlockingSleep(queryWaitTime) - //now process another header, even though we are in FilterHeaderSync - //state, we should process the block header since our query timed out + // now process another header, even though we are in FilterHeaderSync + // state, we should process the block header since our query timed out newDmh1 <- newDmh0.handleDataPayload(payload1, peerData) blockCount <- chainApi.getBlockCount() _ <- node.stop() _ <- node.nodeConfig.stop() } yield { - //we should have processed both headers + // we should have processed both headers assert(blockCount == initBlockCount + 2) - //should still be FilterHeaderSync state + // should still be FilterHeaderSync state assert(newDmh1.state.isInstanceOf[FilterHeaderSync]) } } private def getCustomQueryWaitTime( initNode: NeutrinoNode, - queryWaitTime: FiniteDuration): Future[NeutrinoNode] = { + queryWaitTime: FiniteDuration + ): Future[NeutrinoNode] = { - require(initNode.nodeConfig.queryWaitTime != queryWaitTime, - s"maxConnectedPeers must be different") - //make a custom config, set the inactivity timeout very low - //so we will disconnect our peer organically + require( + initNode.nodeConfig.queryWaitTime != queryWaitTime, + s"maxConnectedPeers must be different" + ) + // make a custom config, set the inactivity timeout very low + // so we will disconnect our peer organically val str = s""" |bitcoin-s.node.query-wait-time = $queryWaitTime diff --git a/node/src/main/scala/org/bitcoins/node/NeutrinoNode.scala b/node/src/main/scala/org/bitcoins/node/NeutrinoNode.scala index b32f371ac2..74e84d4607 100644 --- a/node/src/main/scala/org/bitcoins/node/NeutrinoNode.scala +++ b/node/src/main/scala/org/bitcoins/node/NeutrinoNode.scala @@ -33,12 +33,13 @@ case class NeutrinoNode( nodeConfig: NodeAppConfig, chainConfig: ChainAppConfig, actorSystem: ActorSystem, - paramPeers: Vector[Peer]) - extends Node + paramPeers: Vector[Peer] +) extends Node with SourceQueue[NodeStreamMessage] { require( nodeConfig.nodeType == NodeType.NeutrinoNode, - s"We need our Neutrino mode enabled to be able to construct a Neutrino node, got=${nodeConfig.nodeType}!") + s"We need our Neutrino mode enabled to be able to construct a Neutrino node, got=${nodeConfig.nodeType}!" + ) private val isStarted: AtomicBoolean = new AtomicBoolean(false) implicit override def system: ActorSystem = actorSystem @@ -49,22 +50,26 @@ case class NeutrinoNode( private val dataMessageStreamSource: Source[ NodeStreamMessage, - SourceQueueWithComplete[NodeStreamMessage]] = { + SourceQueueWithComplete[NodeStreamMessage] + ] = { Source .queue[NodeStreamMessage]( 100 * nodeAppConfig.maxConnectedPeers, overflowStrategy = OverflowStrategy.backpressure, - maxConcurrentOffers = Runtime.getRuntime.availableProcessors()) + maxConcurrentOffers = Runtime.getRuntime.availableProcessors() + ) } override lazy val peerManager: PeerManager = { - PeerManager(paramPeers = paramPeers, - walletCreationTimeOpt = walletCreationTimeOpt, - queue = this) + PeerManager( + paramPeers = paramPeers, + walletCreationTimeOpt = walletCreationTimeOpt, + queue = this + ) } - private[this] var queueOpt: Option[ - SourceQueueWithComplete[NodeStreamMessage]] = + private[this] var queueOpt + : Option[SourceQueueWithComplete[NodeStreamMessage]] = None private[this] var streamDoneFOpt: Option[Future[NodeState]] = None @@ -76,8 +81,8 @@ case class NeutrinoNode( private def buildDataMessageStreamGraph( initState: NodeState, - source: Source[NodeStreamMessage, NotUsed]): RunnableGraph[ - Future[NodeState]] = { + source: Source[NodeStreamMessage, NotUsed] + ): RunnableGraph[Future[NodeState]] = { val graph = source .toMat(peerManager.buildP2PMessageHandlerSink(initState))(Keep.right) .withAttributes(ActorAttributes.supervisionStrategy(decider)) @@ -95,13 +100,17 @@ case class NeutrinoNode( queueOpt = Some(queue) val peerFinder: PeerFinder = - PeerFinder(peerManagerApi = peerManager, - paramPeers = paramPeers, - queue = queue) + PeerFinder( + peerManagerApi = peerManager, + paramPeers = paramPeers, + queue = queue + ) val initState = - DoneSyncing(peerWithServicesDataMap = Map.empty, - waitingForDisconnection = Set.empty, - peerFinder) + DoneSyncing( + peerWithServicesDataMap = Map.empty, + waitingForDisconnection = Set.empty, + peerFinder + ) val graph = buildDataMessageStreamGraph(initState = initState, source = source) @@ -145,14 +154,15 @@ case class NeutrinoNode( finishedF } _ = { - //reset all variables + // reset all variables streamDoneFOpt = None inactivityCancellableOpt = None queueOpt = None } } yield { logger.info( - s"Node stopped! It took=${System.currentTimeMillis() - start}ms") + s"Node stopped! It took=${System.currentTimeMillis() - start}ms" + ) this } } else { @@ -162,17 +172,16 @@ case class NeutrinoNode( } - /** Starts to sync our node with our peer - * If our local best block hash is the same as our peers - * we will not sync, otherwise we will keep syncing - * until our best block hashes match up + /** Starts to sync our node with our peer If our local best block hash is the + * same as our peers we will not sync, otherwise we will keep syncing until + * our best block hashes match up * * @return */ override def sync(): Future[Unit] = { - //wait for a peer to be available to sync from... - //due to underlying mutability in PeerManager/PeerFinder - //we may not have a peer available for selection immediately + // wait for a peer to be available to sync from... + // due to underlying mutability in PeerManager/PeerFinder + // we may not have a peer available for selection immediately val peerAvailableF = AsyncUtil.retryUntilSatisfiedF(() => getConnectionCount.map(_ > 0)) for { @@ -191,7 +200,8 @@ case class NeutrinoNode( override def getFiltersBetweenHeights( startHeight: Int, - endHeight: Int): Future[Vector[FilterResponse]] = + endHeight: Int + ): Future[Vector[FilterResponse]] = chainApiFromDb().flatMap(_.getFiltersBetweenHeights(startHeight, endHeight)) private[this] val INACTIVITY_CHECK_TIMEOUT = 60.seconds @@ -225,15 +235,19 @@ case class NeutrinoNode( val interval = nodeAppConfig.healthCheckInterval system.scheduler.scheduleAtFixedRate( initialDelay = interval, - interval = interval)(healthChecksRunnable()) + interval = interval + )(healthChecksRunnable()) } override def offer(elem: NodeStreamMessage): Future[QueueOfferResult] = { queueOpt match { case Some(queue) => queue.offer(elem) case None => - Future.failed(new RuntimeException( - s"NeutrinoNode not started, cannot process p2p message until NeutrinoNode.start() is called")) + Future.failed( + new RuntimeException( + s"NeutrinoNode not started, cannot process p2p message until NeutrinoNode.start() is called" + ) + ) } } diff --git a/node/src/main/scala/org/bitcoins/node/Node.scala b/node/src/main/scala/org/bitcoins/node/Node.scala index b2697fdf4f..d767f10ca7 100644 --- a/node/src/main/scala/org/bitcoins/node/Node.scala +++ b/node/src/main/scala/org/bitcoins/node/Node.scala @@ -21,7 +21,8 @@ import org.bitcoins.node.models._ import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success} -/** This a base trait for various kinds of nodes. It contains house keeping methods required for all nodes. +/** This a base trait for various kinds of nodes. It contains house keeping + * methods required for all nodes. */ trait Node extends NodeApi @@ -48,11 +49,14 @@ trait Node * our [[org.bitcoins.chain.blockchain.Blockchain Blockchain]] */ def chainApiFromDb()(implicit - executionContext: ExecutionContext): Future[ChainApi] = { - val c = ChainHandler.fromDatabase(BlockHeaderDAO(), - CompactFilterHeaderDAO(), - CompactFilterDAO(), - ChainStateDescriptorDAO()) + executionContext: ExecutionContext + ): Future[ChainApi] = { + val c = ChainHandler.fromDatabase( + BlockHeaderDAO(), + CompactFilterHeaderDAO(), + CompactFilterDAO(), + ChainStateDescriptorDAO() + ) Future.successful(c) } @@ -82,23 +86,26 @@ trait Node } yield { logger.info( s"Started node, best block hash ${bestHash.hex} at height $bestHeight, with $filterHeaderCount filter headers and $filterCount filters. It took=${System - .currentTimeMillis() - start}ms") + .currentTimeMillis() - start}ms" + ) node } } - /** Starts to sync our node with our peer - * If our local best block hash is the same as our peers - * we will not sync, otherwise we will keep syncing - * until our best block hashes match up + /** Starts to sync our node with our peer If our local best block hash is the + * same as our peers we will not sync, otherwise we will keep syncing until + * our best block hashes match up * - * @return the peer we are syncing with, or a failed Future if we could not find a peer to sync with after 5 seconds + * @return + * the peer we are syncing with, or a failed Future if we could not find a + * peer to sync with after 5 seconds */ def sync(): Future[Unit] /** Broadcasts the given transaction over the P2P network */ override def broadcastTransactions( - transactions: Vector[Transaction]): Future[Unit] = { + transactions: Vector[Transaction] + ): Future[Unit] = { val broadcastTxDbs = transactions.map(tx => BroadcastAbleTransaction(tx)) val addToDbF = txDAO.upsertAll(broadcastTxDbs) @@ -110,7 +117,8 @@ trait Node logger.error(s"Error when writing broadcastable TXs to DB", exception) case Success(written) => logger.debug( - s"Wrote tx=${written.map(_.transaction.txIdBE.hex)} to broadcastable table") + s"Wrote tx=${written.map(_.transaction.txIdBE.hex)} to broadcastable table" + ) } for { @@ -126,16 +134,20 @@ trait Node } else { Future.failed( new RuntimeException( - s"Error broadcasting transaction $txIds, no peers connected")) + s"Error broadcasting transaction $txIds, no peers connected" + ) + ) } } } yield () } - /** Fetches the given blocks from the peers and calls the appropriate [[callbacks]] when done. + /** Fetches the given blocks from the peers and calls the appropriate + * [[callbacks]] when done. */ override def downloadBlocks( - blockHashes: Vector[DoubleSha256DigestBE]): Future[Unit] = { + blockHashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] = { if (blockHashes.isEmpty) { Future.unit } else { @@ -155,7 +167,8 @@ trait Node /** Gets the height of the given block */ override def getBlockHeight( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = chainApiFromDb().flatMap(_.getBlockHeight(blockHash)) /** Gets the hash of the block that is what we consider "best" */ @@ -164,7 +177,8 @@ trait Node /** Gets number of confirmations for the given block hash */ def getNumberOfConfirmations( - blockHashOpt: DoubleSha256DigestBE): Future[Option[Int]] = + blockHashOpt: DoubleSha256DigestBE + ): Future[Option[Int]] = chainApiFromDb().flatMap(_.getNumberOfConfirmations(blockHashOpt)) override def epochSecondToBlockHeight(time: Long): Future[Int] = diff --git a/node/src/main/scala/org/bitcoins/node/NodeCallbacks.scala b/node/src/main/scala/org/bitcoins/node/NodeCallbacks.scala index ea3d99276a..3a0b938995 100644 --- a/node/src/main/scala/org/bitcoins/node/NodeCallbacks.scala +++ b/node/src/main/scala/org/bitcoins/node/NodeCallbacks.scala @@ -12,15 +12,16 @@ import org.bitcoins.node.callback.NodeCallbackStreamManager import scala.concurrent.{ExecutionContext, Future} -/** Callbacks for responding to events in the node. - * The appropriate callback is executed whenever the node receives - * a `getdata` message matching it. +/** Callbacks for responding to events in the node. The appropriate callback is + * executed whenever the node receives a `getdata` message matching it. */ trait NodeCallbacks extends ModuleCallbacks[NodeCallbacks] with BitcoinSLogger { - def onCompactFiltersReceived: CallbackHandler[ - Vector[(DoubleSha256DigestBE, GolombFilter)], - OnCompactFiltersReceived] + def onCompactFiltersReceived + : CallbackHandler[Vector[ + (DoubleSha256DigestBE, GolombFilter) + ], + OnCompactFiltersReceived] def onTxReceived: CallbackHandler[Transaction, OnTxReceived] @@ -28,61 +29,75 @@ trait NodeCallbacks extends ModuleCallbacks[NodeCallbacks] with BitcoinSLogger { def onMerkleBlockReceived: CallbackHandler[ (MerkleBlock, Vector[Transaction]), - OnMerkleBlockReceived] + OnMerkleBlockReceived + ] - def onBlockHeadersReceived: CallbackHandler[ - Vector[BlockHeader], - OnBlockHeadersReceived] + def onBlockHeadersReceived + : CallbackHandler[Vector[BlockHeader], OnBlockHeadersReceived] override def +(other: NodeCallbacks): NodeCallbacks - def executeOnTxReceivedCallbacks(tx: Transaction)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnTxReceivedCallbacks( + tx: Transaction + )(implicit ec: ExecutionContext): Future[Unit] = { onTxReceived.execute( tx, (err: Throwable) => - logger.error(s"${onTxReceived.name} Callback failed with error: ", err)) + logger.error(s"${onTxReceived.name} Callback failed with error: ", err) + ) } - def executeOnBlockReceivedCallbacks(block: Block)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnBlockReceivedCallbacks( + block: Block + )(implicit ec: ExecutionContext): Future[Unit] = { onBlockReceived.execute( block, (err: Throwable) => - logger.error(s"${onBlockReceived.name} Callback failed with error: ", - err)) + logger.error( + s"${onBlockReceived.name} Callback failed with error: ", + err + ) + ) } def executeOnMerkleBlockReceivedCallbacks( merkleBlock: MerkleBlock, - txs: Vector[Transaction])(implicit ec: ExecutionContext): Future[Unit] = { + txs: Vector[Transaction] + )(implicit ec: ExecutionContext): Future[Unit] = { onMerkleBlockReceived.execute( (merkleBlock, txs), (err: Throwable) => logger.error( s"${onMerkleBlockReceived.name} Callback failed with error: ", - err)) + err + ) + ) } def executeOnCompactFiltersReceivedCallbacks( - blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)])(implicit - ec: ExecutionContext): Future[Unit] = { + blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)] + )(implicit ec: ExecutionContext): Future[Unit] = { onCompactFiltersReceived.execute( blockFilters, (err: Throwable) => logger.error( s"${onCompactFiltersReceived.name} Callback failed with error: ", - err)) + err + ) + ) } - def executeOnBlockHeadersReceivedCallbacks(headers: Vector[BlockHeader])( - implicit ec: ExecutionContext): Future[Unit] = { + def executeOnBlockHeadersReceivedCallbacks( + headers: Vector[BlockHeader] + )(implicit ec: ExecutionContext): Future[Unit] = { onBlockHeadersReceived.execute( headers, (err: Throwable) => logger.error( s"${onBlockHeadersReceived.name} Callback failed with error: ", - err)) + err + ) + ) } } @@ -106,17 +121,21 @@ object NodeCallbacks extends CallbackFactory[NodeCallbacks] { // Use Impl pattern here to enforce the correct names on the CallbackHandlers private case class NodeCallbacksImpl( - onCompactFiltersReceived: CallbackHandler[ - Vector[(DoubleSha256DigestBE, GolombFilter)], - OnCompactFiltersReceived], + onCompactFiltersReceived: CallbackHandler[Vector[ + (DoubleSha256DigestBE, + GolombFilter) + ], + OnCompactFiltersReceived], onTxReceived: CallbackHandler[Transaction, OnTxReceived], onBlockReceived: CallbackHandler[Block, OnBlockReceived], onMerkleBlockReceived: CallbackHandler[ (MerkleBlock, Vector[Transaction]), - OnMerkleBlockReceived], - onBlockHeadersReceived: CallbackHandler[ - Vector[BlockHeader], - OnBlockHeadersReceived] + OnMerkleBlockReceived + ], + onBlockHeadersReceived: CallbackHandler[Vector[ + BlockHeader + ], + OnBlockHeadersReceived] ) extends NodeCallbacks { override def +(other: NodeCallbacks): NodeCallbacks = @@ -134,62 +153,77 @@ object NodeCallbacks extends CallbackFactory[NodeCallbacks] { /** Constructs a set of callbacks that only acts on TX received */ def onTxReceived(f: OnTxReceived)(implicit - system: ActorSystem): NodeCallbacks = + system: ActorSystem + ): NodeCallbacks = NodeCallbacks(onTxReceived = Vector(f)) /** Constructs a set of callbacks that only acts on block received */ def onBlockReceived(f: OnBlockReceived)(implicit - system: ActorSystem): NodeCallbacks = + system: ActorSystem + ): NodeCallbacks = NodeCallbacks(onBlockReceived = Vector(f)) /** Constructs a set of callbacks that only acts on merkle block received */ def onMerkleBlockReceived(f: OnMerkleBlockReceived)(implicit - system: ActorSystem): NodeCallbacks = + system: ActorSystem + ): NodeCallbacks = NodeCallbacks(onMerkleBlockReceived = Vector(f)) /** Constructs a set of callbacks that only acts on compact filter received */ def onCompactFilterReceived(f: OnCompactFiltersReceived)(implicit - system: ActorSystem): NodeCallbacks = + system: ActorSystem + ): NodeCallbacks = NodeCallbacks(onCompactFiltersReceived = Vector(f)) /** Constructs a set of callbacks that only acts on block headers received */ def onBlockHeadersReceived(f: OnBlockHeadersReceived)(implicit - system: ActorSystem): NodeCallbacks = + system: ActorSystem + ): NodeCallbacks = NodeCallbacks(onBlockHeadersReceived = Vector(f)) /** Empty callbacks that does nothing with the received data */ override val empty: NodeCallbacks = - NodeCallbacksImpl(CallbackHandler.empty, - CallbackHandler.empty, - CallbackHandler.empty, - CallbackHandler.empty, - CallbackHandler.empty) + NodeCallbacksImpl( + CallbackHandler.empty, + CallbackHandler.empty, + CallbackHandler.empty, + CallbackHandler.empty, + CallbackHandler.empty + ) def apply( onCompactFiltersReceived: Vector[OnCompactFiltersReceived] = Vector.empty, onTxReceived: Vector[OnTxReceived] = Vector.empty, onBlockReceived: Vector[OnBlockReceived] = Vector.empty, onMerkleBlockReceived: Vector[OnMerkleBlockReceived] = Vector.empty, - onBlockHeadersReceived: Vector[OnBlockHeadersReceived] = Vector.empty)( - implicit system: ActorSystem): NodeCallbacks = { + onBlockHeadersReceived: Vector[OnBlockHeadersReceived] = Vector.empty + )(implicit system: ActorSystem): NodeCallbacks = { val n = NodeCallbacksImpl( onCompactFiltersReceived = - CallbackHandler[Vector[(DoubleSha256DigestBE, GolombFilter)], - OnCompactFiltersReceived]("onCompactFilterReceived", - onCompactFiltersReceived), - onTxReceived = CallbackHandler[Transaction, OnTxReceived]("onTxReceived", - onTxReceived), - onBlockReceived = - CallbackHandler[Block, OnBlockReceived]("onBlockReceived", - onBlockReceived), - onMerkleBlockReceived = - CallbackHandler[(MerkleBlock, Vector[Transaction]), - OnMerkleBlockReceived]("onCompactFilterReceived", - onMerkleBlockReceived), + CallbackHandler[Vector[ + (DoubleSha256DigestBE, GolombFilter) + ], + OnCompactFiltersReceived]( + "onCompactFilterReceived", + onCompactFiltersReceived + ), + onTxReceived = CallbackHandler[Transaction, OnTxReceived]( + "onTxReceived", + onTxReceived + ), + onBlockReceived = CallbackHandler[Block, OnBlockReceived]( + "onBlockReceived", + onBlockReceived + ), + onMerkleBlockReceived = CallbackHandler[ + (MerkleBlock, Vector[Transaction]), + OnMerkleBlockReceived + ]("onCompactFilterReceived", onMerkleBlockReceived), onBlockHeadersReceived = CallbackHandler[Vector[BlockHeader], OnBlockHeadersReceived]( "onCompactFilterReceived", - onBlockHeadersReceived) + onBlockHeadersReceived + ) ) NodeCallbackStreamManager(n) } diff --git a/node/src/main/scala/org/bitcoins/node/NodeState.scala b/node/src/main/scala/org/bitcoins/node/NodeState.scala index 51a0b5de3b..36d6f6e3d7 100644 --- a/node/src/main/scala/org/bitcoins/node/NodeState.scala +++ b/node/src/main/scala/org/bitcoins/node/NodeState.scala @@ -61,9 +61,8 @@ sealed trait NodeRunningState extends NodeState { } def replacePeers( - peerWithServicesDataMap: Map[ - PeerWithServices, - PersistentPeerData]): NodeRunningState = { + peerWithServicesDataMap: Map[PeerWithServices, PersistentPeerData] + ): NodeRunningState = { this match { case h: NodeState.HeaderSync => h.copy(peerWithServicesDataMap = peerWithServicesDataMap) @@ -86,8 +85,8 @@ sealed trait NodeRunningState extends NodeState { val peerDataOpt = peerFinder.popFromCache(peer) peerDataOpt match { case None => - //do we just want to ignore the attempt if - //the peer does not exist?? + // do we just want to ignore the attempt if + // the peer does not exist?? this case Some(peerData) => val persistentPeerData = peerData match { @@ -125,7 +124,8 @@ sealed trait NodeRunningState extends NodeState { } def replaceWaitingForDisconnection( - newWaitingForDisconnection: Set[Peer]): NodeRunningState = { + newWaitingForDisconnection: Set[Peer] + ): NodeRunningState = { this match { case h: NodeState.HeaderSync => h.copy(waitingForDisconnection = newWaitingForDisconnection) @@ -146,11 +146,12 @@ sealed trait NodeRunningState extends NodeState { def randomPeer( excludePeers: Set[Peer], - services: ServiceIdentifier): Option[Peer] = { + services: ServiceIdentifier + ): Option[Peer] = { val filteredPeers = peersWithServices .filterNot(p => excludePeers.exists(_ == p.peer)) - //don't give peer a peer that we are waiting to disconnect + // don't give peer a peer that we are waiting to disconnect .filterNot(p => waitingForDisconnection.exists(_ == p.peer)) .filter(p => p.services.hasServicesOf(services)) .toVector @@ -165,7 +166,8 @@ sealed trait NodeRunningState extends NodeState { def randomPeerMessageSender( excludePeers: Set[Peer], - services: ServiceIdentifier): Option[PeerMessageSender] = { + services: ServiceIdentifier + ): Option[PeerMessageSender] = { randomPeer(excludePeers, services).flatMap { p => getPeerMsgSender(p) } @@ -190,7 +192,8 @@ sealed trait NodeRunningState extends NodeState { sealed abstract class SyncNodeState extends NodeRunningState { require( peers.exists(_ == syncPeer), - s"syncPeer must be a member of peers, syncPeer=$syncPeer peers=$peers") + s"syncPeer must be a member of peers, syncPeer=$syncPeer peers=$peers" + ) override def isSyncing: Boolean = true def syncPeer: Peer @@ -209,12 +212,14 @@ sealed abstract class SyncNodeState extends NodeRunningState { } } - /** Replaces the current sync peer with a new sync peer, - * returns None if there is not a new peer available + /** Replaces the current sync peer with a new sync peer, returns None if there + * is not a new peer available */ def replaceSyncPeer: Option[SyncNodeState] = { - randomPeer(excludePeers = Set(syncPeer), - ServiceIdentifier.NODE_COMPACT_FILTERS).map { p => + randomPeer( + excludePeers = Set(syncPeer), + ServiceIdentifier.NODE_COMPACT_FILTERS + ).map { p => replaceSyncPeer(p) } } @@ -253,7 +258,9 @@ sealed abstract class SyncNodeState extends NodeRunningState { } } -/** Either we are syncing [[NodeState.FilterHeaderSync]] or [[NodeState.FilterSync]] */ +/** Either we are syncing [[NodeState.FilterHeaderSync]] or + * [[NodeState.FilterSync]] + */ sealed trait FilterOrFilterHeaderSync extends SyncNodeState object NodeState { @@ -263,16 +270,16 @@ object NodeState { peerWithServicesDataMap: Map[PeerWithServices, PersistentPeerData], waitingForDisconnection: Set[Peer], peerFinder: PeerFinder, - sentQuery: Instant) - extends SyncNodeState + sentQuery: Instant + ) extends SyncNodeState case class FilterHeaderSync( syncPeer: Peer, peerWithServicesDataMap: Map[PeerWithServices, PersistentPeerData], waitingForDisconnection: Set[Peer], peerFinder: PeerFinder, - sentQuery: Instant) - extends FilterOrFilterHeaderSync + sentQuery: Instant + ) extends FilterOrFilterHeaderSync case class FilterSync( syncPeer: Peer, @@ -280,8 +287,8 @@ object NodeState { waitingForDisconnection: Set[Peer], filterBatchCache: Set[CompactFilterMessage], peerFinder: PeerFinder, - sentQuery: Instant) - extends FilterOrFilterHeaderSync { + sentQuery: Instant + ) extends FilterOrFilterHeaderSync { override def toString: String = { s"FilterSync(syncPeer=$syncPeer,peers=$peers,waitingForDisconnection=$waitingForDisconnection,filterBatchCache.size=${filterBatchCache.size})" @@ -292,13 +299,14 @@ object NodeState { badPeer: Peer, peerWithServicesDataMap: Map[PeerWithServices, PersistentPeerData], waitingForDisconnection: Set[Peer], - peerFinder: PeerFinder) - extends NodeRunningState { + peerFinder: PeerFinder + ) extends NodeRunningState { if (peers.nonEmpty) { - //needed for the case where the last peer we are connected to is the bad peer + // needed for the case where the last peer we are connected to is the bad peer require( peers.exists(_ == badPeer), - s"MisbehavingPeer must be in peers, badPeer=$badPeer peers=$peers") + s"MisbehavingPeer must be in peers, badPeer=$badPeer peers=$peers" + ) } override val isSyncing: Boolean = false @@ -309,23 +317,24 @@ object NodeState { peerWithServicesDataMap: Map[PeerWithServices, PersistentPeerData], waitingForDisconnection: Set[Peer], isSyncing: Boolean, - peerFinder: PeerFinder) - extends NodeRunningState { + peerFinder: PeerFinder + ) extends NodeRunningState { require( peersToRemove.forall(rm => peers.exists(_ == rm)), - s"peersToRemove must be subset of peers, peersToRemove=$peersToRemove peers=$peers") + s"peersToRemove must be subset of peers, peersToRemove=$peersToRemove peers=$peers" + ) } /** State to indicate we are not currently syncing with a peer */ case class DoneSyncing( peerWithServicesDataMap: Map[PeerWithServices, PersistentPeerData], waitingForDisconnection: Set[Peer], - peerFinder: PeerFinder) - extends NodeRunningState { + peerFinder: PeerFinder + ) extends NodeRunningState { override val isSyncing: Boolean = false - /** Selects a random peer and returns us a header sync state - * returns None if we don't have a peer ot sync with + /** Selects a random peer and returns us a header sync state returns None if + * we don't have a peer ot sync with */ def toHeaderSync: Option[HeaderSync] = { val syncPeerOpt = @@ -364,8 +373,8 @@ object NodeState { case class NodeShuttingDown( peerWithServicesDataMap: Map[PeerWithServices, PersistentPeerData], waitingForDisconnection: Set[Peer], - peerFinder: PeerFinder) - extends NodeRunningState { + peerFinder: PeerFinder + ) extends NodeRunningState { override val isSyncing: Boolean = false } diff --git a/node/src/main/scala/org/bitcoins/node/NodeStreamMessage.scala b/node/src/main/scala/org/bitcoins/node/NodeStreamMessage.scala index 6ba1314a70..708a06da74 100644 --- a/node/src/main/scala/org/bitcoins/node/NodeStreamMessage.scala +++ b/node/src/main/scala/org/bitcoins/node/NodeStreamMessage.scala @@ -46,6 +46,8 @@ object NodeStreamMessage { case object NodeShutdown extends NodeStreamMessage - /** Checks our peers are healthy, for instance checking that we are peered with compact filter peers */ + /** Checks our peers are healthy, for instance checking that we are peered + * with compact filter peers + */ case object PeerHealthCheck extends NodeStreamMessage } diff --git a/node/src/main/scala/org/bitcoins/node/PeerData.scala b/node/src/main/scala/org/bitcoins/node/PeerData.scala index 1616d21a6f..8c74c5d7bb 100644 --- a/node/src/main/scala/org/bitcoins/node/PeerData.scala +++ b/node/src/main/scala/org/bitcoins/node/PeerData.scala @@ -40,7 +40,9 @@ sealed trait PeerData { def serviceIdentifier: ServiceIdentifier = { _serviceIdentifier.getOrElse( throw new RuntimeException( - s"Tried using ServiceIdentifier for uninitialized peer $peer")) + s"Tried using ServiceIdentifier for uninitialized peer $peer" + ) + ) } def setServiceIdentifier(serviceIdentifier: ServiceIdentifier): Unit = { @@ -55,8 +57,8 @@ case class PersistentPeerData( )(implicit override val system: ActorSystem, override val nodeAppConfig: NodeAppConfig, - override val chainAppConfig: ChainAppConfig) - extends PeerData { + override val chainAppConfig: ChainAppConfig +) extends PeerData { private var _invalidMessagesCount: Int = 0 @@ -72,7 +74,8 @@ case class PersistentPeerData( lastTimedOut = System.currentTimeMillis() } - /** returns true if the peer has failed due to any reason within the past 30 minutes + /** returns true if the peer has failed due to any reason within the past 30 + * minutes */ def hasFailedRecently: Boolean = { val timePast = System.currentTimeMillis() - lastTimedOut @@ -84,9 +87,9 @@ case class PersistentPeerData( } } -/** A peer we are just discovering on the p2p network for future connections - * we do not want to be persistently connected to this peer, just see if - * we can connect to it and exchange version/verack messages +/** A peer we are just discovering on the p2p network for future connections we + * do not want to be persistently connected to this peer, just see if we can + * connect to it and exchange version/verack messages */ case class AttemptToConnectPeerData( peer: Peer, @@ -94,8 +97,8 @@ case class AttemptToConnectPeerData( )(implicit override val system: ActorSystem, override val nodeAppConfig: NodeAppConfig, - override val chainAppConfig: ChainAppConfig) - extends PeerData { + override val chainAppConfig: ChainAppConfig +) extends PeerData { def toPersistentPeerData: PersistentPeerData = { val p = PersistentPeerData(peer, peerMessageSender) diff --git a/node/src/main/scala/org/bitcoins/node/PeerFinder.scala b/node/src/main/scala/org/bitcoins/node/PeerFinder.scala index 3c7b9ae5d0..9d0a6e7e58 100644 --- a/node/src/main/scala/org/bitcoins/node/PeerFinder.scala +++ b/node/src/main/scala/org/bitcoins/node/PeerFinder.scala @@ -28,12 +28,13 @@ import scala.util.{Failure, Random, Success} case class PeerFinder( peerManagerApi: PeerManagerApi, paramPeers: Vector[Peer], - queue: SourceQueue[NodeStreamMessage])(implicit + queue: SourceQueue[NodeStreamMessage] +)(implicit ec: ExecutionContext, system: ActorSystem, nodeAppConfig: NodeAppConfig, - chainAppConfig: ChainAppConfig) - extends StartStopAsync[PeerFinder] + chainAppConfig: ChainAppConfig +) extends StartStopAsync[PeerFinder] with P2PLogger { private val isStarted: AtomicBoolean = new AtomicBoolean(false) @@ -41,7 +42,9 @@ case class PeerFinder( val controlMessageHandler: ControlMessageHandler = ControlMessageHandler(this) - /** Returns peers by querying each dns seed once. These will be IPv4 addresses. */ + /** Returns peers by querying each dns seed once. These will be IPv4 + * addresses. + */ private def getPeersFromDnsSeeds: Future[Vector[Peer]] = { val dnsSeeds = nodeAppConfig.network.dnsSeeds val addressesF: Future[Vector[String]] = Future @@ -64,7 +67,9 @@ case class PeerFinder( } - /** Returns peers from hardcoded addresses taken from https://github.com/bitcoin/bitcoin/blob/master/contrib/seeds/nodes_main.txt */ + /** Returns peers from hardcoded addresses taken from + * https://github.com/bitcoin/bitcoin/blob/master/contrib/seeds/nodes_main.txt + */ private def getPeersFromResources: Vector[Peer] = { val source = Source.fromURL(getClass.getResource("/hardcoded-peers.txt")) val addresses = source @@ -75,13 +80,17 @@ case class PeerFinder( Random.shuffle(peers) } - /** Returns tuple (non-filter peer, filter peers) from all peers stored in database */ + /** Returns tuple (non-filter peer, filter peers) from all peers stored in + * database + */ private def getPeersFromDb: Future[(Vector[PeerDb], Vector[PeerDb])] = { val dbF: Future[Vector[PeerDb]] = PeerDAO().findAllWithTorFilter(nodeAppConfig.torConf.enabled) - val partitionF = dbF.map(_.partition(b => - !ServiceIdentifier.fromBytes(b.serviceBytes).nodeCompactFilters)) + val partitionF = dbF.map( + _.partition(b => + !ServiceIdentifier.fromBytes(b.serviceBytes).nodeCompactFilters) + ) partitionF.map { p => val sorted1 = p._1.sortBy(_.lastSeen).reverse @@ -90,11 +99,12 @@ case class PeerFinder( } } - /** Gets last seen peers before a given cool down a period so we don't keep automatically - * reconnecting to peers we just disconnected + /** Gets last seen peers before a given cool down a period so we don't keep + * automatically reconnecting to peers we just disconnected */ private def getLastSeenBlockFilterPeers( - dbSlots: Int): Future[Vector[PeerDb]] = { + dbSlots: Int + ): Future[Vector[PeerDb]] = { val cooldown = Instant .now() .minusMillis(nodeAppConfig.connectionAttemptCooldownPeriod.toMillis) @@ -104,8 +114,8 @@ case class PeerFinder( } yield Random.shuffle(filtered).take(dbSlots) } - /** Returns peers from bitcoin-s.config file unless peers are supplied as an argument to [[PeerManager]] in which - * case it returns those. + /** Returns peers from bitcoin-s.config file unless peers are supplied as an + * argument to [[PeerManager]] in which case it returns those. */ private def getPeersFromConfig: Vector[Peer] = { val addresses = nodeAppConfig.peers.filter(p => @@ -113,7 +123,7 @@ case class PeerFinder( addresses } - //for the peers we try + // for the peers we try private val _peerData: mutable.Map[Peer, PeerData] = { mutable.Map.empty } @@ -131,7 +141,8 @@ case class PeerFinder( private def peerConnectionScheduler(): Cancellable = { system.scheduler.scheduleWithFixedDelay( initialDelay = initialDelay, - delay = nodeAppConfig.tryNextPeersInterval) { () => + delay = nodeAppConfig.tryNextPeersInterval + ) { () => { queryForPeerConnections(excludePeers = Set.empty) () @@ -142,12 +153,13 @@ case class PeerFinder( override def start(): Future[PeerFinder] = { if (!isStarted.get()) { logger.info( - s"Starting PeerFinder initialDelay=${initialDelay.toSeconds} seconds tryPeersInterval=${nodeAppConfig.tryNextPeersInterval.toMinutes} minutes paramPeers=$paramPeers") + s"Starting PeerFinder initialDelay=${initialDelay.toSeconds} seconds tryPeersInterval=${nodeAppConfig.tryNextPeersInterval.toMinutes} minutes paramPeers=$paramPeers" + ) val start = System.currentTimeMillis() isStarted.set(true) val peersToTry = (paramPeers ++ getPeersFromConfig).distinct val pds = peersToTry.map(p => buildPeerData(p, isPersistent = true)) - //higher priority for param peers + // higher priority for param peers _peersToTry.pushAll(pds, priority = 2) val peerDiscoveryF = if (nodeAppConfig.enablePeerDiscovery) { @@ -176,7 +188,8 @@ case class PeerFinder( for { peerFinder <- peerDiscoveryF _ = logger.info( - s"Done starting PeerFinder, it took ${System.currentTimeMillis() - start}ms") + s"Done starting PeerFinder, it took ${System.currentTimeMillis() - start}ms" + ) } yield peerFinder } else { logger.warn(s"PeerFinder already started") @@ -190,7 +203,8 @@ case class PeerFinder( tryPeer(peer, isPersistent = true) } else { logger.warn( - s"Ignoring connect attempt to peer=$peer as PeerFinder is not started") + s"Ignoring connect attempt to peer=$peer as PeerFinder is not started" + ) Future.unit } } @@ -201,7 +215,8 @@ case class PeerFinder( tryToReconnectPeer(peer) } else { logger.warn( - s"Ignoring reconnect attempt to peer=$peer as PeerFinder is not started") + s"Ignoring reconnect attempt to peer=$peer as PeerFinder is not started" + ) Future.unit } } @@ -210,10 +225,10 @@ case class PeerFinder( if (isStarted.get()) { logger.info(s"Stopping PeerFinder") isStarted.set(false) - //stop scheduler + // stop scheduler peerConnectionCancellableOpt.map(_.cancel()) peerConnectionCancellableOpt = None - //delete try queue + // delete try queue _peersToTry.clear() val stopF = for { @@ -221,8 +236,8 @@ case class PeerFinder( _ <- AsyncUtil .retryUntilSatisfied( { - //there seems to be some sort of bug in mutable.Map.isEmpty - //convert it to an immutable Map with .toMap and then check isEmpty + // there seems to be some sort of bug in mutable.Map.isEmpty + // convert it to an immutable Map with .toMap and then check isEmpty _peerData.toMap.isEmpty }, interval = 1.seconds, @@ -234,8 +249,10 @@ case class PeerFinder( } stopF.failed.foreach { e => - logger.error(s"Failed to stop peer finder. Peers: ${_peerData.toMap}", - e) + logger.error( + s"Failed to stop peer finder. Peers: ${_peerData.toMap}", + e + ) } stopF } else { @@ -269,13 +286,14 @@ case class PeerFinder( def removePeer(peer: Peer): Future[Option[PeerData]] = { Future.successful { logger.debug(s"Removing peer=$peer") - _peerData.remove(peer) //peer must be a member of _peerData + _peerData.remove(peer) // peer must be a member of _peerData } } def setServiceIdentifier( peer: Peer, - serviceIdentifier: ServiceIdentifier): Unit = { + serviceIdentifier: ServiceIdentifier + ): Unit = { _peerData(peer).setServiceIdentifier(serviceIdentifier) } @@ -313,13 +331,16 @@ case class PeerFinder( } } - /** Attempts to connect to various peers on the p2p network. Try to get more peers for our node. */ + /** Attempts to connect to various peers on the p2p network. Try to get more + * peers for our node. + */ def queryForPeerConnections(excludePeers: Set[Peer]): Option[Unit] = { if ( isConnectionSchedulerRunning.compareAndSet(false, true) && isStarted.get() ) { logger.debug( - s"Attempting to find more peers to connect to... stack.size=${_peersToTry.size}") + s"Attempting to find more peers to connect to... stack.size=${_peersToTry.size}" + ) val dbSlots = nodeAppConfig.maxConnectedPeers val dbPeersDbF = getLastSeenBlockFilterPeers(dbSlots) @@ -345,11 +366,11 @@ case class PeerFinder( } val peersToTryF = paramPdsF.map { _ => - //in case of less _peersToTry.size than maxPeerSearchCount + // in case of less _peersToTry.size than maxPeerSearchCount val max = Math.min(maxPeerSearchCount, _peersToTry.size) - val peers = ( - 0.until(max) - .map(_ => _peersToTry.pop())) + val peers = (0 + .until(max) + .map(_ => _peersToTry.pop())) .distinct .filterNot(p => excludePeers.exists(_ == p.peer)) peers @@ -360,16 +381,18 @@ case class PeerFinder( _ = logger.debug(s"Trying next set of peers $peers") _ <- { Future.traverse(peers) { p => - //check if we already have an active connection + // check if we already have an active connection val isDisconnectedF = peerManagerApi.isDisconnected(p.peer) for { isDisconnected <- isDisconnectedF _ <- { if (isDisconnected) { - tryPeer(peer = p.peer, - isPersistent = p.isInstanceOf[PersistentPeerData]) + tryPeer( + peer = p.peer, + isPersistent = p.isInstanceOf[PersistentPeerData] + ) } else { - //do nothing, we are already connected + // do nothing, we are already connected Future.unit } } @@ -387,7 +410,8 @@ case class PeerFinder( Some(()) } else { logger.warn( - s"Previous connection scheduler is still running or PeerFinder not started, skipping this run, it will run again in ${nodeAppConfig.tryNextPeersInterval}") + s"Previous connection scheduler is still running or PeerFinder not started, skipping this run, it will run again in ${nodeAppConfig.tryNextPeersInterval}" + ) None } } diff --git a/node/src/main/scala/org/bitcoins/node/PeerManager.scala b/node/src/main/scala/org/bitcoins/node/PeerManager.scala index c9c20db2f1..b21df7944d 100644 --- a/node/src/main/scala/org/bitcoins/node/PeerManager.scala +++ b/node/src/main/scala/org/bitcoins/node/PeerManager.scala @@ -33,11 +33,12 @@ import scala.concurrent.{ExecutionContext, Future} case class PeerManager( paramPeers: Vector[Peer], walletCreationTimeOpt: Option[Instant], - queue: SourceQueue[NodeStreamMessage])(implicit + queue: SourceQueue[NodeStreamMessage] +)(implicit ec: ExecutionContext, nodeAppConfig: NodeAppConfig, - chainAppConfig: ChainAppConfig) - extends StartStopAsync[PeerManager] + chainAppConfig: ChainAppConfig +) extends StartStopAsync[PeerManager] with PeerManagerApi with P2PLogger { private val isStarted: AtomicBoolean = new AtomicBoolean(false) @@ -61,15 +62,17 @@ case class PeerManager( peerDataMap.map(t => (t._2.peerWithServicesOpt.get, t._2)) } - /** Starts sync compact filter headers. - * Only starts syncing compact filters if our compact filter headers are in sync with block headers + /** Starts sync compact filter headers. Only starts syncing compact filters if + * our compact filter headers are in sync with block headers */ private def syncCompactFilters( bestFilterHeader: CompactFilterHeaderDb, chainApi: ChainApi, compactFilterStartHeightOpt: Option[Int], - syncNodeState: SyncNodeState)(implicit - chainAppConfig: ChainAppConfig): Future[Option[FilterOrFilterHeaderSync]] = { + syncNodeState: SyncNodeState + )(implicit + chainAppConfig: ChainAppConfig + ): Future[Option[FilterOrFilterHeaderSync]] = { if (syncNodeState.services.nodeCompactFilters) { val syncPeer = syncNodeState.syncPeer val peerMsgSender = syncNodeState.syncPeerMessageSender @@ -112,14 +115,16 @@ case class PeerManager( } } else { logger.warn( - s"Cannot syncCompactFilters() with peer=${syncNodeState.syncPeer} as the peer doesn't support block filters") + s"Cannot syncCompactFilters() with peer=${syncNodeState.syncPeer} as the peer doesn't support block filters" + ) Future.successful(None) } } private def createInDb( peer: Peer, - serviceIdentifier: ServiceIdentifier): Future[PeerDb] = { + serviceIdentifier: ServiceIdentifier + ): Future[PeerDb] = { logger.debug(s"Adding peer to db $peer") val addrBytes = PeerDAOHelper.getAddrBytes(peer) val networkByte = addrBytes.length match { @@ -128,7 +133,8 @@ case class PeerManager( case AddrV2Message.TOR_V3_ADDR_LENGTH => AddrV2Message.TOR_V3_NETWORK_BYTE case unknownSize => throw new IllegalArgumentException( - s"Unsupported address type of size $unknownSize bytes") + s"Unsupported address type of size $unknownSize bytes" + ) } PeerDAO() .upsertPeer(addrBytes, peer.port, networkByte, serviceIdentifier) @@ -174,7 +180,8 @@ case class PeerManager( ) } yield { logger.info( - s"Stopped PeerManager. Took ${System.currentTimeMillis() - beganAt}ms") + s"Stopped PeerManager. Took ${System.currentTimeMillis() - beganAt}ms" + ) this } @@ -198,37 +205,45 @@ case class PeerManager( private def onInitializationTimeout( peer: Peer, - state: NodeRunningState): Future[Unit] = { + state: NodeRunningState + ): Future[Unit] = { logger.debug(s"onInitializationTimeout() peer=$peer state=$state") val finder = state.peerFinder - require(!finder.hasPeer(peer) || !state.getPeerData(peer).isDefined, - s"$peer cannot be both a test and a persistent peer") + require( + !finder.hasPeer(peer) || !state.getPeerData(peer).isDefined, + s"$peer cannot be both a test and a persistent peer" + ) if (finder.hasPeer(peer)) { - //one of the peers that we tried, failed to init within time, disconnect + // one of the peers that we tried, failed to init within time, disconnect finder.getPeerData(peer).get.stop().map(_ => ()) } else if (state.getPeerData(peer).isDefined) { - //this is one of our persistent peers which must have been initialized earlier, this can happen in case of - //a reconnection attempt, meaning it got connected but failed to initialize, disconnect + // this is one of our persistent peers which must have been initialized earlier, this can happen in case of + // a reconnection attempt, meaning it got connected but failed to initialize, disconnect state .getPeerData(peer) .get .stop() .map(_ => ()) } else { - //this should never happen + // this should never happen logger.warn(s"onInitializationTimeout called for unknown $peer") Future.unit } } - /** Helper method to determine what action to take after a peer is initialized, such as beginning sync with that peer */ + /** Helper method to determine what action to take after a peer is + * initialized, such as beginning sync with that peer + */ private def managePeerAfterInitialization( state: NodeRunningState, - peer: Peer): Future[NodeRunningState] = { + peer: Peer + ): Future[NodeRunningState] = { val curPeerDataOpt = state.peerFinder.getPeerData(peer) - require(curPeerDataOpt.isDefined, - s"Could not find peer=$peer in PeerFinder!") + require( + curPeerDataOpt.isDefined, + s"Could not find peer=$peer in PeerFinder!" + ) val peerData = curPeerDataOpt.get val hasCf = peerData.serviceIdentifier.nodeCompactFilters val notCfPeers = state.peerDataMap @@ -238,7 +253,7 @@ case class PeerManager( val hasConnectionSlot = state.connectedPeerCount < nodeAppConfig.maxConnectedPeers if (hasConnectionSlot) { - //we want to promote this peer, so pop from cache + // we want to promote this peer, so pop from cache val newState = state.addPeer(peer) val persistentPeerData = newState.peerDataMap.filter(_._1 == peer).head._2 @@ -258,17 +273,20 @@ case class PeerManager( private def onInitialization( peer: Peer, - state: NodeRunningState): Future[NodeState] = { + state: NodeRunningState + ): Future[NodeState] = { val finder = state.peerFinder val stateF: Future[NodeRunningState] = { - //this assumes neutrino and checks for compact filter support so should not be called for anything else - require(nodeAppConfig.nodeType == NodeType.NeutrinoNode, - s"Node cannot be ${nodeAppConfig.nodeType.shortName}") + // this assumes neutrino and checks for compact filter support so should not be called for anything else + require( + nodeAppConfig.nodeType == NodeType.NeutrinoNode, + s"Node cannot be ${nodeAppConfig.nodeType.shortName}" + ) if (finder.hasPeer(peer)) { - //one of the peers we tries got initialized successfully + // one of the peers we tries got initialized successfully val peerData = finder.getPeerData(peer).get val serviceIdentifer = peerData.serviceIdentifier val hasCf = serviceIdentifer.nodeCompactFilters @@ -278,16 +296,19 @@ case class PeerManager( _ <- createInDb(peer, peerData.serviceIdentifier) newState <- managePeerAfterInitialization(state, peer) } yield { - require(!finder.hasPeer(peer) || !state.getPeerData(peer).isDefined, - s"$peer cannot be both a test and a persistent peer") + require( + !finder.hasPeer(peer) || !state.getPeerData(peer).isDefined, + s"$peer cannot be both a test and a persistent peer" + ) logger.debug( - s"Initialized peer $peer with compactFilter support=$hasCf") + s"Initialized peer $peer with compactFilter support=$hasCf" + ) newState } } else if (state.peers.contains(peer)) { - //one of the persistent peers initialized again, this can happen in case of a reconnection attempt - //which succeeded which is all good, do nothing + // one of the persistent peers initialized again, this can happen in case of a reconnection attempt + // which succeeded which is all good, do nothing state match { case s: SyncNodeState => val x = s.replaceSyncPeer(peer) @@ -308,37 +329,43 @@ case class PeerManager( stateF } - /** @param peer the peer we were disconencted from - * @param reconnect flag indicating if we should attempt to reconnect + /** @param peer + * the peer we were disconencted from + * @param reconnect + * flag indicating if we should attempt to reconnect * @return */ private def onDisconnect( peer: Peer, forceReconnect: Boolean, - state: NodeRunningState): Future[NodeState] = { + state: NodeRunningState + ): Future[NodeState] = { logger.info(s"Disconnected peer=$peer state=$state") val finder = state.peerFinder val updateLastSeenF = PeerDAO().updateLastSeenTime(peer) val stateF: Future[NodeRunningState] = { - require(!finder.hasPeer(peer) || !state.getPeerData(peer).isDefined, - s"$peer cannot be both a test and a persistent peer") + require( + !finder.hasPeer(peer) || !state.getPeerData(peer).isDefined, + s"$peer cannot be both a test and a persistent peer" + ) if (finder.hasPeer(peer)) { finder.removePeer(peer) Future.successful(state) } else if (state.peers.contains(peer)) { _peerDataMap.remove(peer) - onDisconnectNodeStateUpdate(state = state, - disconnectedPeer = peer, - forceReconnect = forceReconnect).map { - updated => - val rm = state.waitingForDisconnection.-(peer) - val rmWaitingForDisconnect = - updated.replaceWaitingForDisconnection(rm) - rmWaitingForDisconnect + onDisconnectNodeStateUpdate( + state = state, + disconnectedPeer = peer, + forceReconnect = forceReconnect + ).map { updated => + val rm = state.waitingForDisconnection.-(peer) + val rmWaitingForDisconnect = + updated.replaceWaitingForDisconnection(rm) + rmWaitingForDisconnect } } else if (state.waitingForDisconnection.contains(peer)) { - //a peer we wanted to disconnect has remove has stopped the client actor, finally mark this as deleted + // a peer we wanted to disconnect has remove has stopped the client actor, finally mark this as deleted val removed = state.waitingForDisconnection.-(peer) val newState = state.replaceWaitingForDisconnection(removed) Future.successful(newState) @@ -357,7 +384,8 @@ case class PeerManager( private def onDisconnectNodeStateUpdate( state: NodeRunningState, disconnectedPeer: Peer, - forceReconnect: Boolean): Future[NodeRunningState] = { + forceReconnect: Boolean + ): Future[NodeRunningState] = { val isShuttingDown = state.isInstanceOf[NodeShuttingDown] val finder = state.peerFinder if (state.peers.exists(_ != disconnectedPeer)) { @@ -366,8 +394,8 @@ case class PeerManager( case s: SyncNodeState => syncHelper(s).map(_.getOrElse(s.toDoneSyncing)) case d: DoneSyncing => - //defensively try to sync with the new peer - //this headerSync is not safe, need to exclude peer we are disconnencting + // defensively try to sync with the new peer + // this headerSync is not safe, need to exclude peer we are disconnencting val hsOpt = d .removePeer(disconnectedPeer) .asInstanceOf[DoneSyncing] @@ -375,7 +403,7 @@ case class PeerManager( hsOpt match { case Some(hs) => syncHelper(hs).map(_.getOrElse(hs.toDoneSyncing)) case None => - //no peers available to sync with, so return DoneSyncing + // no peers available to sync with, so return DoneSyncing Future.successful(d) } @@ -384,22 +412,24 @@ case class PeerManager( Future.successful(x) } } else { - //no new peers to try to sync from, transition to done syncing? + // no new peers to try to sync from, transition to done syncing? val done = state.removePeer(disconnectedPeer).toDoneSyncing if (forceReconnect && !isShuttingDown) { finder.reconnect(disconnectedPeer).map(_ => done) } else if (!isShuttingDown) { logger.info( - s"No new peers to connect to, querying for new connections... state=${state} peers=$peers") + s"No new peers to connect to, querying for new connections... state=${state} peers=$peers" + ) finder.queryForPeerConnections(Set(disconnectedPeer)) match { case Some(_) => Future.successful(done) case None => logger.debug( - s"Could not query for more peer connections as previous job is still running") + s"Could not query for more peer connections as previous job is still running" + ) Future.successful(done) } } else { - //if shutting down, do nothing + // if shutting down, do nothing Future.successful(done) } } @@ -408,10 +438,11 @@ case class PeerManager( private def onQueryTimeout( payload: ExpectsResponse, peer: Peer, - state: NodeRunningState): Future[Unit] = { + state: NodeRunningState + ): Future[Unit] = { logger.debug(s"Query timeout out for $peer with payload=${payload}") - //if we are removing this peer and an existing query timed out because of that + // if we are removing this peer and an existing query timed out because of that // peerData will not have this peer state.getPeerData(peer).map(_.updateLastFailureTime()) @@ -433,11 +464,14 @@ case class PeerManager( /** @param peer * @param state - * @return a NodeState that contains the new peer we are syncing with, None if we couldn't find a new peer to sync with + * @return + * a NodeState that contains the new peer we are syncing with, None if we + * couldn't find a new peer to sync with */ private def onHeaderRequestTimeout( peer: Peer, - state: NodeState): Future[Option[NodeState]] = { + state: NodeState + ): Future[Option[NodeState]] = { logger.info(s"Header request timed out from $peer in state $state") state match { case h: HeaderSync => @@ -456,9 +490,11 @@ case class PeerManager( private def sendResponseTimeout( peer: Peer, payload: NetworkPayload, - state: NodeRunningState): Future[Unit] = { + state: NodeRunningState + ): Future[Unit] = { logger.debug( - s"Sending response timeout for ${payload.commandName} to $peer") + s"Sending response timeout for ${payload.commandName} to $peer" + ) if (state.getPeerData(peer).isDefined) { payload match { case e: ExpectsResponse => @@ -467,7 +503,8 @@ case class PeerManager( .map(_ => ()) case _: NetworkPayload => val exn = new RuntimeException( - s"Cannot have sendResponseTimeout for msg=${payload.commandName} for non ExpectsResponse payload") + s"Cannot have sendResponseTimeout for msg=${payload.commandName} for non ExpectsResponse payload" + ) Future.failed(exn) } } else { @@ -477,7 +514,8 @@ case class PeerManager( } def buildP2PMessageHandlerSink( - initState: NodeState): Sink[NodeStreamMessage, Future[NodeState]] = { + initState: NodeState + ): Sink[NodeStreamMessage, Future[NodeState]] = { Sink.foldAsync(initState) { case (state, s: StartSync) => val nodeStateOptF: Future[Option[NodeState]] = s.peerOpt match { @@ -487,15 +525,18 @@ case class PeerManager( switchSyncToPeer(s, p) case s: SyncNodeState => logger.warn( - s"Ignoring sync request for peer=${p} as its waiting for disconnection") + s"Ignoring sync request for peer=${p} as its waiting for disconnection" + ) Future.successful(Some(s)) case x @ (_: MisbehavingPeer | _: RemovePeers) => logger.warn( - s"Ignoring sync request for peer=${p} while we are in state=$x") - Future.successful(Some(x)) //ignore sync request? + s"Ignoring sync request for peer=${p} while we are in state=$x" + ) + Future.successful(Some(x)) // ignore sync request? case s: NodeShuttingDown => logger.warn( - s"Ignoring sync request as our node is shutting down, state=$s") + s"Ignoring sync request as our node is shutting down, state=$s" + ) Future.successful(Some(s)) case d: DoneSyncing => val h = d.toHeaderSync(p) @@ -505,11 +546,13 @@ case class PeerManager( state match { case x @ (_: SyncNodeState | _: MisbehavingPeer | _: RemovePeers | _: NodeShuttingDown) => - //we are either syncing already, or we are in a bad state to start a sync + // we are either syncing already, or we are in a bad state to start a sync Future.successful(Some(x)) case d: DoneSyncing => - d.randomPeer(Set.empty, - ServiceIdentifier.NODE_COMPACT_FILTERS) match { + d.randomPeer( + Set.empty, + ServiceIdentifier.NODE_COMPACT_FILTERS + ) match { case Some(p) => val h = d.toHeaderSync(p) @@ -523,14 +566,16 @@ case class PeerManager( case Some(ns) => ns case None => logger.warn( - s"Cannot find a new peer to fulfill sync request, reverting to old state=$state") + s"Cannot find a new peer to fulfill sync request, reverting to old state=$state" + ) state } case (state, c: ConnectPeer) => state match { case s: NodeShuttingDown => logger.warn( - s"Ignoring connect peer request as node is shutting down, c=$c") + s"Ignoring connect peer request as node is shutting down, c=$c" + ) Future.successful(s) case runningState: NodeRunningState => val peer = c.peer @@ -544,7 +589,8 @@ case class PeerManager( .map(_.nodeCompactFilters) .getOrElse(false) logger.info( - s"Connected to peer $peer with compact filter support=$hasCf. Connected peer count ${runningState.peerDataMap.size} state=$state") + s"Connected to peer $peer with compact filter support=$hasCf. Connected peer count ${runningState.peerDataMap.size} state=$state" + ) state match { case s: SyncNodeState => syncHelper(s).map(_.getOrElse(s.toDoneSyncing)) @@ -562,7 +608,8 @@ case class PeerManager( case running: NodeRunningState => if (running.waitingForDisconnection.exists(_ == i.peer)) { logger.debug( - s"Attempting to intialize disconnect of peer=${i.peer} we are already waitingForDisconnection, state=$running") + s"Attempting to intialize disconnect of peer=${i.peer} we are already waitingForDisconnection, state=$running" + ) Future.successful(running) } else { val client: PeerData = @@ -570,22 +617,24 @@ case class PeerManager( case Some(p) => p case None => sys.error( - s"Cannot find peer=${i.peer} for InitializeDisconnect=$i") + s"Cannot find peer=${i.peer} for InitializeDisconnect=$i" + ) } - //so we need to remove if from the map for connected peers so no more request could be sent to it but we before - //the actor is stopped we don't delete it to ensure that no such case where peers is deleted but actor not stopped - //leading to a memory leak may happen + // so we need to remove if from the map for connected peers so no more request could be sent to it but we before + // the actor is stopped we don't delete it to ensure that no such case where peers is deleted but actor not stopped + // leading to a memory leak may happen - //now send request to stop actor which will be completed some time in future + // now send request to stop actor which will be completed some time in future val _ = _peerDataMap.remove(i.peer) val newStateF = - onDisconnectNodeStateUpdate(state = running, - disconnectedPeer = i.peer, - forceReconnect = false).map { - updated => - val newWaiting = updated.waitingForDisconnection.+(i.peer) - updated - .replaceWaitingForDisconnection(newWaiting) + onDisconnectNodeStateUpdate( + state = running, + disconnectedPeer = i.peer, + forceReconnect = false + ).map { updated => + val newWaiting = updated.waitingForDisconnection.+(i.peer) + updated + .replaceWaitingForDisconnection(newWaiting) } val stopF: Future[Done] = client.stop().recoverWith { case scala.util.control.NonFatal(err) => @@ -609,7 +658,8 @@ case class PeerManager( peerDataOpt match { case None => logger.debug( - s"Ignoring received msg=${payload.commandName} from peer=$peer because it was disconnected, peers=$peers state=${state}") + s"Ignoring received msg=${payload.commandName} from peer=$peer because it was disconnected, peers=$peers state=${state}" + ) Future.successful(state) case Some(peerData) => val dmh = DataMessageHandler( @@ -623,7 +673,7 @@ case class PeerManager( .flatMap { newDmh => newDmh.state match { case m: MisbehavingPeer => - //disconnect the misbehaving peer + // disconnect the misbehaving peer for { _ <- disconnectPeer(m.badPeer) } yield { @@ -632,7 +682,8 @@ case class PeerManager( case removePeers: RemovePeers => for { _ <- Future.traverse(removePeers.peers)( - disconnectPeer) + disconnectPeer + ) } yield newDmh.state case x @ (_: SyncNodeState | _: DoneSyncing | _: NodeShuttingDown) => @@ -641,7 +692,8 @@ case class PeerManager( } resultF.map { r => logger.debug( - s"Done processing ${payload.commandName} in peer=${peer} state=${r}") + s"Done processing ${payload.commandName} in peer=${peer} state=${r}" + ) r } } @@ -663,14 +715,16 @@ case class PeerManager( peerMsgSenderApiOpt match { case Some(peerMsgSenderApi) => val resultOptF = runningState.peerFinder.controlMessageHandler - .handleControlPayload(payload, - peerMsgSenderApi = peerMsgSenderApi) + .handleControlPayload( + payload, + peerMsgSenderApi = peerMsgSenderApi + ) resultOptF.flatMap { case Some(i: ControlMessageHandler.Initialized) => onInitialization(i.peer, runningState) case Some(ControlMessageHandler.ReceivedAddrMessage) => if (runningState.peerFinder.hasPeer(peer)) { - //got to disconnect it since it hasn't been promoted to a persistent peer + // got to disconnect it since it hasn't been promoted to a persistent peer runningState.peerFinder.getPeerData(peer) match { case Some(pd: AttemptToConnectPeerData) => pd.stop().map(_ => runningState) @@ -678,7 +732,7 @@ case class PeerManager( Future.successful(runningState) } } else { - //do nothing as its a persistent peer + // do nothing as its a persistent peer Future.successful(runningState) } case None => @@ -686,7 +740,8 @@ case class PeerManager( } case None => logger.warn( - s"Cannot find a peer message sender api from peer=$peer to handle control payload=${payload.commandName}") + s"Cannot find a peer message sender api from peer=$peer to handle control payload=${payload.commandName}" + ) Future.successful(state) } } @@ -700,10 +755,12 @@ case class PeerManager( onHeaderRequestTimeout(peer, state).map { case Some(s) => s case None => - //we don't have a state to represent no connected peers atm, so switch to DoneSyncing? - DoneSyncing(peerWithServicesDataMap = Map.empty, - runningState.waitingForDisconnection, - runningState.peerFinder) + // we don't have a state to represent no connected peers atm, so switch to DoneSyncing? + DoneSyncing( + peerWithServicesDataMap = Map.empty, + runningState.waitingForDisconnection, + runningState.peerFinder + ) } } } yield { @@ -748,7 +805,8 @@ case class PeerManager( } if (gossipPeers.isEmpty) { logger.warn( - s"We have 0 peers to gossip message=${msg.commandName} to state=$state.") + s"We have 0 peers to gossip message=${msg.commandName} to state=$state." + ) Future.successful(state) } else { Future @@ -759,7 +817,8 @@ case class PeerManager( sender.sendMsg(msg) case None => logger.warn( - s"Attempting to gossip to peer that is available in state.peers, but not peerDataMap? state=$state") + s"Attempting to gossip to peer that is available in state.peers, but not peerDataMap? state=$state" + ) Future.unit } } @@ -770,7 +829,8 @@ case class PeerManager( state match { case _: NodeShuttingDown => logger.warn( - s"Cannot send to peer when we are shutting down! stp=$stp state=$state") + s"Cannot send to peer when we are shutting down! stp=$stp state=$state" + ) Future.successful(state) case r: NodeRunningState => sendToPeerHelper(r, stp) @@ -780,17 +840,19 @@ case class PeerManager( state match { case s: NodeShuttingDown => logger.warn( - s"Shut down already requested, ignoring new shutdown request") + s"Shut down already requested, ignoring new shutdown request" + ) Future.successful(s) case r: NodeRunningState => logger.info( - s"Received NodeShutdown message, beginning shutdown procedures") + s"Received NodeShutdown message, beginning shutdown procedures" + ) val shutdownState = - NodeShuttingDown(peerWithServicesDataMap = - r.peerWithServicesDataMap, - waitingForDisconnection = - r.waitingForDisconnection, - peerFinder = r.peerFinder) + NodeShuttingDown( + peerWithServicesDataMap = r.peerWithServicesDataMap, + waitingForDisconnection = r.waitingForDisconnection, + peerFinder = r.peerFinder + ) Future .traverse(r.peers)(disconnectPeer(_)) .map(_ => shutdownState) @@ -811,7 +873,8 @@ case class PeerManager( private def sendToPeerHelper( state: NodeRunningState, - stp: SendToPeer): Future[NodeRunningState] = { + stp: SendToPeer + ): Future[NodeRunningState] = { val peerMsgSenderOpt = stp.peerOpt match { case Some(p) => state.getPeerMsgSender(p) @@ -820,8 +883,10 @@ case class PeerManager( case s: SyncNodeState => Some(s.syncPeerMessageSender) case x @ (_: DoneSyncing | _: MisbehavingPeer | _: NodeShuttingDown | _: RemovePeers) => - x.randomPeerMessageSender(Set.empty, - ServiceIdentifier.NODE_COMPACT_FILTERS) + x.randomPeerMessageSender( + Set.empty, + ServiceIdentifier.NODE_COMPACT_FILTERS + ) } } @@ -832,39 +897,45 @@ case class PeerManager( .map(_ => state) case None => logger.warn( - s"Unable to find peer to send message=${stp.msg.payload} to, state=$state") + s"Unable to find peer to send message=${stp.msg.payload} to, state=$state" + ) Future.successful(state) } } private def switchSyncToPeer( oldSyncState: SyncNodeState, - newPeer: Peer): Future[Option[SyncNodeState]] = { + newPeer: Peer + ): Future[Option[SyncNodeState]] = { logger.debug( - s"switchSyncToPeer() oldSyncState=$oldSyncState newPeer=$newPeer") + s"switchSyncToPeer() oldSyncState=$oldSyncState newPeer=$newPeer" + ) val newState = oldSyncState.replaceSyncPeer(newPeer) newState match { case s: HeaderSync => if (s.syncPeer != newPeer) { syncHelper(s) } else { - //if its same peer we don't need to switch + // if its same peer we don't need to switch Future.successful(Some(oldSyncState)) } case fofhs: FilterOrFilterHeaderSync => if (oldSyncState.syncPeer != newPeer) { startFilterSync(chainApi = ChainHandler.fromDatabase(), fofhs = fofhs) } else { - //if its same peer we don't need to switch + // if its same peer we don't need to switch Future.successful(Some(fofhs)) } } } - /** If [[syncPeerOpt]] is given, we send getheaders to only that peer, if no sync peer given we gossip getheaders to all our peers */ + /** If [[syncPeerOpt]] is given, we send getheaders to only that peer, if no + * sync peer given we gossip getheaders to all our peers + */ private def getHeaderSyncHelper( - headerSync: HeaderSync): Future[HeaderSync] = { + headerSync: HeaderSync + ): Future[HeaderSync] = { val blockchainsF = BlockHeaderDAO()(ec, chainAppConfig).getBlockchains() @@ -877,11 +948,13 @@ case class PeerManager( } yield headerSync } - /** Starts a filter header or filter sync is necesssary. Returns None if no sync is started */ + /** Starts a filter header or filter sync is necesssary. Returns None if no + * sync is started + */ def startFilterSync( chainApi: ChainApi, - fofhs: FilterOrFilterHeaderSync): Future[ - Option[FilterOrFilterHeaderSync]] = { + fofhs: FilterOrFilterHeaderSync + ): Future[Option[FilterOrFilterHeaderSync]] = { for { header <- chainApi.getBestBlockHeader() bestFilterHeaderOpt <- chainApi.getBestFilterHeader() @@ -890,8 +963,8 @@ case class PeerManager( hasStaleTip <- chainApi.isTipStale() resultOpt <- { if (hasStaleTip) { - //if we have a stale tip, we will request to sync filter headers / filters - //after we are done syncing block headers + // if we have a stale tip, we will request to sync filter headers / filters + // after we are done syncing block headers Future.successful(None) } else { syncFilters( @@ -913,14 +986,19 @@ case class PeerManager( /** Helper method to sync the blockchain over the network * - * @param syncNodeState the state we should attempt to sync with - * @return None if we did not start a sync attempt, else the new [[SyncNodeState]] corresponding with our new sync + * @param syncNodeState + * the state we should attempt to sync with + * @return + * None if we did not start a sync attempt, else the new [[SyncNodeState]] + * corresponding with our new sync */ private def syncHelper( - syncNodeState: SyncNodeState): Future[Option[SyncNodeState]] = { + syncNodeState: SyncNodeState + ): Future[Option[SyncNodeState]] = { val syncPeer = syncNodeState.syncPeer logger.debug( - s"syncHelper() syncNodeState=$syncNodeState isStarted.get=${isStarted.get}") + s"syncHelper() syncNodeState=$syncNodeState isStarted.get=${isStarted.get}" + ) val chainApi: ChainApi = ChainHandler.fromDatabase() val syncF = chainApi.setSyncing(true) val resultF: Future[Option[SyncNodeState]] = syncNodeState match { @@ -938,29 +1016,34 @@ case class PeerManager( result <- resultF } yield { logger.info( - s"Starting sync node, height=${header.height} hash=${header.hashBE.hex} filterHeaderCount=$filterHeaderCount filterCount=$filterCount syncPeer=$syncPeer") + s"Starting sync node, height=${header.height} hash=${header.hashBE.hex} filterHeaderCount=$filterHeaderCount filterCount=$filterCount syncPeer=$syncPeer" + ) result } } - /** Returns true if filter are in sync with their old counts, but out of sync with our block count */ + /** Returns true if filter are in sync with their old counts, but out of sync + * with our block count + */ private def syncFilters( bestFilterHeaderOpt: Option[CompactFilterHeaderDb], bestFilterOpt: Option[CompactFilterDb], bestBlockHeader: BlockHeaderDb, chainApi: ChainApi, - fofhs: FilterOrFilterHeaderSync): Future[ - Option[FilterOrFilterHeaderSync]] = { + fofhs: FilterOrFilterHeaderSync + ): Future[Option[FilterOrFilterHeaderSync]] = { val isTipStaleF = chainApi.isTipStale() isTipStaleF.flatMap { isTipStale => if (isTipStale) { logger.error( - s"Cannot start syncing filters while blockchain tip is stale") + s"Cannot start syncing filters while blockchain tip is stale" + ) Future.successful(None) } else { logger.debug( - s"syncFilters() bestBlockHeader=$bestBlockHeader bestFilterHeaderOpt=$bestFilterHeaderOpt bestFilterOpt=$bestFilterOpt state=$fofhs") + s"syncFilters() bestBlockHeader=$bestBlockHeader bestFilterHeaderOpt=$bestFilterHeaderOpt bestFilterOpt=$bestFilterOpt state=$fofhs" + ) // If we have started syncing filters headers (bestFilterHeaderOpt, bestFilterOpt) match { case (None, None) | (None, Some(_)) => @@ -973,10 +1056,12 @@ case class PeerManager( peerMessageSenderApi = peerMsgSender, chainApi = chainApi, stopBlockHeaderDb = bestBlockHeader, - state = fhs) + state = fhs + ) case x @ (_: FilterSync) => val exn = new RuntimeException( - s"Invalid state to start syncing filter headers with, got=$x") + s"Invalid state to start syncing filter headers with, got=$x" + ) Future.failed(exn) } @@ -984,36 +1069,40 @@ case class PeerManager( val isFilterHeaderSynced = bestFilterHeader.blockHashBE == bestBlockHeader.hashBE val isFiltersSynced = { - //check if we have started syncing filters, - //and if so, see if filter headers and filters - //were in sync + // check if we have started syncing filters, + // and if so, see if filter headers and filters + // were in sync bestFilter.hashBE == bestFilterHeader.filterHashBE } if (isFilterHeaderSynced && isFiltersSynced) { - //means we are in sync, with filter heads & block headers & filters - //if there _both_ filter headers and block headers are on - //an old tip, our event driven node will start syncing - //filters after block headers are in sync - //do nothing + // means we are in sync, with filter heads & block headers & filters + // if there _both_ filter headers and block headers are on + // an old tip, our event driven node will start syncing + // filters after block headers are in sync + // do nothing Future.successful(None) } else { - syncCompactFilters(bestFilterHeader = bestFilterHeader, - chainApi = chainApi, - compactFilterStartHeightOpt = None, - syncNodeState = fofhs) + syncCompactFilters( + bestFilterHeader = bestFilterHeader, + chainApi = chainApi, + compactFilterStartHeightOpt = None, + syncNodeState = fofhs + ) } case (Some(bestFilterHeader), None) => val compactFilterStartHeightOptF = - PeerManager.getCompactFilterStartHeight(chainApi, - walletCreationTimeOpt) + PeerManager.getCompactFilterStartHeight( + chainApi, + walletCreationTimeOpt + ) for { compactFilterStartHeightOpt <- compactFilterStartHeightOptF - resultOpt <- syncCompactFilters(bestFilterHeader = - bestFilterHeader, - chainApi = chainApi, - compactFilterStartHeightOpt = - compactFilterStartHeightOpt, - syncNodeState = fofhs) + resultOpt <- syncCompactFilters( + bestFilterHeader = bestFilterHeader, + chainApi = chainApi, + compactFilterStartHeightOpt = compactFilterStartHeightOpt, + syncNodeState = fofhs + ) } yield resultOpt } @@ -1021,9 +1110,12 @@ case class PeerManager( } } - /** Attempts to start syncing from a new peer. Returns None if we have no new peers to sync with */ + /** Attempts to start syncing from a new peer. Returns None if we have no new + * peers to sync with + */ private def syncFromNewPeer( - state: NodeRunningState): Future[Option[NodeRunningState]] = { + state: NodeRunningState + ): Future[Option[NodeRunningState]] = { val svcIdentifier = ServiceIdentifier.NODE_COMPACT_FILTERS val syncPeerOpt = state match { case s: SyncNodeState => @@ -1057,10 +1149,13 @@ case class PeerManager( newStateOptF } - /** Gossips the given message to all peers except the excluded peer. If None given as excluded peer, gossip message to all peers */ + /** Gossips the given message to all peers except the excluded peer. If None + * given as excluded peer, gossip message to all peers + */ override def gossipMessage( msg: NetworkPayload, - excludedPeerOpt: Option[Peer]): Future[Unit] = { + excludedPeerOpt: Option[Peer] + ): Future[Unit] = { val m = NetworkMessage(chainAppConfig.network, msg) queue .offer(GossipMessage(m, excludedPeerOpt)) @@ -1068,7 +1163,8 @@ case class PeerManager( } override def gossipGetHeadersMessage( - hashes: Vector[DoubleSha256DigestBE]): Future[Unit] = { + hashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] = { val headersMsg = GetHeadersMessage(hashes.distinct.take(101).map(_.flip)) gossipMessage(msg = headersMsg, excludedPeerOpt = None) } @@ -1086,18 +1182,19 @@ case class ResponseTimeout(payload: NetworkPayload) object PeerManager extends BitcoinSLogger { - /** Sends first getcfheader message. - * Returns None if are our filter headers are in sync with our block headers or - * if the peer we are attempting to send messages to does not support block filters + /** Sends first getcfheader message. Returns None if are our filter headers + * are in sync with our block headers or if the peer we are attempting to + * send messages to does not support block filters */ def sendFirstGetCompactFilterHeadersCommand( peerMessageSenderApi: PeerMessageSenderApi, chainApi: ChainApi, stopBlockHeaderDb: BlockHeaderDb, - state: FilterHeaderSync)(implicit + state: FilterHeaderSync + )(implicit ec: ExecutionContext, - chainConfig: ChainAppConfig): Future[ - Option[NodeState.FilterHeaderSync]] = { + chainConfig: ChainAppConfig + ): Future[Option[NodeState.FilterHeaderSync]] = { val peer = peerMessageSenderApi.peer if (state.services.nodeCompactFilters) { for { @@ -1106,14 +1203,14 @@ object PeerManager extends BitcoinSLogger { .getBestFilterHeader() blockHash = bestFilterHeaderOpt match { case Some(filterHeaderDb) => - //need to check for reorg scenarios here + // need to check for reorg scenarios here val isSameHeight = filterHeaderDb.height == stopBlockHeaderDb.height val isNotSameBlockHash = filterHeaderDb.blockHashBE != stopBlockHeaderDb.hashBE if (isSameHeight && isNotSameBlockHash) { - //need to start from previous header has to sync filter headers - //correctly in a reorg scenario + // need to start from previous header has to sync filter headers + // correctly in a reorg scenario stopBlockHeaderDb.previousBlockHashBE } else { filterHeaderDb.blockHashBE @@ -1126,10 +1223,11 @@ object PeerManager extends BitcoinSLogger { chainApi.nextBlockHeaderBatchRange( prevStopHash = blockHash, stopHash = stopBlockHeaderDb.hashBE, - batchSize = chainConfig.filterHeaderBatchSize) + batchSize = chainConfig.filterHeaderBatchSize + ) } - //needed to work around this bug in bitcoin core: - //https://github.com/bitcoin/bitcoin/issues/27085 + // needed to work around this bug in bitcoin core: + // https://github.com/bitcoin/bitcoin/issues/27085 _ <- AsyncUtil.nonBlockingSleep(1.second) res <- hashHeightOpt match { case Some(filterSyncMarker) => @@ -1138,13 +1236,15 @@ object PeerManager extends BitcoinSLogger { .map(_ => Some(state)) case None => logger.info( - s"Filter headers are synced! filterHeader.blockHashBE=$blockHash") + s"Filter headers are synced! filterHeader.blockHashBE=$blockHash" + ) Future.successful(None) } } yield res } else { logger.debug( - s"Cannot send compact filter messages to peer=$peer as it does not support compact filters") + s"Cannot send compact filter messages to peer=$peer as it does not support compact filters" + ) Future.successful(None) } @@ -1155,18 +1255,20 @@ object PeerManager extends BitcoinSLogger { chainApi: ChainApi, filterHeaderBatchSize: Int, prevStopHash: DoubleSha256DigestBE, - stopHash: DoubleSha256DigestBE)(implicit - ec: ExecutionContext): Future[Boolean] = { + stopHash: DoubleSha256DigestBE + )(implicit ec: ExecutionContext): Future[Boolean] = { val peer = peerMessageSenderApi.peer for { filterSyncMarkerOpt <- chainApi.nextBlockHeaderBatchRange( prevStopHash = prevStopHash, stopHash = stopHash, - batchSize = filterHeaderBatchSize) + batchSize = filterHeaderBatchSize + ) res <- filterSyncMarkerOpt match { case Some(filterSyncMarker) => logger.debug( - s"Requesting next compact filter headers from $filterSyncMarker with peer=$peer") + s"Requesting next compact filter headers from $filterSyncMarker with peer=$peer" + ) peerMessageSenderApi .sendGetCompactFilterHeadersMessage(filterSyncMarker) .map(_ => true) @@ -1176,7 +1278,8 @@ object PeerManager extends BitcoinSLogger { } yield res } - /** @return a flag indicating if we are syncing or not + /** @return + * a flag indicating if we are syncing or not */ def sendNextGetCompactFilterCommand( peerMessageSenderApi: PeerMessageSenderApi, @@ -1184,16 +1287,20 @@ object PeerManager extends BitcoinSLogger { filterBatchSize: Int, startHeightOpt: Option[Int], stopBlockHash: DoubleSha256DigestBE, - peer: Peer)(implicit ec: ExecutionContext): Future[Boolean] = { + peer: Peer + )(implicit ec: ExecutionContext): Future[Boolean] = { for { filterSyncMarkerOpt <- - chainApi.nextFilterHeaderBatchRange(stopBlockHash = stopBlockHash, - batchSize = filterBatchSize, - startHeightOpt = startHeightOpt) + chainApi.nextFilterHeaderBatchRange( + stopBlockHash = stopBlockHash, + batchSize = filterBatchSize, + startHeightOpt = startHeightOpt + ) res <- filterSyncMarkerOpt match { case Some(filterSyncMarker) => logger.debug( - s"Requesting compact filters from with peer=$peer stopBlockHashBE=${filterSyncMarker.stopBlockHashBE.hex}") + s"Requesting compact filters from with peer=$peer stopBlockHashBE=${filterSyncMarker.stopBlockHashBE.hex}" + ) peerMessageSenderApi .sendGetCompactFiltersMessage(filterSyncMarker) .map(_ => true) @@ -1207,16 +1314,18 @@ object PeerManager extends BitcoinSLogger { state: FilterHeaderSync, chainApi: ChainApi, peerMessageSenderApi: PeerMessageSenderApi, - stopBlockHeaderDb: BlockHeaderDb)(implicit + stopBlockHeaderDb: BlockHeaderDb + )(implicit ec: ExecutionContext, - chainAppConfig: ChainAppConfig): Future[ - Option[NodeState.FilterHeaderSync]] = { + chainAppConfig: ChainAppConfig + ): Future[Option[NodeState.FilterHeaderSync]] = { for { newSyncingStateOpt <- PeerManager.sendFirstGetCompactFilterHeadersCommand( peerMessageSenderApi = peerMessageSenderApi, chainApi = chainApi, stopBlockHeaderDb = stopBlockHeaderDb, - state = state) + state = state + ) } yield { newSyncingStateOpt } @@ -1227,25 +1336,30 @@ object PeerManager extends BitcoinSLogger { oldFilterHeaderCount: Int, currentFilterHeaderCount: Int, oldFilterCount: Int, - currentFilterCount: Int): Boolean = { + currentFilterCount: Int + ): Boolean = { (oldFilterHeaderCount == currentFilterHeaderCount && oldFilterCount == currentFilterCount) && (blockCount != currentFilterHeaderCount || blockCount != currentFilterCount) } - /** Return the starting point for first sync of compact filters from the network + /** Return the starting point for first sync of compact filters from the + * network * * @param chainApi - * @param walletCreationTimeOpt the time the wallet was created, we will start syncing form this point if given + * @param walletCreationTimeOpt + * the time the wallet was created, we will start syncing form this point + * if given * @param ec - * @return the start height for compact filters + * @return + * the start height for compact filters */ def getCompactFilterStartHeight( chainApi: ChainApi, - walletCreationTimeOpt: Option[Instant])(implicit - ec: ExecutionContext): Future[Option[Int]] = { + walletCreationTimeOpt: Option[Instant] + )(implicit ec: ExecutionContext): Future[Option[Int]] = { chainApi.getBestFilter().flatMap { case Some(_) => - //we have already started syncing filters, return the height of the last filter seen + // we have already started syncing filters, return the height of the last filter seen Future.successful(None) case None => walletCreationTimeOpt match { @@ -1257,13 +1371,13 @@ object PeerManager extends BitcoinSLogger { creationTimeHeight <- creationTimeHeightF filterCount <- filterCountF } yield { - //filterHeightOpt contains the height of the last filter of the last batch - //so if we want to start syncing filters from the correct height we need to - //decrease the computed height + // filterHeightOpt contains the height of the last filter of the last batch + // so if we want to start syncing filters from the correct height we need to + // decrease the computed height val height = Math.max(0, creationTimeHeight - 1) - //want to choose the maximum out of these too - //if our internal chainstate filter count is > creationTimeHeight - //we just want to start syncing from our last seen filter + // want to choose the maximum out of these too + // if our internal chainstate filter count is > creationTimeHeight + // we just want to start syncing from our last seen filter val result = Math.max(height, filterCount) Some(result) } @@ -1273,17 +1387,18 @@ object PeerManager extends BitcoinSLogger { } } - def handleHealthCheck(runningState: NodeRunningState)(implicit - nodeAppConfig: NodeAppConfig): Future[NodeRunningState] = { + def handleHealthCheck( + runningState: NodeRunningState + )(implicit nodeAppConfig: NodeAppConfig): Future[NodeRunningState] = { val blockFilterPeers = runningState.peerDataMap.filter(_._2.serviceIdentifier.nodeCompactFilters) val slotsFull = blockFilterPeers.size == nodeAppConfig.maxConnectedPeers if (runningState.peerDataMap.nonEmpty && slotsFull) { - //do nothing + // do nothing Future.successful(runningState) } else { - //keep querying for block filter peers until our connection - //slots are full of block filter peers + // keep querying for block filter peers until our connection + // slots are full of block filter peers val peerFinder = runningState.peerFinder peerFinder.queryForPeerConnections(excludePeers = Set.empty) Future.successful(runningState) diff --git a/node/src/main/scala/org/bitcoins/node/callback/NodeCallbackStreamManager.scala b/node/src/main/scala/org/bitcoins/node/callback/NodeCallbackStreamManager.scala index 7a8180544a..d6b8909214 100644 --- a/node/src/main/scala/org/bitcoins/node/callback/NodeCallbackStreamManager.scala +++ b/node/src/main/scala/org/bitcoins/node/callback/NodeCallbackStreamManager.scala @@ -25,21 +25,23 @@ import scala.concurrent.{ExecutionContext, Future} case class NodeCallbackStreamManager( callbacks: NodeCallbacks, overflowStrategy: OverflowStrategy = OverflowStrategy.backpressure, - maxBufferSize: Int = 16)(implicit system: ActorSystem) + maxBufferSize: Int = 16 +)(implicit system: ActorSystem) extends NodeCallbacks with StartStopAsync[Unit] with BitcoinSLogger { import system.dispatcher private val filterQueueSource: Source[ - Vector[(DoubleSha256DigestBE, GolombFilter)], + Vector[ + (DoubleSha256DigestBE, GolombFilter) + ], SourceQueueWithComplete[Vector[(DoubleSha256DigestBE, GolombFilter)]]] = { Source.queue(maxBufferSize, overflowStrategy) } - private val filterSink: Sink[ - Vector[(DoubleSha256DigestBE, GolombFilter)], - Future[Done]] = { + private val filterSink + : Sink[Vector[(DoubleSha256DigestBE, GolombFilter)], Future[Done]] = { Sink.foreachAsync(1) { case vec => callbacks.executeOnCompactFiltersReceivedCallbacks(vec) } @@ -48,9 +50,8 @@ case class NodeCallbackStreamManager( private val (filterQueue, filterSinkCompleteF) = matSourceAndQueue(filterQueueSource, filterSink) - private val txQueueSource: Source[ - Transaction, - SourceQueueWithComplete[Transaction]] = { + private val txQueueSource + : Source[Transaction, SourceQueueWithComplete[Transaction]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -63,9 +64,11 @@ case class NodeCallbackStreamManager( private val (txQueue, txSinkCompleteF) = matSourceAndQueue(txQueueSource, txSink) - private val headerQueueSource: Source[ - Vector[BlockHeader], - SourceQueueWithComplete[Vector[BlockHeader]]] = { + private val headerQueueSource + : Source[Vector[ + BlockHeader + ], + SourceQueueWithComplete[Vector[BlockHeader]]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -78,9 +81,8 @@ case class NodeCallbackStreamManager( private val (headerQueue, headerSinkCompleteF) = matSourceAndQueue(headerQueueSource, headerSink) - private val blockQueueSource: Source[ - Block, - SourceQueueWithComplete[Block]] = { + private val blockQueueSource + : Source[Block, SourceQueueWithComplete[Block]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -93,18 +95,21 @@ case class NodeCallbackStreamManager( private val (blockQueue, blockSinkCompleteF) = matSourceAndQueue(blockQueueSource, blockSink) - private val merkleBlockQueueSource: Source[ - (MerkleBlock, Vector[Transaction]), - SourceQueueWithComplete[(MerkleBlock, Vector[Transaction])]] = { + private val merkleBlockQueueSource + : Source[(MerkleBlock, Vector[Transaction]), + SourceQueueWithComplete[ + (MerkleBlock, Vector[Transaction]) + ]] = { Source.queue(maxBufferSize, overflowStrategy) } - private val merkleBlockSink: Sink[ - (MerkleBlock, Vector[Transaction]), - Future[Done]] = { + private val merkleBlockSink + : Sink[(MerkleBlock, Vector[Transaction]), Future[Done]] = { Sink.foreachAsync(1) { case tuple => - callbacks.executeOnMerkleBlockReceivedCallbacks(merkleBlock = tuple._1, - txs = tuple._2) + callbacks.executeOnMerkleBlockReceivedCallbacks( + merkleBlock = tuple._1, + txs = tuple._2 + ) } } @@ -119,9 +124,9 @@ case class NodeCallbackStreamManager( override def stop(): Future[Unit] = { val start = System.currentTimeMillis() - //can't complete a stream twice + // can't complete a stream twice if (!isStopped.get()) { - //complete all queues + // complete all queues filterQueue.complete() txQueue.complete() headerQueue.complete() @@ -130,7 +135,8 @@ case class NodeCallbackStreamManager( isStopped.set(true) } else { logger.warn( - s"Already stopped all queues associated with this NodeCallBackStreamManager") + s"Already stopped all queues associated with this NodeCallBackStreamManager" + ) } for { @@ -142,24 +148,26 @@ case class NodeCallbackStreamManager( } yield { logger.info( s"Done draining akka streams for NodeCallbackStreamManager, it took=${System - .currentTimeMillis() - start}ms") + .currentTimeMillis() - start}ms" + ) () } } private def matSourceAndQueue[T]( source: Source[T, SourceQueueWithComplete[T]], - sink: Sink[T, Future[Done]]): ( - SourceQueueWithComplete[T], - Future[Done]) = { + sink: Sink[T, Future[Done]] + ): (SourceQueueWithComplete[T], Future[Done]) = { source .toMat(sink)(Keep.both) .run() } - override def onCompactFiltersReceived: CallbackHandler[ - Vector[(DoubleSha256DigestBE, GolombFilter)], - OnCompactFiltersReceived] = { + override def onCompactFiltersReceived + : CallbackHandler[Vector[ + (DoubleSha256DigestBE, GolombFilter) + ], + OnCompactFiltersReceived] = { callbacks.onCompactFiltersReceived } @@ -172,29 +180,32 @@ case class NodeCallbackStreamManager( override def onMerkleBlockReceived: CallbackHandler[ (MerkleBlock, Vector[Transaction]), - OnMerkleBlockReceived] = callbacks.onMerkleBlockReceived + OnMerkleBlockReceived + ] = callbacks.onMerkleBlockReceived - override def onBlockHeadersReceived: CallbackHandler[ - Vector[BlockHeader], - OnBlockHeadersReceived] = callbacks.onBlockHeadersReceived + override def onBlockHeadersReceived + : CallbackHandler[Vector[BlockHeader], OnBlockHeadersReceived] = + callbacks.onBlockHeadersReceived - override def executeOnTxReceivedCallbacks(tx: Transaction)(implicit - ec: ExecutionContext): Future[Unit] = { + override def executeOnTxReceivedCallbacks( + tx: Transaction + )(implicit ec: ExecutionContext): Future[Unit] = { txQueue .offer(tx) .map(_ => ()) } - override def executeOnBlockReceivedCallbacks(block: Block)(implicit - ec: ExecutionContext): Future[Unit] = { + override def executeOnBlockReceivedCallbacks( + block: Block + )(implicit ec: ExecutionContext): Future[Unit] = { blockQueue .offer(block) .map(_ => ()) } override def executeOnCompactFiltersReceivedCallbacks( - blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)])(implicit - ec: ExecutionContext): Future[Unit] = { + blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)] + )(implicit ec: ExecutionContext): Future[Unit] = { filterQueue .offer(blockFilters) .map(_ => ()) @@ -202,15 +213,16 @@ case class NodeCallbackStreamManager( override def executeOnMerkleBlockReceivedCallbacks( merkleBlock: MerkleBlock, - txs: Vector[Transaction])(implicit ec: ExecutionContext): Future[Unit] = { + txs: Vector[Transaction] + )(implicit ec: ExecutionContext): Future[Unit] = { merkleBlockQueue .offer((merkleBlock, txs)) .map(_ => ()) } override def executeOnBlockHeadersReceivedCallbacks( - headers: Vector[BlockHeader])(implicit - ec: ExecutionContext): Future[Unit] = { + headers: Vector[BlockHeader] + )(implicit ec: ExecutionContext): Future[Unit] = { headerQueue .offer(headers) .map(_ => ()) diff --git a/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala b/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala index 034ddc69c4..b5fabb5e0d 100644 --- a/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala +++ b/node/src/main/scala/org/bitcoins/node/config/NodeAppConfig.scala @@ -23,12 +23,14 @@ import scala.concurrent.duration.{DurationInt, FiniteDuration} import scala.concurrent.{ExecutionContext, Future} /** Configuration for the Bitcoin-S node - * @param directory The data directory of the node - * @param confs Optional sequence of configuration overrides + * @param directory + * The data directory of the node + * @param confs + * Optional sequence of configuration overrides */ case class NodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( - implicit val system: ActorSystem) - extends DbAppConfig + implicit val system: ActorSystem +) extends DbAppConfig with NodeDbManagement with JdbcProfileComponent[NodeAppConfig] with CallbackConfig[NodeCallbacks] { @@ -36,7 +38,8 @@ case class NodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( override protected[bitcoins] type ConfigType = NodeAppConfig override protected[bitcoins] def newConfigOfType( - configs: Vector[Config]): NodeAppConfig = + configs: Vector[Config] + ): NodeAppConfig = NodeAppConfig(baseDatadir, configs) implicit override def ec: ExecutionContext = system.dispatcher @@ -45,8 +48,8 @@ case class NodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( override lazy val callbackFactory: NodeCallbacks.type = NodeCallbacks - /** Ensures correct tables and other required information is in - * place for our node. + /** Ensures correct tables and other required information is in place for our + * node. */ override def start(): Future[Unit] = { for { @@ -72,7 +75,7 @@ case class NodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( logger.info(s"Initializing node setup") val numMigrations = migrate() val _ = if (isHikariLoggingEnabled) { - //.get is safe because hikari logging is enabled + // .get is safe because hikari logging is enabled startHikariLogger(hikariLoggingInterval.get) () } else { @@ -151,7 +154,9 @@ case class NodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( } else 12.hour } - /** timeout to wait for response the messages extend [[org.bitcoins.core.p2p.ExpectsResponse]] */ + /** timeout to wait for response the messages extend + * [[org.bitcoins.core.p2p.ExpectsResponse]] + */ lazy val queryWaitTime: FiniteDuration = { if (config.hasPath("bitcoin-s.node.query-wait-time")) { val duration = config.getDuration("bitcoin-s.node.query-wait-time") @@ -159,7 +164,8 @@ case class NodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( } else 120.seconds } - /** maximum consecutive number of invalid responses allowed from the same peer */ + /** maximum consecutive number of invalid responses allowed from the same peer + */ lazy val maxInvalidResponsesAllowed: Int = { if (config.hasPath("bitcoin-s.node.max-invalid-response-count")) { config.getInt("bitcoin-s.node.max-invalid-response-count") @@ -188,13 +194,18 @@ case class NodeAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( } else 5.minute } - /** Creates either a neutrino node or a spv node based on the [[NodeAppConfig]] given */ - def createNode(peers: Vector[Peer], walletCreationTimeOpt: Option[Instant])( - chainConf: ChainAppConfig, - system: ActorSystem): Future[Node] = { - NodeAppConfig.createNode(peers, walletCreationTimeOpt)(this, - chainConf, - system) + /** Creates either a neutrino node or a spv node based on the + * [[NodeAppConfig]] given + */ + def createNode( + peers: Vector[Peer], + walletCreationTimeOpt: Option[Instant] + )(chainConf: ChainAppConfig, system: ActorSystem): Future[Node] = { + NodeAppConfig.createNode(peers, walletCreationTimeOpt)( + this, + chainConf, + system + ) } } @@ -202,27 +213,33 @@ object NodeAppConfig extends AppConfigFactoryActorSystem[NodeAppConfig] { override val moduleName: String = "node" - /** Constructs a node configuration from the default Bitcoin-S - * data directory and given list of configuration overrides. + /** Constructs a node configuration from the default Bitcoin-S data directory + * and given list of configuration overrides. */ override def fromDatadir(datadir: Path, confs: Vector[Config])(implicit - system: ActorSystem): NodeAppConfig = + system: ActorSystem + ): NodeAppConfig = NodeAppConfig(datadir, confs) - /** Creates either a neutrino node or a spv node based on the [[NodeAppConfig]] given */ + /** Creates either a neutrino node or a spv node based on the + * [[NodeAppConfig]] given + */ def createNode(peers: Vector[Peer], walletCreationTimeOpt: Option[Instant])( implicit nodeConf: NodeAppConfig, chainConf: ChainAppConfig, - system: ActorSystem): Future[Node] = { + system: ActorSystem + ): Future[Node] = { nodeConf.nodeType match { case NodeType.NeutrinoNode => - val n = NeutrinoNode(walletCreationTimeOpt, - nodeConf, - chainConf, - system, - paramPeers = peers) + val n = NeutrinoNode( + walletCreationTimeOpt, + nodeConf, + chainConf, + system, + paramPeers = peers + ) Future.successful(n) case NodeType.FullNode => Future.failed(new RuntimeException("Not implemented")) diff --git a/node/src/main/scala/org/bitcoins/node/models/BroadcastAbleTransactionDAO.scala b/node/src/main/scala/org/bitcoins/node/models/BroadcastAbleTransactionDAO.scala index f15021ffca..5fb104ab73 100644 --- a/node/src/main/scala/org/bitcoins/node/models/BroadcastAbleTransactionDAO.scala +++ b/node/src/main/scala/org/bitcoins/node/models/BroadcastAbleTransactionDAO.scala @@ -11,8 +11,8 @@ import scala.concurrent.{ExecutionContext, Future} final case class BroadcastAbleTransactionDAO()(implicit override val appConfig: NodeAppConfig, - override val ec: ExecutionContext) - extends CRUD[BroadcastAbleTransaction, DoubleSha256DigestBE] + override val ec: ExecutionContext +) extends CRUD[BroadcastAbleTransaction, DoubleSha256DigestBE] with SlickUtil[BroadcastAbleTransaction, DoubleSha256DigestBE] { import profile.api._ @@ -22,30 +22,32 @@ final case class BroadcastAbleTransactionDAO()(implicit override val table: profile.api.TableQuery[BroadcastAbleTransactionTable] = profile.api.TableQuery[BroadcastAbleTransactionTable] - override def createAll(ts: Vector[BroadcastAbleTransaction]): Future[ - Vector[BroadcastAbleTransaction]] = createAllNoAutoInc(ts, safeDatabase) + override def createAll( + ts: Vector[BroadcastAbleTransaction] + ): Future[Vector[BroadcastAbleTransaction]] = + createAllNoAutoInc(ts, safeDatabase) /** Finds the rows that correlate to the given primary keys */ override protected def findByPrimaryKeys( - txIds: Vector[DoubleSha256DigestBE]): Query[ - BroadcastAbleTransactionTable, - BroadcastAbleTransaction, - Seq] = { + txIds: Vector[DoubleSha256DigestBE] + ): Query[BroadcastAbleTransactionTable, BroadcastAbleTransaction, Seq] = { table.filter(_.txid.inSet(txIds)) } - override protected def findAll(ts: Vector[BroadcastAbleTransaction]): Query[ - BroadcastAbleTransactionTable, - BroadcastAbleTransaction, - Seq] = findByPrimaryKeys(ts.map(_.transaction.txIdBE)) + override protected def findAll( + ts: Vector[BroadcastAbleTransaction] + ): Query[BroadcastAbleTransactionTable, BroadcastAbleTransaction, Seq] = + findByPrimaryKeys(ts.map(_.transaction.txIdBE)) def findByHash( - hash: DoubleSha256DigestBE): Future[Option[BroadcastAbleTransaction]] = + hash: DoubleSha256DigestBE + ): Future[Option[BroadcastAbleTransaction]] = findByHash(hash.flip) /** Searches for a TX by its TXID */ def findByHash( - hash: DoubleSha256Digest): Future[Option[BroadcastAbleTransaction]] = { + hash: DoubleSha256Digest + ): Future[Option[BroadcastAbleTransaction]] = { val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) import mappers._ @@ -55,9 +57,11 @@ final case class BroadcastAbleTransactionDAO()(implicit /** Table over TXs we can broadcast over the P2P network */ class BroadcastAbleTransactionTable(tag: Tag) - extends Table[BroadcastAbleTransaction](tag, - schemaName, - "broadcast_elements") { + extends Table[BroadcastAbleTransaction]( + tag, + schemaName, + "broadcast_elements" + ) { private type Tuple = (DoubleSha256DigestBE, ByteVector) private val fromTuple: Tuple => BroadcastAbleTransaction = { diff --git a/node/src/main/scala/org/bitcoins/node/models/NodeStateDescriptorDAO.scala b/node/src/main/scala/org/bitcoins/node/models/NodeStateDescriptorDAO.scala index 9cdaff5e51..e22b77dd8a 100644 --- a/node/src/main/scala/org/bitcoins/node/models/NodeStateDescriptorDAO.scala +++ b/node/src/main/scala/org/bitcoins/node/models/NodeStateDescriptorDAO.scala @@ -14,14 +14,15 @@ import scala.concurrent.{ExecutionContext, Future} case class NodeStateDescriptorDb( tpe: NodeStateDescriptorType, - descriptor: NodeStateDescriptor) { + descriptor: NodeStateDescriptor +) { require(descriptor.descriptorType == tpe) } case class NodeStateDescriptorDAO()(implicit override val ec: ExecutionContext, - override val appConfig: NodeAppConfig) - extends CRUD[NodeStateDescriptorDb, NodeStateDescriptorType] + override val appConfig: NodeAppConfig +) extends CRUD[NodeStateDescriptorDb, NodeStateDescriptorType] with SlickUtil[NodeStateDescriptorDb, NodeStateDescriptorType] { import profile.api._ private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -30,28 +31,26 @@ case class NodeStateDescriptorDAO()(implicit override val table: profile.api.TableQuery[NodeStateDescriptorTable] = TableQuery[NodeStateDescriptorTable] - override def createAll(ts: Vector[NodeStateDescriptorDb]): Future[ - Vector[NodeStateDescriptorDb]] = + override def createAll( + ts: Vector[NodeStateDescriptorDb] + ): Future[Vector[NodeStateDescriptorDb]] = createAllNoAutoInc(ts, safeDatabase) - override def findByPrimaryKeys(ids: Vector[NodeStateDescriptorType]): Query[ - NodeStateDescriptorTable, - NodeStateDescriptorDb, - Seq] = { + override def findByPrimaryKeys( + ids: Vector[NodeStateDescriptorType] + ): Query[NodeStateDescriptorTable, NodeStateDescriptorDb, Seq] = { table.filter(_.tpe.inSet(ids)) } - override def findByPrimaryKey(id: NodeStateDescriptorType): Query[ - Table[NodeStateDescriptorDb], - NodeStateDescriptorDb, - Seq] = { + override def findByPrimaryKey( + id: NodeStateDescriptorType + ): Query[Table[NodeStateDescriptorDb], NodeStateDescriptorDb, Seq] = { table.filter(_.tpe === id) } - override def findAll(ts: Vector[NodeStateDescriptorDb]): Query[ - Table[NodeStateDescriptorDb], - NodeStateDescriptorDb, - Seq] = + override def findAll( + ts: Vector[NodeStateDescriptorDb] + ): Query[Table[NodeStateDescriptorDb], NodeStateDescriptorDb, Seq] = findByPrimaryKeys(ts.map(_.tpe)) // def setWalletName(walletName: Option[String]): Future[Unit] = { @@ -88,8 +87,10 @@ case class NodeStateDescriptorDAO()(implicit def descriptor: Rep[NodeStateDescriptor] = column("descriptor") override def * : ProvenShape[NodeStateDescriptorDb] = - (tpe, descriptor).<>(NodeStateDescriptorDb.tupled, - NodeStateDescriptorDb.unapply) + (tpe, descriptor).<>( + NodeStateDescriptorDb.tupled, + NodeStateDescriptorDb.unapply + ) } } diff --git a/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala b/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala index 180040a4a0..c43e0bbe89 100644 --- a/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala +++ b/node/src/main/scala/org/bitcoins/node/models/PeerDAO.scala @@ -47,14 +47,16 @@ case class PeerDAO()(implicit appConfig: NodeAppConfig, ec: ExecutionContext) createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - ids: Vector[(ByteVector, Int)]): Query[PeerTable, PeerDb, Seq] = { - //from: https://stackoverflow.com/questions/26815913/how-to-do-or-filter-in-slick + ids: Vector[(ByteVector, Int)] + ): Query[PeerTable, PeerDb, Seq] = { + // from: https://stackoverflow.com/questions/26815913/how-to-do-or-filter-in-slick table.filter(r => ids.map(i => r.address === i._1 && r.port === i._2).reduceLeft(_ || _)) } override protected def findAll( - ts: Vector[PeerDb]): Query[Table[PeerDb], PeerDb, Seq] = + ts: Vector[PeerDb] + ): Query[Table[PeerDb], PeerDb, Seq] = findByPrimaryKeys(ts.map(t => (t.address, t.port))) def deleteByKey(address: String): Future[Int] = { @@ -66,7 +68,8 @@ case class PeerDAO()(implicit appConfig: NodeAppConfig, ec: ExecutionContext) /** returns only non onion addresses if tor is disabled, all otherwise */ def findAllWithTorFilter(torEnabled: Boolean): Future[Vector[PeerDb]] = { val q = table.filterIf(!torEnabled)( - _.networkId =!= AddrV2Message.TOR_V3_NETWORK_BYTE) + _.networkId =!= AddrV2Message.TOR_V3_NETWORK_BYTE + ) safeDatabase.run(q.result).map(_.toVector) } @@ -74,26 +77,33 @@ case class PeerDAO()(implicit appConfig: NodeAppConfig, ec: ExecutionContext) address: ByteVector, port: Int, networkId: Byte, - serviceIdentifier: ServiceIdentifier): Future[PeerDb] = { + serviceIdentifier: ServiceIdentifier + ): Future[PeerDb] = { val lastSeen: Instant = Instant.now val existingF = read((address, port)) existingF.flatMap { case Some(value) => upsert( - PeerDb(address, - port, - firstSeen = value.firstSeen, - lastSeen = lastSeen, - networkId = networkId, - serviceBytes = serviceIdentifier.bytes)) + PeerDb( + address, + port, + firstSeen = value.firstSeen, + lastSeen = lastSeen, + networkId = networkId, + serviceBytes = serviceIdentifier.bytes + ) + ) case None => upsert( - PeerDb(address, - port, - firstSeen = Instant.now, - lastSeen = lastSeen, - networkId = networkId, - serviceBytes = serviceIdentifier.bytes)) + PeerDb( + address, + port, + firstSeen = Instant.now, + lastSeen = lastSeen, + networkId = networkId, + serviceBytes = serviceIdentifier.bytes + ) + ) } } @@ -133,7 +143,8 @@ case class PeerDAO()(implicit appConfig: NodeAppConfig, ec: ExecutionContext) def * : ProvenShape[PeerDb] = (address, port, lastSeen, firstSeen, networkId, serviceBytes).<>( PeerDb.tupled, - PeerDb.unapply) + PeerDb.unapply + ) } } diff --git a/node/src/main/scala/org/bitcoins/node/networking/peer/ControlMessageHandler.scala b/node/src/main/scala/org/bitcoins/node/networking/peer/ControlMessageHandler.scala index 99724ae11b..0dd39aa887 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/peer/ControlMessageHandler.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/peer/ControlMessageHandler.scala @@ -13,13 +13,13 @@ import scala.util.{Failure, Success, Try} case class ControlMessageHandler(peerFinder: PeerFinder)(implicit ec: ExecutionContext, - nodeAppConfig: NodeAppConfig) - extends P2PLogger { + nodeAppConfig: NodeAppConfig +) extends P2PLogger { def handleControlPayload( payload: ControlPayload, - peerMsgSenderApi: PeerMessageSenderApi): Future[ - Option[ControlMessageHandlerState]] = { + peerMsgSenderApi: PeerMessageSenderApi + ): Future[Option[ControlMessageHandlerState]] = { val peer = peerMsgSenderApi.peer payload match { @@ -38,8 +38,8 @@ case class ControlMessageHandler(peerFinder: PeerFinder)(implicit .sendPong(ping) .map(_ => None) case SendHeadersMessage => - //we want peers to just send us headers - //we don't want to have to request them manually + // we want peers to just send us headers + // we don't want to have to request them manually peerMsgSenderApi .sendHeadersMessage() .map(_ => None) @@ -74,9 +74,10 @@ case class ControlMessageHandler(peerFinder: PeerFinder)(implicit } val inetAddress = NetworkUtil.parseInetSocketAddress(bytes, networkAddress.port) - val peer = Peer.fromSocket(socket = inetAddress, - socks5ProxyParams = - nodeAppConfig.socks5ProxyParams) + val peer = Peer.fromSocket( + socket = inetAddress, + socks5ProxyParams = nodeAppConfig.socks5ProxyParams + ) val pd = peerFinder.buildPeerData(peer, isPersistent = false) peerFinder.addToTry(Vector(pd), 0) } @@ -86,9 +87,10 @@ case class ControlMessageHandler(peerFinder: PeerFinder)(implicit val services = ServiceIdentifier.fromBytes(addr.services.bytes) val inetAddress = NetworkUtil.parseInetSocketAddress(bytes, port) - val peer = Peer.fromSocket(socket = inetAddress, - socks5ProxyParams = - nodeAppConfig.socks5ProxyParams) + val peer = Peer.fromSocket( + socket = inetAddress, + socks5ProxyParams = nodeAppConfig.socks5ProxyParams + ) val priority = if (services.nodeCompactFilters) 1 else 0 addr match { case IPv4AddrV2Message(_, _, _, _) | IPv6AddrV2Message(_, _, _, _) => diff --git a/node/src/main/scala/org/bitcoins/node/networking/peer/DataMessageHandler.scala b/node/src/main/scala/org/bitcoins/node/networking/peer/DataMessageHandler.scala index 48b3cd9122..6fbcf913f1 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/peer/DataMessageHandler.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/peer/DataMessageHandler.scala @@ -21,25 +21,31 @@ import java.time.Instant import scala.concurrent.{ExecutionContext, Future} import scala.util.control.NonFatal -/** This actor is meant to handle a [[org.bitcoins.core.p2p.DataPayload DataPayload]] - * that a peer to sent to us on the p2p network, for instance, if we a receive a - * [[org.bitcoins.core.p2p.HeadersMessage HeadersMessage]] we should store those headers in our database +/** This actor is meant to handle a + * [[org.bitcoins.core.p2p.DataPayload DataPayload]] that a peer to sent to us + * on the p2p network, for instance, if we a receive a + * [[org.bitcoins.core.p2p.HeadersMessage HeadersMessage]] we should store + * those headers in our database * - * @param currentFilterBatch holds the current batch of filters to be processed, after its size reaches - * chainConfig.filterBatchSize they will be processed and then emptied + * @param currentFilterBatch + * holds the current batch of filters to be processed, after its size reaches + * chainConfig.filterBatchSize they will be processed and then emptied */ case class DataMessageHandler( chainApi: ChainApi, walletCreationTimeOpt: Option[Instant], peerManager: PeerManager, - state: NodeRunningState)(implicit + state: NodeRunningState +)(implicit ec: ExecutionContext, appConfig: NodeAppConfig, - chainConfig: ChainAppConfig) - extends P2PLogger { + chainConfig: ChainAppConfig +) extends P2PLogger { - require(appConfig.nodeType == NodeType.NeutrinoNode, - "DataMessageHandler is meant to be used with NeutrinoNode") + require( + appConfig.nodeType == NodeType.NeutrinoNode, + "DataMessageHandler is meant to be used with NeutrinoNode" + ) private val txDAO = BroadcastAbleTransactionDAO() @@ -49,7 +55,8 @@ case class DataMessageHandler( def handleDataPayload( payload: DataPayload, - peerData: PersistentPeerData): Future[DataMessageHandler] = { + peerData: PersistentPeerData + ): Future[DataMessageHandler] = { state match { case syncState: SyncNodeState => syncState match { @@ -57,15 +64,16 @@ case class DataMessageHandler( val syncPeer = state.syncPeer val isQueryTimedOut = state.isQueryTimedOut(appConfig.queryWaitTime) if (peerData.peer != syncPeer && !isQueryTimedOut) { - //ignore message from peers that we aren't syncing with during IBD + // ignore message from peers that we aren't syncing with during IBD logger.debug( - s"Ignoring message ${payload.commandName} from peer=${peerData.peer} in state=$state because we are syncing with this peer currently. syncPeer=$syncPeer") + s"Ignoring message ${payload.commandName} from peer=${peerData.peer} in state=$state because we are syncing with this peer currently. syncPeer=$syncPeer" + ) Future.successful(this) } else { val dmh = if (isQueryTimedOut) { - //if query is timed out, we need to transition back to DoneSyncing - //to avoid getting stuck in a state when a peer does not respond to us - //see: https://github.com/bitcoin-s/bitcoin-s/issues/5429 + // if query is timed out, we need to transition back to DoneSyncing + // to avoid getting stuck in a state when a peer does not respond to us + // see: https://github.com/bitcoin-s/bitcoin-s/issues/5429 logger.info(s"Query timed out with in state=$state") copy(state = state.toDoneSyncing) } else { @@ -76,7 +84,8 @@ case class DataMessageHandler( resultF.failed.foreach { err => logger.error( s"Failed to handle data payload=${payload} from peer=${peerData.peer} in state=$state errMsg=${err.getMessage}", - err) + err + ) } resultF.recoverWith { case NonFatal(_) => Future.successful(this) @@ -89,7 +98,8 @@ case class DataMessageHandler( resultF.failed.foreach { err => logger.error( s"Failed to handle data payload=${payload} from peer=${peerData.peer} in state=$state errMsg=${err.getMessage}", - err) + err + ) } resultF.recoverWith { case NonFatal(_) => @@ -102,18 +112,23 @@ case class DataMessageHandler( if (badPeer == peerData.peer) { Future.failed( new RuntimeException( - s"Cannot continue processing p2p messages from badPeer=$badPeer")) + s"Cannot continue processing p2p messages from badPeer=$badPeer" + ) + ) } else { - //re-review this, we should probably pattern match on old state so we can continue syncing - //from where we left off? + // re-review this, we should probably pattern match on old state so we can continue syncing + // from where we left off? val d = DoneSyncing(pdm, m.waitingForDisconnection, m.peerFinder) copy(state = d).handleDataPayload(payload, peerData) } case r: RemovePeers => val badPeers = r.peersToRemove if (badPeers.exists(_ == peerData.peer)) { - Future.failed(new RuntimeException( - s"Cannot continue processing p2p messages from peer we were suppose to remove, peer=${peerData.peer}")) + Future.failed( + new RuntimeException( + s"Cannot continue processing p2p messages from peer we were suppose to remove, peer=${peerData.peer}" + ) + ) } else { val d = r.toDoneSyncing copy(state = d).handleDataPayload(payload, peerData) @@ -121,35 +136,40 @@ case class DataMessageHandler( case _: NodeShuttingDown => logger.warn( - s"Ignoring message ${payload.commandName} from peer=${peerData.peer} in state=$state because we are shuttingdown.") + s"Ignoring message ${payload.commandName} from peer=${peerData.peer} in state=$state because we are shuttingdown." + ) Future.successful(this) } } - /** Processes a [[DataPayload]] if our [[NodeState]] is valid. - * We ignore messages from certain peers when we are in initial block download. + /** Processes a [[DataPayload]] if our [[NodeState]] is valid. We ignore + * messages from certain peers when we are in initial block download. */ private def handleDataPayloadValidState( payload: DataPayload, - peerData: PersistentPeerData): Future[DataMessageHandler] = { + peerData: PersistentPeerData + ): Future[DataMessageHandler] = { val peer = peerData.peer val wrappedFuture: Future[Future[DataMessageHandler]] = Future { payload match { case checkpoint: CompactFilterCheckPointMessage => logger.debug( - s"Got ${checkpoint.filterHeaders.size} checkpoints ${checkpoint} from $peer") + s"Got ${checkpoint.filterHeaders.size} checkpoints ${checkpoint} from $peer" + ) for { newChainApi <- chainApi.processCheckpoints( checkpoint.filterHeaders.map(_.flip), - checkpoint.stopHash.flip) + checkpoint.stopHash.flip + ) } yield { this.copy(chainApi = newChainApi) } case filterHeader: CompactFilterHeadersMessage => logger.debug( - s"Got ${filterHeader.filterHashes.size} compact filter header hashes, state=$state") + s"Got ${filterHeader.filterHashes.size} compact filter header hashes, state=$state" + ) state match { case s @ (_: HeaderSync | _: DoneSyncing) => val filterHeaderSync = @@ -160,37 +180,43 @@ case class DataMessageHandler( peerFinder = s.peerFinder, sentQuery = Instant.now() ) - handleFilterHeadersMessage(filterHeaderSync = filterHeaderSync, - filterHeader = filterHeader, - chainApi = chainApi, - peerMessageSenderApi = - peerData.peerMessageSender) + handleFilterHeadersMessage( + filterHeaderSync = filterHeaderSync, + filterHeader = filterHeader, + chainApi = chainApi, + peerMessageSenderApi = peerData.peerMessageSender + ) .map(s => copy(state = s)) case filterHeaderSync: FilterHeaderSync => - handleFilterHeadersMessage(filterHeaderSync = filterHeaderSync, - filterHeader = filterHeader, - chainApi = chainApi, - peerMessageSenderApi = - peerData.peerMessageSender) + handleFilterHeadersMessage( + filterHeaderSync = filterHeaderSync, + filterHeader = filterHeader, + chainApi = chainApi, + peerMessageSenderApi = peerData.peerMessageSender + ) .map(s => copy(state = s)) case x @ (_: NodeShuttingDown | _: FilterSync) => logger.warn( - s"Ignoring filterheaders msg with size=${filterHeader.filterHashes.size} while in state=$x from peer=$peer") + s"Ignoring filterheaders msg with size=${filterHeader.filterHashes.size} while in state=$x from peer=$peer" + ) Future.successful(copy(state = x)) case x @ (_: MisbehavingPeer | _: RemovePeers) => sys.error( - s"Incorrect state for handling filter header messages, got=$x") + s"Incorrect state for handling filter header messages, got=$x" + ) } case filter: CompactFilterMessage => logger.debug( - s"Received ${filter.commandName}, filter.blockHash=${filter.blockHash.flip} state=$state") + s"Received ${filter.commandName}, filter.blockHash=${filter.blockHash.flip} state=$state" + ) state match { case f: FilterSync => - handleFilterMessage(filterSyncState = f, - filter = filter, - peerMessageSenderApi = - peerData.peerMessageSender) + handleFilterMessage( + filterSyncState = f, + filter = filter, + peerMessageSenderApi = peerData.peerMessageSender + ) .map(s => copy(state = s)) case s @ (_: DoneSyncing | _: FilterHeaderSync) => val f = FilterSync( @@ -201,14 +227,16 @@ case class DataMessageHandler( peerFinder = s.peerFinder, sentQuery = Instant.now() ) - handleFilterMessage(filterSyncState = f, - filter = filter, - peerMessageSenderApi = - peerData.peerMessageSender) + handleFilterMessage( + filterSyncState = f, + filter = filter, + peerMessageSenderApi = peerData.peerMessageSender + ) .map(s => copy(state = s)) case x @ (_: HeaderSync | _: NodeShuttingDown) => logger.warn( - s"Ignoring filter msg with blockHash=${filter.blockHashBE} while in state=$x from peer=$peer") + s"Ignoring filter msg with blockHash=${filter.blockHashBE} while in state=$x from peer=$peer" + ) Future.successful(copy(state = x)) case x @ (_: MisbehavingPeer | _: RemovePeers | _: HeaderSync) => sys.error(s"Incorrect state for handling filter messages, got=$x") @@ -218,11 +246,13 @@ case class DataMessageHandler( _: GetCompactFilterHeadersMessage | _: GetCompactFilterCheckPointMessage) => logger.debug( - s"Received ${notHandling.commandName} message, skipping ") + s"Received ${notHandling.commandName} message, skipping " + ) Future.successful(this) case getData: GetDataMessage => logger.info( - s"Received a getdata message for inventories=${getData.inventories}") + s"Received a getdata message for inventories=${getData.inventories}" + ) getData.inventories.foreach { inv => logger.debug(s"Looking for inv=$inv") inv.typeIdentifier match { @@ -240,7 +270,8 @@ case class DataMessageHandler( .sendTransactionMessage(transaction = txToBroadcast) case None => logger.warn( - s"Got request to send data with hash=${inv.hash}, but found nothing") + s"Got request to send data with hash=${inv.hash}, but found nothing" + ) Future.unit } case other @ (TypeIdentifier.MsgBlock | @@ -249,11 +280,13 @@ case class DataMessageHandler( TypeIdentifier.MsgFilteredWitnessBlock | TypeIdentifier.MsgWitnessBlock) => logger.warn( - s"Got request to send data type=$other, this is not implemented yet") + s"Got request to send data type=$other, this is not implemented yet" + ) case unassigned: MsgUnassigned => logger.warn( - s"Received unassigned message we do not understand, msg=${unassigned}") + s"Received unassigned message we do not understand, msg=${unassigned}" + ) } } @@ -269,21 +302,26 @@ case class DataMessageHandler( .getHeader(block.blockHeader.hashBE) newMsgHandler <- { if (isIBD && headerOpt.isEmpty) { - //ignore block, don't execute callbacks until IBD is done + // ignore block, don't execute callbacks until IBD is done logger.info( - s"Received block=${block.blockHeader.hashBE.hex} while in IBD, ignoring it until IBD complete state=${state}.") + s"Received block=${block.blockHeader.hashBE.hex} while in IBD, ignoring it until IBD complete state=${state}." + ) Future.successful(this) } else if (!isIBD && headerOpt.isEmpty) { logger.info( - s"Received block=${block.blockHeader.hash.flip.hex}, processing block's header... state=$state") + s"Received block=${block.blockHeader.hash.flip.hex}, processing block's header... state=$state" + ) val headersMessage = HeadersMessage(CompactSizeUInt.one, Vector(block.blockHeader)) - val newDmhF = handleDataPayload(payload = headersMessage, - peerData = peerData) + val newDmhF = handleDataPayload( + payload = headersMessage, + peerData = peerData + ) newDmhF } else { logger.info( - s"Received block=${block.blockHeader.hash.flip.hex} state=$state") + s"Received block=${block.blockHeader.hash.flip.hex} state=$state" + ) appConfig.callBacks .executeOnBlockReceivedCallbacks(block) .map(_ => this) @@ -294,7 +332,8 @@ case class DataMessageHandler( newMsgHandlerF case TransactionMessage(tx) => logger.trace( - s"Received txmsg=${tx.txIdBE}, processing given callbacks") + s"Received txmsg=${tx.txIdBE}, processing given callbacks" + ) appConfig.callBacks .executeOnTxReceivedCallbacks(tx) .map(_ => this) @@ -302,18 +341,23 @@ case class DataMessageHandler( logger.warn(s"Merkleblock is not supported") Future.successful(this) case invMsg: InventoryMessage => - handleInventoryMsg(invMsg = invMsg, - peerMessageSenderApi = peerData.peerMessageSender) + handleInventoryMsg( + invMsg = invMsg, + peerMessageSenderApi = peerData.peerMessageSender + ) } } wrappedFuture.flatten } - /** syncs filter headers in case the header chain is still ahead post filter sync */ + /** syncs filter headers in case the header chain is still ahead post filter + * sync + */ private def syncIfHeadersAhead( syncNodeState: SyncNodeState, - peerMessageSenderApi: PeerMessageSenderApi): Future[NodeRunningState] = { + peerMessageSenderApi: PeerMessageSenderApi + ): Future[NodeRunningState] = { val bestBlockHeaderDbF = chainApi.getBestBlockHeader() for { headerHeight <- chainApi.getBestHashBlockHeight() @@ -321,14 +365,18 @@ case class DataMessageHandler( filterCount <- chainApi.getFilterCount() bestBlockHeaderDb <- bestBlockHeaderDbF newState <- { - require(headerHeight >= Math.max(filterHeaderCount, filterCount), - "Header chain cannot be behind filter or filter header chain") + require( + headerHeight >= Math.max(filterHeaderCount, filterCount), + "Header chain cannot be behind filter or filter header chain" + ) require( filterHeaderCount >= filterCount, - s"Filter header height $filterHeaderCount must be atleast filter height $filterCount") + s"Filter header height $filterHeaderCount must be atleast filter height $filterCount" + ) if (headerHeight > filterHeaderCount) { logger.info( - s"Starting to fetch filter headers in data message handler") + s"Starting to fetch filter headers in data message handler" + ) val fhs = syncNodeState.toFilterHeaderSync for { @@ -337,7 +385,8 @@ case class DataMessageHandler( peerMessageSenderApi = peerMessageSenderApi, chainApi = chainApi, state = fhs, - stopBlockHeaderDb = bestBlockHeaderDb) + stopBlockHeaderDb = bestBlockHeaderDb + ) } yield { syncingFilterHeadersState.getOrElse(fhs.toDoneSyncing) } @@ -345,12 +394,15 @@ case class DataMessageHandler( } else { require( headerHeight == filterHeaderCount, - s"headerHeight=$headerHeight filterHeaderCount=$filterHeaderCount") - require(headerHeight == filterCount, - s"headerHeight=$headerHeight filterCount=$filterCount") + s"headerHeight=$headerHeight filterHeaderCount=$filterHeaderCount" + ) + require( + headerHeight == filterCount, + s"headerHeight=$headerHeight filterCount=$filterCount" + ) logger.info(s"We are synced") - //check to see if we had blocks mined while IBD - //was ongoing, see: https://github.com/bitcoin-s/bitcoin-s/issues/5036 + // check to see if we had blocks mined while IBD + // was ongoing, see: https://github.com/bitcoin-s/bitcoin-s/issues/5036 for { bestBlockHash <- chainApi.getBestBlockHash() d = syncNodeState.toDoneSyncing @@ -358,8 +410,8 @@ case class DataMessageHandler( peerManager .gossipGetHeadersMessage(Vector(bestBlockHash)) .map { _ => - //set to done syncing since we are technically done with IBD - //we just need to sync blocks that occurred while we were doing IBD + // set to done syncing since we are technically done with IBD + // we just need to sync blocks that occurred while we were doing IBD d } } @@ -369,22 +421,27 @@ case class DataMessageHandler( } yield newState } - /** Recover the data message handler if we received an invalid block header from a peer */ + /** Recover the data message handler if we received an invalid block header + * from a peer + */ private def recoverInvalidHeader( - peerData: PersistentPeerData): Future[NodeRunningState] = { + peerData: PersistentPeerData + ): Future[NodeRunningState] = { val result = state match { case state @ (_: HeaderSync | _: DoneSyncing) => val peer = peerData.peer peerData.updateInvalidMessageCount() if (peerData.exceededMaxInvalidMessages) { logger.warn( - s"$peer exceeded max limit of invalid messages. Disconnecting. peers=${state.peers}") + s"$peer exceeded max limit of invalid messages. Disconnecting. peers=${state.peers}" + ) val m = MisbehavingPeer( badPeer = peer, peerWithServicesDataMap = state.peerWithServicesDataMap, waitingForDisconnection = state.waitingForDisconnection, - state.peerFinder) + state.peerFinder + ) Future.successful(m) } else { @@ -395,10 +452,11 @@ case class DataMessageHandler( .map(_.hashBE) newState <- { logger.info( - s"Received invalid header from peer=$peer. Re-querying headers from peers=${state.peers}. invalidMessages=${peerData.getInvalidMessageCount} peers.size=${state.peers.size}") + s"Received invalid header from peer=$peer. Re-querying headers from peers=${state.peers}. invalidMessages=${peerData.getInvalidMessageCount} peers.size=${state.peers.size}" + ) val queryF = peerManager.gossipGetHeadersMessage(cachedHeaders) - //switch to DoneSyncing state until we receive a valid header from our peers + // switch to DoneSyncing state until we receive a valid header from our peers val d = state.toDoneSyncing queryF.map(_ => d) } @@ -408,7 +466,8 @@ case class DataMessageHandler( Future.successful(state) case m @ (_: MisbehavingPeer | _: RemovePeers) => val exn = new RuntimeException( - s"Cannot recover invalid headers, got=$m") + s"Cannot recover invalid headers, got=$m" + ) Future.failed(exn) } @@ -418,7 +477,8 @@ case class DataMessageHandler( private def sendNextGetCompactFilterHeadersCommand( peerMessageSenderApi: PeerMessageSenderApi, prevStopHash: DoubleSha256DigestBE, - stopHash: DoubleSha256DigestBE): Future[Boolean] = + stopHash: DoubleSha256DigestBE + ): Future[Boolean] = PeerManager.sendNextGetCompactFilterHeadersCommand( peerMessageSenderApi = peerMessageSenderApi, chainApi = chainApi, @@ -431,7 +491,8 @@ case class DataMessageHandler( peerMessageSenderApi: PeerMessageSenderApi, startHeightOpt: Option[Int], stopBlockHash: DoubleSha256DigestBE, - fs: NodeState.FilterSync): Future[Option[NodeState.FilterSync]] = { + fs: NodeState.FilterSync + ): Future[Option[NodeState.FilterSync]] = { PeerManager .sendNextGetCompactFilterCommand( @@ -454,7 +515,8 @@ case class DataMessageHandler( peerMessageSenderApi: PeerMessageSenderApi, stopBlockHash: DoubleSha256DigestBE, startHeightOpt: Option[Int], - syncNodeState: SyncNodeState): Future[Option[NodeState.FilterSync]] = { + syncNodeState: SyncNodeState + ): Future[Option[NodeState.FilterSync]] = { logger.debug(s"Beginning to sync filters to stopBlockHashBE=$stopBlockHash") val fs = syncNodeState match { @@ -463,16 +525,18 @@ case class DataMessageHandler( case fs: FilterSync => fs } - sendNextGetCompactFilterCommand(peerMessageSenderApi = peerMessageSenderApi, - startHeightOpt = startHeightOpt, - stopBlockHash = stopBlockHash, - fs = fs) + sendNextGetCompactFilterCommand( + peerMessageSenderApi = peerMessageSenderApi, + startHeightOpt = startHeightOpt, + stopBlockHash = stopBlockHash, + fs = fs + ) } private def handleInventoryMsg( invMsg: InventoryMessage, - peerMessageSenderApi: PeerMessageSenderApi): Future[ - DataMessageHandler] = { + peerMessageSenderApi: PeerMessageSenderApi + ): Future[DataMessageHandler] = { logger.debug(s"Received inv=${invMsg}") val invsOptF: Future[Seq[Option[Inventory]]] = Future.traverse(invMsg.inventories) { @@ -484,7 +548,8 @@ case class DataMessageHandler( } yield { if (isIBD) { logger.info( - s"Ignoring inv while in IBD message=$invMsg while in state=$state") + s"Ignoring inv while in IBD message=$invMsg while in state=$state" + ) None } else Some(Inventory(TypeIdentifier.MsgWitnessBlock, hash)) } @@ -507,7 +572,8 @@ case class DataMessageHandler( } private def calcFilterHeaderFilterHeight( - chainApi: ChainApi): Future[(Int, Int)] = { + chainApi: ChainApi + ): Future[(Int, Int)] = { for { filterHeaderHeight <- chainApi.getFilterHeaderCount() filterHeight <- chainApi.getFilterCount() @@ -517,17 +583,19 @@ case class DataMessageHandler( /** Helper method to determine if compact filters are synced */ private def isFiltersSynced( chainApi: ChainApi, - filterBatch: Set[CompactFilterMessage]): Future[Boolean] = { + filterBatch: Set[CompactFilterMessage] + ): Future[Boolean] = { val bestChainTipsF = chainApi.getBestChainTips() for { (newFilterHeaderHeight, newFilterHeight) <- calcFilterHeaderFilterHeight( - chainApi) + chainApi + ) isSynced <- if (newFilterHeight == 0 && walletCreationTimeOpt.isDefined) { - //if we have zero filters in our database and are syncing filters after a wallet creation time - //we need to calculate the offset of the first filter - //and how many compact filter headers we have seen. filter_height = best_filter_header - first_filter_filter_header + // if we have zero filters in our database and are syncing filters after a wallet creation time + // we need to calculate the offset of the first filter + // and how many compact filter headers we have seen. filter_height = best_filter_header - first_filter_filter_header val bestBlockHashF = chainApi.getBestBlockHash() val filterHeadersF: Future[Vector[CompactFilterHeaderDb]] = { Future @@ -543,7 +611,7 @@ case class DataMessageHandler( filterHeaders.exists(_.blockHashBE == bestBlockHash) } } else if (newFilterHeight == 0 && walletCreationTimeOpt.isEmpty) { - //fully syncing all filters + // fully syncing all filters Future.successful(filterBatch.size == newFilterHeaderHeight + 1) } else { for { @@ -575,10 +643,13 @@ case class DataMessageHandler( } private def sortBlockFiltersByBlockHeight( - filterBatch: Set[CompactFilterMessage]): Future[ - Vector[(DoubleSha256Digest, CompactFilterMessage, GolombFilter)]] = { + filterBatch: Set[CompactFilterMessage] + ): Future[ + Vector[(DoubleSha256Digest, CompactFilterMessage, GolombFilter)] + ] = { val blockFiltersF: Future[ - Set[(Int, DoubleSha256Digest, CompactFilterMessage, GolombFilter)]] = { + Set[(Int, DoubleSha256Digest, CompactFilterMessage, GolombFilter)] + ] = { Future.traverse(filterBatch) { filter => val blockHeightOptF = chainApi.getBlockHeight(filter.blockHash.flip) @@ -587,11 +658,14 @@ case class DataMessageHandler( } yield { require( blockHeightOpt.isDefined, - s"Could not find block height for blockHash=${filter.blockHash.flip}") - (blockHeightOpt.get, - filter.blockHash, - filter, - BlockFilter.fromBytes(filter.filterBytes, filter.blockHash)) + s"Could not find block height for blockHash=${filter.blockHash.flip}" + ) + ( + blockHeightOpt.get, + filter.blockHash, + filter, + BlockFilter.fromBytes(filter.filterBytes, filter.blockHash) + ) } filtersWithBlockHeightF @@ -610,7 +684,8 @@ case class DataMessageHandler( state: HeaderSync, headers: Vector[BlockHeader], peerMessageSenderApi: PeerMessageSenderApi, - chainApi: ChainApi): Future[NodeRunningState] = { + chainApi: ChainApi + ): Future[NodeRunningState] = { val peer = peerMessageSenderApi.peer logger.debug(s"getHeaders() newDmh.state=${state} peer=$peer peers=$peer") val count = headers.length @@ -621,23 +696,28 @@ case class DataMessageHandler( val lastHash = lastHeader.hash chainApi.getBlockCount().map { count => logger.trace( - s"Processed headers, most recent has height=$count and hash=$lastHash.") + s"Processed headers, most recent has height=$count and hash=$lastHash." + ) } if (count == HeadersMessage.MaxHeadersCount) { logger.debug( - s"Received maximum amount of headers in one header message. This means we are not synced, requesting more") - //ask for headers more from the same peer + s"Received maximum amount of headers in one header message. This means we are not synced, requesting more" + ) + // ask for headers more from the same peer peerMessageSenderApi .sendGetHeadersMessage(lastHash.flip) .map(_ => state) } else { logger.debug( - List(s"Received headers=${count.toInt} in one message,", - "which is less than max. This means we are synced,", - s"not requesting more. state=$state") - .mkString(" ")) + List( + s"Received headers=${count.toInt} in one message,", + "which is less than max. This means we are synced,", + s"not requesting more. state=$state" + ) + .mkString(" ") + ) // If we are in neutrino mode, we might need to start fetching filters and their headers // if we are syncing we should do this, however, sometimes syncing isn't a good enough check, // so we also check if our cached filter heights have been set as well, if they haven't then @@ -653,7 +733,8 @@ case class DataMessageHandler( state = state.toFilterHeaderSync, chainApi = chainApi, peerMessageSenderApi = peerMessageSenderApi, - stopBlockHeaderDb = lastBlockHeaderDbOpt.get) + stopBlockHeaderDb = lastBlockHeaderDbOpt.get + ) } yield { fhs } @@ -661,12 +742,12 @@ case class DataMessageHandler( fhsOptF.map { case Some(s) => s case None => - //is this right? If we don't send cfheaders to our peers, are we done syncing? + // is this right? If we don't send cfheaders to our peers, are we done syncing? state.toDoneSyncing } } } else { - //what if we are synced exactly by the 2000th header + // what if we are synced exactly by the 2000th header Future.successful(state) } } @@ -675,16 +756,18 @@ case class DataMessageHandler( private def handleHeadersMessage( headersMessage: HeadersMessage, - peerData: PersistentPeerData): Future[DataMessageHandler] = { + peerData: PersistentPeerData + ): Future[DataMessageHandler] = { val count = headersMessage.count val peer = peerData.peer val headers = headersMessage.headers logger.debug( - s"Received headers message with ${count.toInt} headers from peer=$peer state=$state") + s"Received headers message with ${count.toInt} headers from peer=$peer state=$state" + ) val newStateOpt: Option[NodeRunningState] = state match { case d: DoneSyncing => val s = if (count.toInt != 0) { - //why do we sometimes get empty HeadersMessage? + // why do we sometimes get empty HeadersMessage? d.toHeaderSync(peer) } else { d @@ -697,14 +780,16 @@ case class DataMessageHandler( } else if (headerSync.syncPeer == peer) { Some(headerSync) } else { - //means we received a headers message from a peer we aren't syncing with, so ignore for now + // means we received a headers message from a peer we aren't syncing with, so ignore for now logger.debug( - s"Ignoring block headers from peer=$peer while we are syncing with syncPeer=${headerSync.syncPeer}") + s"Ignoring block headers from peer=$peer while we are syncing with syncPeer=${headerSync.syncPeer}" + ) None } case x @ (_: FilterHeaderSync | _: FilterSync | _: NodeShuttingDown) => logger.debug( - s"Ignoring block headers msg with size=${headers.size} while in state=$x from peer=$peer") + s"Ignoring block headers msg with size=${headers.size} while in state=$x from peer=$peer" + ) Some(x) case x @ (_: MisbehavingPeer | _: RemovePeers) => sys.error(s"Invalid state to receive headers in, got=$x") @@ -725,7 +810,8 @@ case class DataMessageHandler( case Some(x @ (_: FilterHeaderSync | _: FilterSync)) => Future.successful(copy(state = x)) case Some( - x @ (_: MisbehavingPeer | _: RemovePeers | _: NodeShuttingDown)) => + x @ (_: MisbehavingPeer | _: RemovePeers | _: NodeShuttingDown) + ) => Future.successful(copy(state = x)) case None => Future.successful(this) @@ -735,7 +821,8 @@ case class DataMessageHandler( private def handleHeadersMessageValidState( headerSyncState: HeaderSync, headers: Vector[BlockHeader], - peerData: PersistentPeerData): Future[NodeRunningState] = { + peerData: PersistentPeerData + ): Future[NodeRunningState] = { val peer = headerSyncState.syncPeer val count = headers.size val chainApiHeaderProcessF: Future[DataMessageHandler] = for { @@ -748,10 +835,12 @@ case class DataMessageHandler( val getHeadersF: Future[NodeRunningState] = { for { newDmh <- chainApiHeaderProcessF - dmh <- getHeaders(state = headerSyncState, - headers = headers, - peerMessageSenderApi = peerData.peerMessageSender, - newDmh.chainApi) + dmh <- getHeaders( + state = headerSyncState, + headers = headers, + peerMessageSenderApi = peerData.peerMessageSender, + newDmh.chainApi + ) } yield dmh } val recoveredStateF: Future[NodeRunningState] = getHeadersF.recoverWith { @@ -761,7 +850,8 @@ case class DataMessageHandler( Future.successful(d) case _: InvalidBlockHeader => logger.warn( - s"Invalid headers of count $count sent from ${peer} in state=$state") + s"Invalid headers of count $count sent from ${peer} in state=$state" + ) recoverInvalidHeader(peerData) case e: Throwable => throw e } @@ -774,7 +864,7 @@ case class DataMessageHandler( newState <- recoveredStateF _ <- { if (count == 0) { - Future.unit //don't execute callbacks if we receive 0 headers from peer + Future.unit // don't execute callbacks if we receive 0 headers from peer } else { appConfig.callBacks.executeOnBlockHeadersReceivedCallbacks(headers) } @@ -789,7 +879,8 @@ case class DataMessageHandler( filterHeaderSync: FilterHeaderSync, filterHeader: CompactFilterHeadersMessage, chainApi: ChainApi, - peerMessageSenderApi: PeerMessageSenderApi): Future[NodeRunningState] = { + peerMessageSenderApi: PeerMessageSenderApi + ): Future[NodeRunningState] = { val filterHeaders = filterHeader.filterHeaders val blockCountF = chainApi.getBlockCount() val bestBlockHashF = chainApi.getBestBlockHash() @@ -801,21 +892,25 @@ case class DataMessageHandler( newState <- if (blockCount != filterHeaderCount) { logger.debug( - s"Received maximum amount of filter headers in one header message. This means we are not synced, requesting more") + s"Received maximum amount of filter headers in one header message. This means we are not synced, requesting more" + ) sendNextGetCompactFilterHeadersCommand( peerMessageSenderApi = peerMessageSenderApi, prevStopHash = filterHeader.stopHashBE, - stopHash = bestBlockHash).map(_ => filterHeaderSync) + stopHash = bestBlockHash + ).map(_ => filterHeaderSync) } else { for { startHeightOpt <- PeerManager.getCompactFilterStartHeight( chainApi, - walletCreationTimeOpt) + walletCreationTimeOpt + ) filterSyncStateOpt <- sendFirstGetCompactFilterCommand( peerMessageSenderApi = peerMessageSenderApi, stopBlockHash = filterHeader.stopHashBE, startHeightOpt = startHeightOpt, - syncNodeState = filterHeaderSync) + syncNodeState = filterHeaderSync + ) } yield { filterSyncStateOpt match { case Some(filterSyncState) => filterSyncState @@ -834,7 +929,8 @@ case class DataMessageHandler( private def handleFilterMessage( filterSyncState: FilterSync, filter: CompactFilterMessage, - peerMessageSenderApi: PeerMessageSenderApi): Future[NodeRunningState] = { + peerMessageSenderApi: PeerMessageSenderApi + ): Future[NodeRunningState] = { val filterBatch = filterSyncState.filterBatchCache.+(filter) val batchSizeFull: Boolean = filterBatch.size == chainConfig.filterBatchSize @@ -851,7 +947,8 @@ case class DataMessageHandler( filterBestBlockHashBE = sortedFilterMessages.lastOption .map(_.blockHashBE) _ = logger.debug( - s"Processing ${filterBatch.size} filters bestBlockHashBE=${filterBestBlockHashBE}") + s"Processing ${filterBatch.size} filters bestBlockHashBE=${filterBestBlockHashBE}" + ) newChainApi <- chainApi.processFilters(sortedFilterMessages) sortedGolombFilters = sortedBlockFilters.map(x => (x._1.flip, x._3)) _ <- @@ -863,14 +960,16 @@ case class DataMessageHandler( filterHeaderSyncStateOpt <- if (batchSizeFull && !isFiltersSynced) { logger.debug( - s"Received maximum amount of filters in one batch. This means we are not synced, requesting more") + s"Received maximum amount of filters in one batch. This means we are not synced, requesting more" + ) for { bestBlockHash <- chainApi.getBestBlockHash() fssOpt <- sendNextGetCompactFilterCommand( peerMessageSenderApi = peerMessageSenderApi, startHeightOpt = None, stopBlockHash = bestBlockHash, - fs = filterSyncState) + fs = filterSyncState + ) } yield { fssOpt } diff --git a/node/src/main/scala/org/bitcoins/node/networking/peer/PeerConnection.scala b/node/src/main/scala/org/bitcoins/node/networking/peer/PeerConnection.scala index fab270f86b..2ccf3e7f7c 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/peer/PeerConnection.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/peer/PeerConnection.scala @@ -40,8 +40,8 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( implicit nodeAppConfig: NodeAppConfig, chainAppConfig: ChainAppConfig, - system: ActorSystem) - extends P2PLogger { + system: ActorSystem +) extends P2PLogger { import system.dispatcher @@ -62,11 +62,14 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( private lazy val connection: Flow[ ByteString, ByteString, - (Future[Tcp.OutgoingConnection], UniqueKillSwitch)] = { + (Future[Tcp.OutgoingConnection], UniqueKillSwitch) + ] = { val base = Tcp(system) - .outgoingConnection(remoteAddress = socket, - halfClose = false, - options = options) + .outgoingConnection( + remoteAddress = socket, + halfClose = false, + options = options + ) .viaMat(KillSwitches.single)(Keep.both) base } @@ -77,12 +80,14 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( chainApi.getBestHashBlockHeight().map { height => val localhost = java.net.InetAddress.getLocalHost val versionMsg = - VersionMessage(nodeAppConfig.network, - NodeConstants.userAgent, - Int32(height), - InetAddress(localhost.getAddress), - InetAddress(localhost.getAddress), - nodeAppConfig.relay) + VersionMessage( + nodeAppConfig.network, + NodeConstants.userAgent, + Int32(height), + InetAddress(localhost.getAddress), + InetAddress(localhost.getAddress), + nodeAppConfig.relay + ) NetworkMessage(nodeAppConfig.network, versionMsg) } } @@ -93,7 +98,8 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( private def parseHelper( unalignedBytes: ByteString, - byteVec: ByteString): (ByteString, Vector[NetworkMessage]) = { + byteVec: ByteString + ): (ByteString, Vector[NetworkMessage]) = { val bytes: ByteVector = ByteVector(unalignedBytes ++ byteVec) logger.trace(s"Bytes for message parsing: ${bytes.toHex}") val (messages, newUnalignedBytes) = @@ -102,18 +108,19 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( (ByteString.fromArray(newUnalignedBytes.toArray), messages) } - private val parseToNetworkMsgFlow: Flow[ - ByteString, - Vector[NetworkMessage], - NotUsed] = { + private val parseToNetworkMsgFlow + : Flow[ByteString, Vector[NetworkMessage], NotUsed] = { Flow[ByteString] - .statefulMap(() => ByteString.empty)(parseHelper, - { _: ByteString => None }) + .statefulMap(() => ByteString.empty)( + parseHelper, + { _: ByteString => None } + ) .log( "parseToNetworkMsgFlow", { case msgs: Vector[NetworkMessage] => s"received msgs=${msgs.map(_.payload.commandName)} from peer=$peer socket=$socket" - }) + } + ) .withAttributes(Attributes.logLevels(onFailure = Logging.DebugLevel)) } @@ -121,35 +128,40 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( Flow.apply } - private val bidiFlow: BidiFlow[ - ByteString, - Vector[NetworkMessage], - ByteString, - ByteString, - NotUsed] = { + private val bidiFlow: BidiFlow[ByteString, + Vector[ + NetworkMessage + ], + ByteString, + ByteString, + NotUsed] = { BidiFlow.fromFlows(parseToNetworkMsgFlow, writeNetworkMsgFlow) } - private val (mergeHubSink: Sink[ByteString, NotUsed], - mergeHubSource: Source[ByteString, NotUsed]) = { + private val ( + mergeHubSink: Sink[ByteString, NotUsed], + mergeHubSource: Source[ByteString, NotUsed] + ) = { MergeHub .source[ByteString](1024) .preMaterialize() } - private val connectionFlow: Flow[ - ByteString, - Vector[NetworkMessage], - (Future[Tcp.OutgoingConnection], UniqueKillSwitch)] = + private val connectionFlow + : Flow[ByteString, + Vector[ + NetworkMessage + ], + (Future[Tcp.OutgoingConnection], UniqueKillSwitch)] = connection .idleTimeout(nodeAppConfig.peerTimeout) .joinMat(bidiFlow)(Keep.left) private def connectionGraph( - handleNetworkMsgSink: Sink[ - Vector[NetworkMessage], - Future[Done]]): RunnableGraph[ - ((Future[Tcp.OutgoingConnection], UniqueKillSwitch), Future[Done])] = { + handleNetworkMsgSink: Sink[Vector[NetworkMessage], Future[Done]] + ): RunnableGraph[ + ((Future[Tcp.OutgoingConnection], UniqueKillSwitch), Future[Done]) + ] = { val result = mergeHubSource .viaMat(connectionFlow)(Keep.right) .toMat(handleNetworkMsgSink)(Keep.both) @@ -157,8 +169,8 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( result } - private def buildConnectionGraph(): Future[ - ((Tcp.OutgoingConnection, UniqueKillSwitch), Future[Done])] = { + private def buildConnectionGraph() + : Future[((Tcp.OutgoingConnection, UniqueKillSwitch), Future[Done])] = { val handleNetworkMsgSink: Sink[Vector[NetworkMessage], Future[Done]] = { Flow[Vector[NetworkMessage]] @@ -175,8 +187,8 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( .toMat(Sink.ignore)(Keep.right) } - val runningStream: Future[ - ((Tcp.OutgoingConnection, UniqueKillSwitch), Future[Done])] = { + val runningStream + : Future[((Tcp.OutgoingConnection, UniqueKillSwitch), Future[Done])] = { nodeAppConfig.socks5ProxyParams match { case Some(s) => val connectionSink = @@ -186,8 +198,8 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( case Right(state) => state match { case Socks5ConnectionState.Connected => - //need to send version message when we are first - //connected to initiate bitcoin protocol handshake + // need to send version message when we are first + // connected to initiate bitcoin protocol handshake sendVersionMsg().map(_ => ByteString.empty) case Socks5ConnectionState.Disconnected | Socks5ConnectionState.Authenticating | @@ -200,7 +212,8 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( val source: Source[ ByteString, - (Future[Tcp.OutgoingConnection], UniqueKillSwitch)] = + (Future[Tcp.OutgoingConnection], UniqueKillSwitch) + ] = mergeHubSource.viaMat(connection)(Keep.right) Socks5Connection .socks5Handler( @@ -246,15 +259,19 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( case scala.util.Success(o) => val tcp = o._1._1 logger.debug( - s"Connected to remote=${tcp.remoteAddress} local=${tcp.localAddress}") + s"Connected to remote=${tcp.remoteAddress} local=${tcp.localAddress}" + ) case scala.util.Failure(err) => logger.debug( - s"Failed to connect to peer=$peer with errMsg=${err.getMessage}") + s"Failed to connect to peer=$peer with errMsg=${err.getMessage}" + ) val offerF = queue.offer(NodeStreamMessage.InitializationTimeout(peer)) offerF.failed.foreach(err => - logger.error(s"Failed to offer initialize timeout for peer=$peer", - err)) + logger.error( + s"Failed to offer initialize timeout for peer=$peer", + err + )) } val resultF: Future[Unit] = { @@ -274,7 +291,8 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( handleStreamComplete() case scala.util.Failure(err) => logger.debug( - s"Connection with peer=$peer failed with err=${err.getMessage}") + s"Connection with peer=$peer failed with err=${err.getMessage}" + ) handleStreamComplete() } } @@ -301,7 +319,7 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( /** resets reconnect state after connecting to a peer */ private def resetReconnect(): Unit = { - //cancel the job for reconnecting in case we were attempting to reconnect + // cancel the job for reconnecting in case we were attempting to reconnect reconnectionCancellableOpt.map(_.cancel()) reconnectionCancellableOpt = None reconnectionTry = 0 @@ -312,7 +330,8 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( connectionGraphOpt match { case Some(_) => logger.error( - s"Cannot reconnect when we have an active connection to peer=$peer") + s"Cannot reconnect when we have an active connection to peer=$peer" + ) Future.unit case None => logger.info(s"Attempting to reconnect peer=$peer") @@ -358,16 +377,17 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( } private[node] def sendMsg(msg: NetworkPayload): Future[Unit] = { - //version or verack messages are the only messages that - //can be sent before we are fully initialized - //as they are needed to complete our handshake with our peer + // version or verack messages are the only messages that + // can be sent before we are fully initialized + // as they are needed to complete our handshake with our peer val networkMsg = NetworkMessage(nodeAppConfig.network, msg) sendMsg(networkMsg) } private[node] def sendMsg(msg: NetworkMessage): Future[Unit] = { logger.debug( - s"Sending msg=${msg.header.commandName} to peer=${peer} socket=$socket") + s"Sending msg=${msg.header.commandName} to peer=${peer} socket=$socket" + ) connectionGraphOpt match { case Some(g) => sendMsg(msg.bytes, g.mergeHubSink) @@ -381,13 +401,15 @@ case class PeerConnection(peer: Peer, queue: SourceQueue[NodeStreamMessage])( private def sendMsg( bytes: ByteVector, - mergeHubSink: Sink[ByteString, NotUsed]): Future[Unit] = { + mergeHubSink: Sink[ByteString, NotUsed] + ): Future[Unit] = { sendMsg(ByteString.fromArray(bytes.toArray), mergeHubSink) } private def sendMsg( bytes: ByteString, - mergeHubSink: Sink[ByteString, NotUsed]): Future[Unit] = { + mergeHubSink: Sink[ByteString, NotUsed] + ): Future[Unit] = { val sendMsgF = Future { Source.single(bytes).to(mergeHubSink).run() }.map(_ => ()) @@ -401,7 +423,8 @@ object PeerConnection { mergeHubSink: Sink[ByteString, NotUsed], connectionF: Future[Tcp.OutgoingConnection], streamDoneF: Future[Done], - killswitch: UniqueKillSwitch) { + killswitch: UniqueKillSwitch + ) { def stop(): Future[Done] = { killswitch.shutdown() diff --git a/node/src/main/scala/org/bitcoins/node/networking/peer/PeerMessageSender.scala b/node/src/main/scala/org/bitcoins/node/networking/peer/PeerMessageSender.scala index 0280b05a36..9ea42114a2 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/peer/PeerMessageSender.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/peer/PeerMessageSender.scala @@ -33,14 +33,16 @@ case class PeerMessageSender(peerConnection: PeerConnection) } override def sendGetHeadersMessage( - hashes: Vector[DoubleSha256DigestBE]): Future[Unit] = { + hashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] = { val headersMsg = GetHeadersMessage(hashes.distinct.take(101).map(_.flip)) sendMsg(headersMsg) } override def sendGetDataMessages( typeIdentifier: TypeIdentifier, - hashes: Vector[DoubleSha256DigestBE]): Future[Unit] = { + hashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] = { val msg: NetworkPayload = { val inventories = hashes.map(hash => Inventory(typeIdentifier, hash.flip)) @@ -52,26 +54,33 @@ case class PeerMessageSender(peerConnection: PeerConnection) } override def sendGetCompactFilterHeadersMessage( - filterSyncMarker: FilterSyncMarker): Future[Unit] = { + filterSyncMarker: FilterSyncMarker + ): Future[Unit] = { val message = - GetCompactFilterHeadersMessage(if (filterSyncMarker.startHeight < 0) 0 - else filterSyncMarker.startHeight, - filterSyncMarker.stopBlockHash) + GetCompactFilterHeadersMessage( + if (filterSyncMarker.startHeight < 0) 0 + else filterSyncMarker.startHeight, + filterSyncMarker.stopBlockHash + ) sendMsg(message) } - override def sendGetCompactFiltersMessage(filterSyncMarker: FilterSyncMarker)( - implicit ec: ExecutionContext): Future[Unit] = { + override def sendGetCompactFiltersMessage( + filterSyncMarker: FilterSyncMarker + )(implicit ec: ExecutionContext): Future[Unit] = { val message = - GetCompactFiltersMessage(if (filterSyncMarker.startHeight < 0) 0 - else filterSyncMarker.startHeight, - filterSyncMarker.stopBlockHash) + GetCompactFiltersMessage( + if (filterSyncMarker.startHeight < 0) 0 + else filterSyncMarker.startHeight, + filterSyncMarker.stopBlockHash + ) logger.debug(s"Sending getcfilters=$message to peer ${peer}") sendMsg(message).map(_ => ())(ec) } override def sendInventoryMessage( - transactions: Vector[Transaction]): Future[Unit] = { + transactions: Vector[Transaction] + ): Future[Unit] = { val inventories = transactions.map(tx => Inventory(TypeIdentifier.MsgTx, tx.txId)) val message = InventoryMessage(inventories) @@ -79,15 +88,19 @@ case class PeerMessageSender(peerConnection: PeerConnection) } - /** Sends a [[org.bitcoins.core.p2p.VersionMessage VersionMessage]] to our peer */ + /** Sends a [[org.bitcoins.core.p2p.VersionMessage VersionMessage]] to our + * peer + */ override def sendVersionMessage()(implicit - conf: NodeAppConfig): Future[Unit] = { + conf: NodeAppConfig + ): Future[Unit] = { val local = java.net.InetAddress.getLocalHost val versionMsg = VersionMessage( conf.network, InetAddress(peer.socket.getAddress.getAddress), InetAddress(local.getAddress), - relay = conf.relay) + relay = conf.relay + ) sendMsg(versionMsg) } } diff --git a/node/src/main/scala/org/bitcoins/node/util/BitcoinSNodeUtil.scala b/node/src/main/scala/org/bitcoins/node/util/BitcoinSNodeUtil.scala index fac147b9a6..82e87d7777 100644 --- a/node/src/main/scala/org/bitcoins/node/util/BitcoinSNodeUtil.scala +++ b/node/src/main/scala/org/bitcoins/node/util/BitcoinSNodeUtil.scala @@ -23,16 +23,18 @@ object BitcoinSNodeUtil { def createActorName(className: Class[_]): String = createActorName(className.getSimpleName) - def stringsToPeers(addresses: Vector[String])(implicit - nodeAppConfig: NodeAppConfig): Vector[Peer] = { + def stringsToPeers( + addresses: Vector[String] + )(implicit nodeAppConfig: NodeAppConfig): Vector[Peer] = { val formatStrings = addresses.map { s => - //assumes strings are valid, todo: add util functions to check fully for different addresses - if (s.count(_ == ':') > 1 && s(0) != '[') //ipv6 + // assumes strings are valid, todo: add util functions to check fully for different addresses + if (s.count(_ == ':') > 1 && s(0) != '[') // ipv6 "[" + s + "]" else s } val inetSockets = formatStrings.map( - NetworkUtil.parseInetSocketAddress(_, nodeAppConfig.network.port)) + NetworkUtil.parseInetSocketAddress(_, nodeAppConfig.network.port) + ) val peers = inetSockets.map(Peer.fromSocket(_, nodeAppConfig.socks5ProxyParams)) peers diff --git a/node/src/main/scala/org/bitcoins/node/util/PeerMessageSenderApi.scala b/node/src/main/scala/org/bitcoins/node/util/PeerMessageSenderApi.scala index 377527ff15..c3b324b2cd 100644 --- a/node/src/main/scala/org/bitcoins/node/util/PeerMessageSenderApi.scala +++ b/node/src/main/scala/org/bitcoins/node/util/PeerMessageSenderApi.scala @@ -29,13 +29,15 @@ trait PeerMessageSenderApi { def sendGetDataMessage( typeIdentifier: TypeIdentifier, - hash: DoubleSha256DigestBE): Future[Unit] = { + hash: DoubleSha256DigestBE + ): Future[Unit] = { sendGetDataMessages(typeIdentifier, Vector(hash)) } def sendGetDataMessages( typeIdentifier: TypeIdentifier, - hashes: Vector[DoubleSha256DigestBE]): Future[Unit] + hashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] def sendGetHeadersMessage(hashes: Vector[DoubleSha256DigestBE]): Future[Unit] @@ -46,10 +48,12 @@ trait PeerMessageSenderApi { def sendMsg(msg: NetworkPayload): Future[Unit] def sendGetCompactFilterHeadersMessage( - filterSyncMarker: FilterSyncMarker): Future[Unit] + filterSyncMarker: FilterSyncMarker + ): Future[Unit] def sendGetCompactFiltersMessage(filterSyncMarker: FilterSyncMarker)(implicit - ec: ExecutionContext): Future[Unit] + ec: ExecutionContext + ): Future[Unit] def sendInventoryMessage(transactions: Vector[Transaction]): Future[Unit] @@ -72,21 +76,25 @@ trait PeerMessageSenderApi { sendMsg(sendHeadersMsg) } - /** Sends a [[org.bitcoins.core.p2p.VersionMessage VersionMessage]] to our peer */ + /** Sends a [[org.bitcoins.core.p2p.VersionMessage VersionMessage]] to our + * peer + */ def sendVersionMessage()(implicit conf: NodeAppConfig): Future[Unit] - def sendVersionMessage(chainApi: ChainApi)(implicit - ec: ExecutionContext, - conf: NodeAppConfig): Future[Unit] = { + def sendVersionMessage( + chainApi: ChainApi + )(implicit ec: ExecutionContext, conf: NodeAppConfig): Future[Unit] = { chainApi.getBestHashBlockHeight().flatMap { height => val localhost = java.net.InetAddress.getLocalHost val versionMsg = - VersionMessage(conf.network, - NodeConstants.userAgent, - Int32(height), - InetAddress(localhost.getAddress), - InetAddress(localhost.getAddress), - conf.relay) + VersionMessage( + conf.network, + NodeConstants.userAgent, + Int32(height), + InetAddress(localhost.getAddress), + InetAddress(localhost.getAddress), + conf.relay + ) sendMsg(versionMsg) } } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/Implicits.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/Implicits.scala index bb534f4469..1e0d712e72 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/Implicits.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/Implicits.scala @@ -6,9 +6,8 @@ import org.scalatest.exceptions.TestFailedException import scala.annotation.tailrec -/** Provides extension methods, syntax - * and other handy implicit values that - * aid in testing. +/** Provides extension methods, syntax and other handy implicit values that aid + * in testing. */ object Implicits { @@ -22,7 +21,8 @@ object Implicits { def loop(counter: Int): T = if (counter > max) { sys.error( - s"Could not get a sample from generator after $max attempts") + s"Could not get a sample from generator after $max attempts" + ) } else { gen.sample match { case None => loop(counter + 1) @@ -43,7 +43,8 @@ object Implicits { case Seq() => throw new TestFailedException( message = "Cannot turn an empty list into an assertion!", - failedCodeStackDepth = 0) + failedCodeStackDepth = 0 + ) // this should force all collection kinds to // evaluate all their members, throwing when // evaluating a bad one diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/chain/ChainTestUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/chain/ChainTestUtil.scala index fe55c147ec..deb4e47d78 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/chain/ChainTestUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/chain/ChainTestUtil.scala @@ -22,26 +22,31 @@ sealed abstract class ChainTestUtil { BlockHeaderDbHelper.fromBlockHeader( height = 0, chainWork = BlockHeader.getBlockProof(regTestHeader), - bh = regTestHeader) + bh = regTestHeader + ) } lazy val regTestGenesisHeaderCompactFilter: GolombFilter = BlockFilter.apply(regTestChainParams.genesisBlock, Vector.empty) lazy val regTestGenesisHeaderCompactFilterDb: CompactFilterDb = - CompactFilterDbHelper.fromGolombFilter(regTestGenesisHeaderCompactFilter, - regTestHeader.hashBE, - 0) + CompactFilterDbHelper.fromGolombFilter( + regTestGenesisHeaderCompactFilter, + regTestHeader.hashBE, + 0 + ) lazy val regTestGenesisHeaderCompactFilterHeader: FilterHeader = FilterHeader( regTestGenesisHeaderCompactFilter.hash, - DoubleSha256Digest.empty) + DoubleSha256Digest.empty + ) lazy val regTestGenesisHeaderCompactFilterHeaderDb: CompactFilterHeaderDb = CompactFilterHeaderDbHelper.fromFilterHeader( regTestGenesisHeaderCompactFilterHeader, regTestHeader.hashBE, - 0) + 0 + ) val genesisHeaderDb: BlockHeaderDb = regTestGenesisHeaderDb @@ -52,66 +57,80 @@ sealed abstract class ChainTestUtil { regTestGenesisHeaderCompactFilterHeaderDb val genesisFilterMessage: CompactFilterMessage = { - CompactFilterMessage(filterType = genesisFilterDb.filterType, - blockHash = genesisFilterDb.blockHashBE.flip, - filterBytes = genesisFilterDb.golombFilter.bytes) + CompactFilterMessage( + filterType = genesisFilterDb.filterType, + blockHash = genesisFilterDb.blockHashBE.flip, + filterBytes = genesisFilterDb.golombFilter.bytes + ) } lazy val mainnetChainParam: MainNetChainParams.type = MainNetChainParams lazy val blockHeader562375 = BlockHeader.fromHex( - "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c") + "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c" + ) lazy val blockHeader562462 = BlockHeader.fromHex( - "0100000053fb045b4d3ca149faca8e7ea53cdb3168bc58b875e47196b3a6b3f100000000406468307c915485a9c9eabe31cc853e68311176e07e71475c3e26888fb7b7ed30846949ffff001d2b740f74") + "0100000053fb045b4d3ca149faca8e7ea53cdb3168bc58b875e47196b3a6b3f100000000406468307c915485a9c9eabe31cc853e68311176e07e71475c3e26888fb7b7ed30846949ffff001d2b740f74" + ) lazy val blockHeader562463 = BlockHeader.fromHex( - "010000003ce6c27ae14022e4b6ea0a5c3633d156e3e3a47509c1adf085371ba300000000f01258747019514aa5c475cddd59a309347280ead98d19d8df8f9f99eb56757938866949ffff001d18bcb4f8") + "010000003ce6c27ae14022e4b6ea0a5c3633d156e3e3a47509c1adf085371ba300000000f01258747019514aa5c475cddd59a309347280ead98d19d8df8f9f99eb56757938866949ffff001d18bcb4f8" + ) lazy val blockHeader562464 = BlockHeader.fromHex( - "010000004bd0b78e90c6b0f361f395535ac170980de0c8214380daefce31fd1100000000282c9db8313817b4835efab229872eae2b8b5011c2e90ed14e57192984da062359896949ffff001d15c6aed8") + "010000004bd0b78e90c6b0f361f395535ac170980de0c8214380daefce31fd1100000000282c9db8313817b4835efab229872eae2b8b5011c2e90ed14e57192984da062359896949ffff001d15c6aed8" + ) /** Contains block headers where a proof of work change is valid */ object ValidPOWChange { - //this is the first block in the 2016 block proof of work difficulty change interval - //https://blockstream.info/block/0000000000000000002567dc317da20ddb0d7ef922fe1f9c2375671654f9006c + // this is the first block in the 2016 block proof of work difficulty change interval + // https://blockstream.info/block/0000000000000000002567dc317da20ddb0d7ef922fe1f9c2375671654f9006c lazy val blockHeader564480 = BlockHeader.fromHex( - "000000200cd536b3eb1cd9c028e081f1455006276b293467c3e5170000000000000000007bc1b27489db01c85d38a4bc6d2280611e9804f506d83ad00d2a33ebd663992f76c7725c505b2e174fb90f55") + "000000200cd536b3eb1cd9c028e081f1455006276b293467c3e5170000000000000000007bc1b27489db01c85d38a4bc6d2280611e9804f506d83ad00d2a33ebd663992f76c7725c505b2e174fb90f55" + ) lazy val blockHeaderDb564480 = BlockHeaderDbHelper.fromBlockHeader( 564480, BlockHeader.getBlockProof(blockHeader564480), - blockHeader564480) + blockHeader564480 + ) lazy val blockHeader566494 = BlockHeader.fromHex( - "00000020ea2cb07d670ddb7a158e72ddfcfd9e1b9bf4459278bb240000000000000000004fb33054d79de69bb84b4d5c7dd87d80473c416320427a882c72108f7e43fd0c3d3e855c505b2e178f328fe2") + "00000020ea2cb07d670ddb7a158e72ddfcfd9e1b9bf4459278bb240000000000000000004fb33054d79de69bb84b4d5c7dd87d80473c416320427a882c72108f7e43fd0c3d3e855c505b2e178f328fe2" + ) lazy val blockHeaderDb566494 = BlockHeaderDbHelper.fromBlockHeader( 566594, BlockHeader.getBlockProof(blockHeader566494), - blockHeader566494) + blockHeader566494 + ) lazy val blockHeader566495 = BlockHeader.fromHex( - "000000202164d8c4e5246ab003fdebe36c697b9418aa454ec4190d00000000000000000059134ad5aaad38a0e75946c7d4cb09b3ad45b459070195dd564cde193cf0ef29c33e855c505b2e17f61af734") + "000000202164d8c4e5246ab003fdebe36c697b9418aa454ec4190d00000000000000000059134ad5aaad38a0e75946c7d4cb09b3ad45b459070195dd564cde193cf0ef29c33e855c505b2e17f61af734" + ) lazy val blockHeaderDb566495 = { val chainWork = blockHeaderDb566494.chainWork + BlockHeader.getBlockProof( - blockHeader566495) + blockHeader566495 + ) BlockHeaderDbHelper.fromBlockHeader(566495, chainWork, blockHeader566495) } - //https://blockstream.info/block/00000000000000000015fea169c62eb0a1161aba36932ca32bc3785cbb3480bf + // https://blockstream.info/block/00000000000000000015fea169c62eb0a1161aba36932ca32bc3785cbb3480bf lazy val blockHeader566496 = BlockHeader.fromHex( - "000000201b61e8961710991a47ff8187d946d93e4fb33569c09622000000000000000000d0098658f53531e6e67fc9448986b5a8f994da42d746079eabe10f55e561e243103f855c17612e1735c4afdb") + "000000201b61e8961710991a47ff8187d946d93e4fb33569c09622000000000000000000d0098658f53531e6e67fc9448986b5a8f994da42d746079eabe10f55e561e243103f855c17612e1735c4afdb" + ) lazy val blockHeaderDb566496 = { val chainWork = blockHeaderDb566495.chainWork + BlockHeader.getBlockProof( - blockHeader566496) + blockHeader566496 + ) BlockHeaderDbHelper.fromBlockHeader(566496, chainWork, blockHeader566496) } } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCFeeTestUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCFeeTestUtil.scala index f6a504c944..52d34c492a 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCFeeTestUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCFeeTestUtil.scala @@ -12,7 +12,8 @@ object DLCFeeTestUtil extends Assertions { fundingTx: Transaction, closingTx: Transaction, fundingTxSigs: Int = 2, - closingTxSigs: Int = 2): Assertion = { + closingTxSigs: Int = 2 + ): Assertion = { val feeRate = builder.feeRate val finalizer = builder.fundingTxFinalizer val expectedFundingFee = @@ -31,31 +32,34 @@ object DLCFeeTestUtil extends Assertions { val closingOutput = closingTx.outputs.map(_.value).sum val actualClosingFee = closingInput - closingOutput - /** Actual Fee Rate = Actual Fee / Ceil(Actual Weight / 4.0) - * Expected Fee Rate = Expected Fee / Ceil(Expected Weight / 4.0) + /** Actual Fee Rate = Actual Fee / Ceil(Actual Weight / 4.0) Expected Fee + * Rate = Expected Fee / Ceil(Expected Weight / 4.0) * * Expected Fee = Actual Fee (yay!) * - * Expected Weight - #sigs - 4 <= Actual Weight <= Expected Weight - * The right comparison is true because Expected Weight is designed to be an upper bound. - * The left comparison is true because the possible savings are from one weight being saved per - * signature, and 1 vbyte = 4 weight being saved if rounding works out well between both parites. + * Expected Weight - #sigs - 4 <= Actual Weight <= Expected Weight The + * right comparison is true because Expected Weight is designed to be an + * upper bound. The left comparison is true because the possible savings + * are from one weight being saved per signature, and 1 vbyte = 4 weight + * being saved if rounding works out well between both parites. * * Because of these comparisons, we can derive * - * Lower Bound Fee Rate = Actual Fee / (Ceil((Actual Weight + #sigs)/4.0) + 1) - * Upper Bound Fee Rate = Actual Fee / Ceil(Actual Weight/4.0) + * Lower Bound Fee Rate = Actual Fee / (Ceil((Actual Weight + #sigs)/4.0) + + * 1) Upper Bound Fee Rate = Actual Fee / Ceil(Actual Weight/4.0) * - * So that these two fee rates correspond to vbyte amounts 1 apart and represent the - * actual fee rate but allowing for signature size variation after which we should match - * the expected fee rate. This function asserts: - * Lower Bound Fee Rate <= Expected Fee Rate <= Upper Bound Fee Rate + * So that these two fee rates correspond to vbyte amounts 1 apart and + * represent the actual fee rate but allowing for signature size variation + * after which we should match the expected fee rate. This function + * asserts: Lower Bound Fee Rate <= Expected Fee Rate <= Upper Bound Fee + * Rate */ def feeRateBounds( tx: Transaction, actualFee: CurrencyUnit, numSignatures: Int, - missingOutputBytes: Long = 0): (Double, Double) = { + missingOutputBytes: Long = 0 + ): (Double, Double) = { val vbytesLower = Math.ceil(tx.weight / 4.0) + missingOutputBytes val vbytesUpper = @@ -82,35 +86,51 @@ object DLCFeeTestUtil extends Assertions { val acceptOutputBytes = 9 + builder.acceptFinalAddress.scriptPubKey.asmBytes.length - val (actualClosingFeeRateWithoutOfferLower, - actualClosingFeeRateWithoutOfferUpper) = - feeRateBounds(closingTx, - actualClosingFee, - closingTxSigs, - offerOutputBytes) + val ( + actualClosingFeeRateWithoutOfferLower, + actualClosingFeeRateWithoutOfferUpper + ) = + feeRateBounds( + closingTx, + actualClosingFee, + closingTxSigs, + offerOutputBytes + ) - val (actualClosingFeeRateWithoutAcceptLower, - actualClosingFeeRateWithoutAcceptUpper) = - feeRateBounds(closingTx, - actualClosingFee, - closingTxSigs, - acceptOutputBytes) + val ( + actualClosingFeeRateWithoutAcceptLower, + actualClosingFeeRateWithoutAcceptUpper + ) = + feeRateBounds( + closingTx, + actualClosingFee, + closingTxSigs, + acceptOutputBytes + ) def feeRateBetweenBounds( lowerBound: Double, - upperBound: Double): Boolean = { + upperBound: Double + ): Boolean = { feeRate.toLong >= lowerBound - 10 && feeRate.toLong <= upperBound + 10 } assert( - feeRateBetweenBounds(actualFundingFeeRateLower, - actualFundingFeeRateUpper)) + feeRateBetweenBounds(actualFundingFeeRateLower, actualFundingFeeRateUpper) + ) assert( - feeRateBetweenBounds(actualClosingFeeRateLower, - actualClosingFeeRateUpper) || - feeRateBetweenBounds(actualClosingFeeRateWithoutOfferLower, - actualClosingFeeRateWithoutOfferUpper) || - feeRateBetweenBounds(actualClosingFeeRateWithoutAcceptLower, - actualClosingFeeRateWithoutAcceptUpper)) + feeRateBetweenBounds( + actualClosingFeeRateLower, + actualClosingFeeRateUpper + ) || + feeRateBetweenBounds( + actualClosingFeeRateWithoutOfferLower, + actualClosingFeeRateWithoutOfferUpper + ) || + feeRateBetweenBounds( + actualClosingFeeRateWithoutAcceptLower, + actualClosingFeeRateWithoutAcceptUpper + ) + ) } } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTest.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTest.scala index dd3b54b7db..d3687a4ed1 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTest.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTest.scala @@ -86,24 +86,32 @@ trait DLCTest { val inputPubKeyAccept2B: ECPublicKey = inputPrivKeyAccept2B.publicKey val blockTimeToday: BlockTime = BlockTime( - UInt32(System.currentTimeMillis() / 1000)) + UInt32(System.currentTimeMillis() / 1000) + ) val offerFundingTx: Transaction = BaseTransaction( TransactionConstants.validLockVersion, Vector.empty, Vector( - TransactionOutput(offerInput, - P2WPKHWitnessSPKV0(inputPrivKeyOffer.publicKey))), + TransactionOutput( + offerInput, + P2WPKHWitnessSPKV0(inputPrivKeyOffer.publicKey) + ) + ), UInt32.zero ) val offerAddress: BitcoinAddress = - BitcoinAddress.fromScriptPubKey(P2WPKHWitnessSPKV0(inputPubKeyOffer), - RegTest) + BitcoinAddress.fromScriptPubKey( + P2WPKHWitnessSPKV0(inputPubKeyOffer), + RegTest + ) val offerNestedSPK: IfConditionalScriptPubKey = - NonStandardIfConditionalScriptPubKey(P2PKScriptPubKey(inputPubKeyOffer2A), - P2PKScriptPubKey(inputPubKeyOffer2B)) + NonStandardIfConditionalScriptPubKey( + P2PKScriptPubKey(inputPubKeyOffer2A), + P2PKScriptPubKey(inputPubKeyOffer2B) + ) val offerAddress2: BitcoinAddress = BitcoinAddress.fromScriptPubKey(P2WSHWitnessSPKV0(offerNestedSPK), RegTest) @@ -118,10 +126,11 @@ trait DLCTest { val offerFundingUtxos = Vector( SpendingInfoWithSerialId( ScriptSignatureParams( - P2WPKHV0InputInfo(outPoint = TransactionOutPoint(offerFundingTx.txId, - UInt32.zero), - amount = offerInput, - pubKey = inputPubKeyOffer), + P2WPKHV0InputInfo( + outPoint = TransactionOutPoint(offerFundingTx.txId, UInt32.zero), + amount = offerInput, + pubKey = inputPubKeyOffer + ), prevTransaction = offerFundingTx, signer = inputPrivKeyOffer, hashType = HashType.sigHashAll @@ -146,57 +155,72 @@ trait DLCTest { val offerFundingInputs: Vector[DLCFundingInput] = Vector( - DLCFundingInputP2WPKHV0(UInt64.zero, - offerFundingTx, - UInt32.zero, - TransactionConstants.enableRBFSequence), + DLCFundingInputP2WPKHV0( + UInt64.zero, + offerFundingTx, + UInt32.zero, + TransactionConstants.enableRBFSequence + ), DLCFundingInputP2WSHV0( UInt64.one, offerFundingTx2, UInt32.zero, TransactionConstants.enableRBFSequence, maxWitnessLen = - UInt16(offerFundingUtxos.last.spendingInfo.maxWitnessLen)) + UInt16(offerFundingUtxos.last.spendingInfo.maxWitnessLen) + ) ) val acceptFundingTx: Transaction = BaseTransaction( TransactionConstants.validLockVersion, Vector.empty, Vector( - TransactionOutput(acceptInput, - P2WPKHWitnessSPKV0(inputPrivKeyAccept.publicKey))), + TransactionOutput( + acceptInput, + P2WPKHWitnessSPKV0(inputPrivKeyAccept.publicKey) + ) + ), UInt32.zero ) val acceptAddress: BitcoinAddress = - BitcoinAddress.fromScriptPubKey(P2WPKHWitnessSPKV0(inputPubKeyAccept), - RegTest) + BitcoinAddress.fromScriptPubKey( + P2WPKHWitnessSPKV0(inputPubKeyAccept), + RegTest + ) val acceptNestedSPK: MultiSignatureScriptPubKey = - MultiSignatureScriptPubKey(2, - Vector(inputPubKeyAccept2A, inputPubKeyAccept2B)) + MultiSignatureScriptPubKey( + 2, + Vector(inputPubKeyAccept2A, inputPubKeyAccept2B) + ) val acceptAddress2: BitcoinAddress = BitcoinAddress.fromScriptPubKey( P2SHScriptPubKey(P2WSHWitnessSPKV0(acceptNestedSPK)), - RegTest) + RegTest + ) val acceptFundingTx2: Transaction = BaseTransaction( TransactionConstants.validLockVersion, Vector.empty, Vector( - TransactionOutput(acceptInput, - P2SHScriptPubKey(P2WSHWitnessSPKV0(acceptNestedSPK)))), + TransactionOutput( + acceptInput, + P2SHScriptPubKey(P2WSHWitnessSPKV0(acceptNestedSPK)) + ) + ), UInt32.zero ) val acceptFundingUtxos = Vector( SpendingInfoWithSerialId( ScriptSignatureParams( - P2WPKHV0InputInfo(outPoint = TransactionOutPoint(acceptFundingTx.txId, - UInt32.zero), - amount = acceptInput, - pubKey = inputPubKeyAccept), + P2WPKHV0InputInfo( + outPoint = TransactionOutPoint(acceptFundingTx.txId, UInt32.zero), + amount = acceptInput, + pubKey = inputPubKeyAccept + ), prevTransaction = acceptFundingTx, signer = inputPrivKeyAccept, hashType = HashType.sigHashAll @@ -221,10 +245,12 @@ trait DLCTest { val acceptFundingInputs: Vector[DLCFundingInput] = Vector( - DLCFundingInputP2WPKHV0(UInt64(3), - acceptFundingTx, - UInt32.zero, - TransactionConstants.enableRBFSequence), + DLCFundingInputP2WPKHV0( + UInt64(3), + acceptFundingTx, + UInt32.zero, + TransactionConstants.enableRBFSequence + ), DLCFundingInputP2SHSegwit( inputSerialId = UInt64(4), prevTx = acceptFundingTx2, @@ -237,12 +263,14 @@ trait DLCTest { ) val offerChangeSPK: P2WPKHWitnessSPKV0 = P2WPKHWitnessSPKV0( - ECPublicKey.freshPublicKey) + ECPublicKey.freshPublicKey + ) val offerChangeSerialId: UInt64 = UInt64.one val acceptChangeSPK: P2WPKHWitnessSPKV0 = P2WPKHWitnessSPKV0( - ECPublicKey.freshPublicKey) + ECPublicKey.freshPublicKey + ) val acceptChangeSerialId: UInt64 = UInt64(2) @@ -261,8 +289,10 @@ trait DLCTest { val acceptPayoutSerialId: UInt64 = UInt64.one val timeouts: DLCTimeouts = - DLCTimeouts(blockTimeToday, - BlockTime(UInt32(blockTimeToday.time.toLong + 1))) + DLCTimeouts( + blockTimeToday, + BlockTime(UInt32(blockTimeToday.time.toLong + 1)) + ) val feeRate: SatoshisPerVirtualByte = SatoshisPerVirtualByte(Satoshis(10)) @@ -277,14 +307,17 @@ trait DLCTest { isNumeric: Boolean, threshold: Int, numOracles: Int, - paramsOpt: Option[OracleParamsV0TLV]): SingleContractParams = { + paramsOpt: Option[OracleParamsV0TLV] + ): SingleContractParams = { if (isNumeric) { EnumContractParams(numDigitsOrOutcomes, threshold, numOracles) } else { - NumericContractParams(numDigitsOrOutcomes, - threshold, - numOracles, - paramsOpt) + NumericContractParams( + numDigitsOrOutcomes, + threshold, + numOracles, + paramsOpt + ) } } } @@ -292,19 +325,19 @@ trait DLCTest { case class EnumContractParams( numOutcomes: Int, oracleThreshold: Int, - numOracles: Int) - extends SingleContractParams + numOracles: Int + ) extends SingleContractParams case class NumericContractParams( numDigits: Int, oracleThreshold: Int, numOracles: Int, - paramsOpt: Option[OracleParamsV0TLV] = None) - extends SingleContractParams + paramsOpt: Option[OracleParamsV0TLV] = None + ) extends SingleContractParams case class DisjointUnionContractParams( - singleParams: Vector[SingleContractParams]) - extends ContractParams + singleParams: Vector[SingleContractParams] + ) extends ContractParams def constructDLCClientsFromInfos( offerInfo: ContractInfo, @@ -320,17 +353,16 @@ trait DLCTest { this.acceptFundingUtxos, acceptFundingInputs: Vector[DLCFundingInput] = this.acceptFundingInputs, feeRate: SatoshisPerVirtualByte = this.feeRate, - timeouts: DLCTimeouts = this.timeouts)(implicit - ec: ExecutionContext): (TestDLCClient, TestDLCClient) = { + timeouts: DLCTimeouts = this.timeouts + )(implicit ec: ExecutionContext): (TestDLCClient, TestDLCClient) = { val offerDLC = TestDLCClient( outcomes = offerInfo, isInitiator = true, fundingPrivKey = offerFundingPrivKey, payoutPrivKey = offerPayoutPrivKey, payoutSerialId = offerPayoutSerialId, - remotePubKeys = DLCPublicKeys.fromPrivKeys(acceptFundingPrivKey, - acceptPayoutPrivKey, - RegTest), + remotePubKeys = DLCPublicKeys + .fromPrivKeys(acceptFundingPrivKey, acceptPayoutPrivKey, RegTest), remotePayoutSerialId = acceptPayoutSerialId, input = offerInput, remoteInput = acceptInput, @@ -353,9 +385,8 @@ trait DLCTest { fundingPrivKey = acceptFundingPrivKey, payoutPrivKey = acceptPayoutPrivKey, payoutSerialId = acceptPayoutSerialId, - remotePubKeys = DLCPublicKeys.fromPrivKeys(offerFundingPrivKey, - offerPayoutPrivKey, - RegTest), + remotePubKeys = DLCPublicKeys + .fromPrivKeys(offerFundingPrivKey, offerPayoutPrivKey, RegTest), remotePayoutSerialId = offerPayoutSerialId, input = acceptInput, remoteInput = offerInput, @@ -377,7 +408,8 @@ trait DLCTest { def constructEnumContractInfos( params: EnumContractParams, - oracleShift: Int = 0): (SingleContractInfo, SingleContractInfo) = { + oracleShift: Int = 0 + ): (SingleContractInfo, SingleContractInfo) = { val outcomeStrs = DLCTestUtil.genOutcomes(params.numOutcomes) val outcomes = outcomeStrs.map(EnumOutcome.apply) @@ -387,7 +419,8 @@ trait DLCTest { .zip( preCommittedRsPerOracle .slice(oracleShift, oracleShift + params.numOracles) - .map(_.head)) + .map(_.head) + ) .map { case (privKey, rVal) => OracleAnnouncementV0TLV.dummyForEventsAndKeys(privKey, rVal, outcomes) } @@ -420,10 +453,10 @@ trait DLCTest { this.acceptFundingUtxos, acceptFundingInputs: Vector[DLCFundingInput] = this.acceptFundingInputs, feeRate: SatoshisPerVirtualByte = this.feeRate, - timeouts: DLCTimeouts = this.timeouts)(implicit ec: ExecutionContext): ( - TestDLCClient, - TestDLCClient, - Vector[EnumOutcome]) = { + timeouts: DLCTimeouts = this.timeouts + )(implicit + ec: ExecutionContext + ): (TestDLCClient, TestDLCClient, Vector[EnumOutcome]) = { val (offerInfo, acceptInfo) = constructEnumContractInfos(contractParams) val (offerDLC, acceptDLC) = constructDLCClientsFromInfos( @@ -451,17 +484,22 @@ trait DLCTest { def constructNumericContractInfos( params: NumericContractParams, - oracleShift: Int = 0): (SingleContractInfo, SingleContractInfo) = { + oracleShift: Int = 0 + ): (SingleContractInfo, SingleContractInfo) = { val (offerDesc, acceptDesc) = - DLCTestUtil.genMultiDigitContractInfo(params.numDigits, - totalInput, - numRounds = 4) + DLCTestUtil.genMultiDigitContractInfo( + params.numDigits, + totalInput, + numRounds = 4 + ) val announcements = oraclePrivKeys .slice(oracleShift, oracleShift + params.numOracles) - .zip(preCommittedRsPerOracle - .slice(oracleShift, oracleShift + params.numOracles)) + .zip( + preCommittedRsPerOracle + .slice(oracleShift, oracleShift + params.numOracles) + ) .map { case (privKey, rVals) => val nonces = OrderedNonces.fromUnsorted(rVals.take(params.numDigits).toVector) @@ -501,10 +539,10 @@ trait DLCTest { this.acceptFundingUtxos, acceptFundingInputs: Vector[DLCFundingInput] = this.acceptFundingInputs, feeRate: SatoshisPerVirtualByte = this.feeRate, - timeouts: DLCTimeouts = this.timeouts)(implicit ec: ExecutionContext): ( - TestDLCClient, - TestDLCClient, - Vector[UnsignedNumericOutcome]) = { + timeouts: DLCTimeouts = this.timeouts + )(implicit + ec: ExecutionContext + ): (TestDLCClient, TestDLCClient, Vector[UnsignedNumericOutcome]) = { val (offerInfo, acceptInfo) = constructNumericContractInfos(contractParams) val outcomes = offerInfo.allOutcomes.map(_.asInstanceOf[NumericOracleOutcome].outcome) @@ -540,10 +578,10 @@ trait DLCTest { this.acceptFundingUtxos, acceptFundingInputs: Vector[DLCFundingInput] = this.acceptFundingInputs, feeRate: SatoshisPerVirtualByte = this.feeRate, - timeouts: DLCTimeouts = this.timeouts)(implicit ec: ExecutionContext): ( - TestDLCClient, - TestDLCClient, - Vector[DLCOutcomeType]) = { + timeouts: DLCTimeouts = this.timeouts + )(implicit + ec: ExecutionContext + ): (TestDLCClient, TestDLCClient, Vector[DLCOutcomeType]) = { var oraclesSoFar = 0 val singleInfosAndOutcomes = contractParams.singleParams.map { case enumParams: EnumContractParams => @@ -558,7 +596,8 @@ trait DLCTest { constructNumericContractInfos(numericParams, oraclesSoFar) oraclesSoFar += numericParams.numOracles val outcomes = offerInfo.allOutcomes.map( - _.asInstanceOf[NumericOracleOutcome].outcome) + _.asInstanceOf[NumericOracleOutcome].outcome + ) (offerInfo, acceptInfo, outcomes) } val offerInfos = singleInfosAndOutcomes.map(_._1) @@ -599,10 +638,10 @@ trait DLCTest { this.acceptFundingUtxos, acceptFundingInputs: Vector[DLCFundingInput] = this.acceptFundingInputs, feeRate: SatoshisPerVirtualByte = this.feeRate, - timeouts: DLCTimeouts = this.timeouts)(implicit ec: ExecutionContext): ( - TestDLCClient, - TestDLCClient, - Vector[DLCOutcomeType]) = { + timeouts: DLCTimeouts = this.timeouts + )(implicit + ec: ExecutionContext + ): (TestDLCClient, TestDLCClient, Vector[DLCOutcomeType]) = { contractParams match { case enumParams: EnumContractParams => constructEnumDLCClients( @@ -657,8 +696,8 @@ trait DLCTest { dlcOffer: TestDLCClient, dlcAccept: TestDLCClient, fundingTxF: Future[SetupDLC] => Future[Transaction], - publishTransaction: Transaction => Future[_])(implicit - ec: ExecutionContext): Future[(SetupDLC, SetupDLC)] = { + publishTransaction: Transaction => Future[_] + )(implicit ec: ExecutionContext): Future[(SetupDLC, SetupDLC)] = { val offerSigReceiveP = { Promise[(CETSignatures, PartialSignature)]() } @@ -676,19 +715,22 @@ trait DLCTest { ( cetSigs: CETSignatures, refundSig: PartialSignature, - fundingSigs: FundingSignatures) => + fundingSigs: FundingSignatures + ) => val _ = acceptSigReceiveP.success((cetSigs, refundSig, fundingSigs)) FutureUtil.unit } - val acceptSetupF = dlcAccept.setupDLCAccept(sendSigs = sendAcceptSigs, - getSigs = - acceptSigReceiveP.future) + val acceptSetupF = dlcAccept.setupDLCAccept( + sendSigs = sendAcceptSigs, + getSigs = acceptSigReceiveP.future + ) - val offerSetupF = dlcOffer.setupDLCOffer(getSigs = offerSigReceiveP.future, - sendSigs = sendOfferSigs, - getFundingTx = - fundingTxF(acceptSetupF)) + val offerSetupF = dlcOffer.setupDLCOffer( + getSigs = offerSigReceiveP.future, + sendSigs = sendOfferSigs, + getFundingTx = fundingTxF(acceptSetupF) + ) for { acceptSetup <- acceptSetupF @@ -706,22 +748,22 @@ trait DLCTest { } def setupDLC(dlcOffer: TestDLCClient, dlcAccept: TestDLCClient)(implicit - ec: ExecutionContext): Future[(SetupDLC, SetupDLC)] = { + ec: ExecutionContext + ): Future[(SetupDLC, SetupDLC)] = { - setupDLC(dlcOffer, - dlcAccept, - _.map(_.fundingTx), - _ => Future.successful(())) + setupDLC( + dlcOffer, + dlcAccept, + _.map(_.fundingTx), + _ => Future.successful(()) + ) } - def constructAndSetupDLC(contractParams: ContractParams)(implicit - ec: ExecutionContext): Future[ - ( - TestDLCClient, - SetupDLC, - TestDLCClient, - SetupDLC, - Vector[DLCOutcomeType])] = { + def constructAndSetupDLC( + contractParams: ContractParams + )(implicit ec: ExecutionContext): Future[ + (TestDLCClient, SetupDLC, TestDLCClient, SetupDLC, Vector[DLCOutcomeType]) + ] = { val (offerDLC, acceptDLC, outcomes) = constructDLCClients(contractParams) for { @@ -734,11 +776,14 @@ trait DLCTest { oracleInfo: EnumSingleOracleInfo, outcome: String, privKey: ECPrivateKey = oraclePrivKey, - kVal: ECPrivateKey = preCommittedK): EnumOracleSignature = { - val sig = privKey.schnorrSignWithNonce(CryptoUtil - .sha256DLCAttestation(outcome) - .bytes, - kVal) + kVal: ECPrivateKey = preCommittedK + ): EnumOracleSignature = { + val sig = privKey.schnorrSignWithNonce( + CryptoUtil + .sha256DLCAttestation(outcome) + .bytes, + kVal + ) EnumOracleSignature(oracleInfo, sig) } @@ -747,7 +792,8 @@ trait DLCTest { chosenOracles: Vector[Int], contractInfo: SingleContractInfo, outcomes: Vector[DLCOutcomeType], - outcomeIndex: Long): EnumOracleOutcome = { + outcomeIndex: Long + ): EnumOracleOutcome = { outcomes(outcomeIndex.toInt) match { case outcome: EnumOutcome => val oracles = chosenOracles @@ -760,17 +806,20 @@ trait DLCTest { } def genEnumOracleSignatures( - outcome: EnumOracleOutcome): Vector[EnumOracleSignature] = { + outcome: EnumOracleOutcome + ): Vector[EnumOracleSignature] = { outcome.oracles.map { oracle => val index = oraclePubKeys.zipWithIndex .find(_._1 == oracle.publicKey) .get ._2 - genEnumOracleSignature(oracle, - outcome.outcome.outcome, - oraclePrivKeys(index), - preCommittedKsPerOracle(index).head) + genEnumOracleSignature( + oracle, + outcome.outcome.outcome, + oraclePrivKeys(index), + preCommittedKsPerOracle(index).head + ) } } @@ -778,7 +827,8 @@ trait DLCTest { chosenOracles: Vector[Int], contractInfo: SingleContractInfo, outcomes: Vector[DLCOutcomeType], - outcomeIndex: Long): Vector[EnumOracleSignature] = { + outcomeIndex: Long + ): Vector[EnumOracleSignature] = { val outcome = genEnumOracleOutcome(chosenOracles, contractInfo, outcomes, outcomeIndex) @@ -789,25 +839,30 @@ trait DLCTest { def computeNumericOracleSignatures( digits: Vector[Int], privKey: ECPrivateKey = oraclePrivKey, - kVals: Vector[ECPrivateKey] = - preCommittedKs): OrderedSchnorrSignatures = { + kVals: Vector[ECPrivateKey] = preCommittedKs + ): OrderedSchnorrSignatures = { val unsorted = digits.zip(kVals.take(digits.length)).map { case (digit, kValue) => - privKey.schnorrSignWithNonce(CryptoUtil - .sha256DLCAttestation(digit.toString) - .bytes, - kValue) + privKey.schnorrSignWithNonce( + CryptoUtil + .sha256DLCAttestation(digit.toString) + .bytes, + kValue + ) } OrderedSchnorrSignatures.fromUnsorted(unsorted) } - /** Deterministically chooses an outcome from the middle third of the interesting possible outcomes. */ + /** Deterministically chooses an outcome from the middle third of the + * interesting possible outcomes. + */ def computeNumericOutcome( numDigits: Int, desc: NumericContractDescriptor, outcomes: Vector[DLCOutcomeType], - outcomeIndex: Long): Vector[Int] = { + outcomeIndex: Long + ): Vector[Int] = { val points = desc.outcomeValueFunc.endpoints val left = points(1).outcome @@ -821,7 +876,7 @@ trait DLCTest { CETCalculator.searchForNumericOutcome(fullDigits, outcomes) match { case Some(UnsignedNumericOutcome(digits)) => digits - case None => Assertions.fail(s"Couldn't find outcome for $outcomeIndex") + case None => Assertions.fail(s"Couldn't find outcome for $outcomeIndex") } } @@ -829,7 +884,8 @@ trait DLCTest { chosenOracles: Vector[Int], contractInfo: ContractInfo, digits: Vector[Int], - paramsOpt: Option[OracleParamsV0TLV]): NumericOracleOutcome = { + paramsOpt: Option[OracleParamsV0TLV] + ): NumericOracleOutcome = { contractInfo.contracts.head.contractOraclePair match { case e: ContractOraclePair.EnumPair => Assertions.fail(s"Expected Numeric Contract, got enum=$e") @@ -837,7 +893,8 @@ trait DLCTest { lazy val possibleOutcomesOpt = paramsOpt.map { _ => contractInfo.allOutcomes .map( - _.asInstanceOf[NumericOracleOutcome].oraclesAndOutcomes.map(_._2)) + _.asInstanceOf[NumericOracleOutcome].oraclesAndOutcomes.map(_._2) + ) .filter(_.head.digits == digits) .map(_.apply(1).digits) .sorted(NumberUtil.lexicographicalOrdering[Int]) @@ -873,7 +930,8 @@ trait DLCTest { contractInfo: SingleContractInfo, outcomes: Vector[DLCOutcomeType], outcomeIndex: Long, - paramsOpt: Option[OracleParamsV0TLV]): NumericOracleOutcome = { + paramsOpt: Option[OracleParamsV0TLV] + ): NumericOracleOutcome = { contractInfo.contractOraclePair match { case e: ContractOraclePair.EnumPair => Assertions.fail(s"Expected Numeric Contract, got enum=$e") @@ -885,7 +943,8 @@ trait DLCTest { } def genNumericOracleSignatures( - outcome: NumericOracleOutcome): Vector[NumericOracleSignatures] = { + outcome: NumericOracleOutcome + ): Vector[NumericOracleSignatures] = { outcome.oraclesAndOutcomes.map { case (singleOracleInfo, digitsToSign) => val index = oraclePubKeys.zipWithIndex .find(_._1 == singleOracleInfo.publicKey) @@ -896,9 +955,11 @@ trait DLCTest { singleOracleInfo.announcement.eventTLV.eventDescriptor.noncesNeeded - digitsToSign.digits.length val paddedDigits = digitsToSign.digits ++ Vector.fill(neededPadding)(0) val sigs = - computeNumericOracleSignatures(paddedDigits, - oraclePrivKeys(index), - preCommittedKsPerOracle(index)) + computeNumericOracleSignatures( + paddedDigits, + oraclePrivKeys(index), + preCommittedKsPerOracle(index) + ) NumericOracleSignaturesSorted(singleOracleInfo, sigs) } @@ -910,13 +971,16 @@ trait DLCTest { contractInfo: SingleContractInfo, outcomes: Vector[DLCOutcomeType], outcomeIndex: Long, - paramsOpt: Option[OracleParamsV0TLV]): Vector[NumericOracleSignatures] = { - val outcome = genNumericOracleOutcome(numDigits, - chosenOracles, - contractInfo, - outcomes, - outcomeIndex, - paramsOpt) + paramsOpt: Option[OracleParamsV0TLV] + ): Vector[NumericOracleSignatures] = { + val outcome = genNumericOracleOutcome( + numDigits, + chosenOracles, + contractInfo, + outcomes, + outcomeIndex, + paramsOpt + ) genNumericOracleSignatures(outcome) } @@ -926,7 +990,8 @@ trait DLCTest { contractInfo: SingleContractInfo, outcomes: Vector[DLCOutcomeType], outcomeIndex: Long, - paramsOpt: Option[OracleParamsV0TLV]): OracleOutcome = { + paramsOpt: Option[OracleParamsV0TLV] + ): OracleOutcome = { val oracleInfo = contractInfo.oracleInfos.head val oracleIndices = @@ -937,12 +1002,14 @@ trait DLCTest { if (!isNumeric) { genEnumOracleOutcome(chosenOracles, contractInfo, outcomes, outcomeIndex) } else { - genNumericOracleOutcome(numOutcomesOrDigits, - chosenOracles, - contractInfo, - outcomes, - outcomeIndex, - paramsOpt) + genNumericOracleOutcome( + numOutcomesOrDigits, + chosenOracles, + contractInfo, + outcomes, + outcomeIndex, + paramsOpt + ) } } @@ -952,15 +1019,16 @@ trait DLCTest { contractInfo: SingleContractInfo, outcomes: Vector[DLCOutcomeType], outcomeIndex: Long, - paramsOpt: Option[OracleParamsV0TLV]): ( - OracleOutcome, - Vector[OracleSignatures]) = { - val outcome = genOracleOutcome(numOutcomesOrDigits, - isNumeric, - contractInfo, - outcomes, - outcomeIndex, - paramsOpt) + paramsOpt: Option[OracleParamsV0TLV] + ): (OracleOutcome, Vector[OracleSignatures]) = { + val outcome = genOracleOutcome( + numOutcomesOrDigits, + isNumeric, + contractInfo, + outcomes, + outcomeIndex, + paramsOpt + ) val sigs = genOracleSignatures(outcome) (outcome, sigs) @@ -979,20 +1047,24 @@ trait DLCTest { contractInfo: SingleContractInfo, outcomes: Vector[DLCOutcomeType], outcomeIndex: Long, - paramsOpt: Option[OracleParamsV0TLV]): Vector[OracleSignatures] = { - val (_, sigs) = genOracleOutcomeAndSignatures(numOutcomesOrDigits, - isNumeric, - contractInfo, - outcomes, - outcomeIndex, - paramsOpt) + paramsOpt: Option[OracleParamsV0TLV] + ): Vector[OracleSignatures] = { + val (_, sigs) = genOracleOutcomeAndSignatures( + numOutcomesOrDigits, + isNumeric, + contractInfo, + outcomes, + outcomeIndex, + paramsOpt + ) sigs } def validateOutcome( outcome: DLCOutcome, dlcOffer: TestDLCClient, - dlcAccept: TestDLCClient): Assertion = { + dlcAccept: TestDLCClient + ): Assertion = { val fundingTx = outcome.fundingTx assert(noEmptySPKOutputs(fundingTx)) @@ -1004,8 +1076,8 @@ trait DLCTest { TransactionOutPoint(fundingTx.txId, UInt32(fundOutputIndex)), fundingTx.outputs(fundOutputIndex).value, P2WSHWitnessV0( - MultiSignatureScriptPubKey(2, - signers.map(_.publicKey).sortBy(_.hex))), + MultiSignatureScriptPubKey(2, signers.map(_.publicKey).sortBy(_.hex)) + ), ConditionalPath.NoCondition ), fundingTx, @@ -1015,58 +1087,68 @@ trait DLCTest { outcome match { case ExecutedDLCOutcome(fundingTx, cet, _, _) => - DLCFeeTestUtil.validateFees(dlcOffer.dlcTxBuilder, - fundingTx, - cet, - fundingTxSigs = 5) + DLCFeeTestUtil.validateFees( + dlcOffer.dlcTxBuilder, + fundingTx, + cet, + fundingTxSigs = 5 + ) assert(noEmptySPKOutputs(cet)) assert(BitcoinScriptUtil.verifyScript(cet, Vector(closingSpendingInfo))) case RefundDLCOutcome(fundingTx, refundTx) => - DLCFeeTestUtil.validateFees(dlcOffer.dlcTxBuilder, - fundingTx, - refundTx, - fundingTxSigs = 5) + DLCFeeTestUtil.validateFees( + dlcOffer.dlcTxBuilder, + fundingTx, + refundTx, + fundingTxSigs = 5 + ) assert(noEmptySPKOutputs(refundTx)) assert( - BitcoinScriptUtil.verifyScript(refundTx, Vector(closingSpendingInfo))) + BitcoinScriptUtil.verifyScript(refundTx, Vector(closingSpendingInfo)) + ) } } def executeForCase(outcomeIndex: Long, contractParams: ContractParams)( - implicit ec: ExecutionContext): Future[Assertion] = { + implicit ec: ExecutionContext + ): Future[Assertion] = { executeForCase(contractIndex = 0, outcomeIndex, contractParams) } def executeForCase( contractIndex: Int, outcomeIndex: Long, - contractParams: ContractParams)(implicit - ec: ExecutionContext): Future[Assertion] = { + contractParams: ContractParams + )(implicit ec: ExecutionContext): Future[Assertion] = { constructAndSetupDLC(contractParams) .flatMap { case (dlcOffer, offerSetup, dlcAccept, acceptSetup, outcomes) => - executeForOutcome(outcomeIndex, - dlcOffer, - offerSetup, - dlcAccept, - acceptSetup, - outcomes, - contractIndex) + executeForOutcome( + outcomeIndex, + dlcOffer, + offerSetup, + dlcAccept, + acceptSetup, + outcomes, + contractIndex + ) } } def executeForCases( outcomeIndices: Vector[Long], - contractParams: ContractParams)(implicit - ec: ExecutionContext): Future[Assertion] = { - executeForCasesInUnion(outcomeIndices = outcomeIndices.map((0, _)), - contractParams = contractParams) + contractParams: ContractParams + )(implicit ec: ExecutionContext): Future[Assertion] = { + executeForCasesInUnion( + outcomeIndices = outcomeIndices.map((0, _)), + contractParams = contractParams + ) } def executeForCasesInUnion( outcomeIndices: Vector[(Int, Long)], - contractParams: ContractParams)(implicit - ec: ExecutionContext): Future[Assertion] = { + contractParams: ContractParams + )(implicit ec: ExecutionContext): Future[Assertion] = { constructAndSetupDLC(contractParams) .flatMap { case (dlcOffer, offerSetup, dlcAccept, acceptSetup, outcomes) => @@ -1094,8 +1176,8 @@ trait DLCTest { dlcAccept: TestDLCClient, acceptSetup: SetupDLC, outcomes: Vector[DLCOutcomeType], - contractIndex: Int = 0)(implicit - ec: ExecutionContext): Future[Assertion] = { + contractIndex: Int = 0 + )(implicit ec: ExecutionContext): Future[Assertion] = { val contractInfo = dlcOffer.offer.contractInfo val contractSizes = contractInfo.contracts.map { contract => contract.allOutcomes.length @@ -1108,7 +1190,8 @@ trait DLCTest { val possibleOutcomesForContract = outcomes.slice( indexOfOutcomeStart, - indexOfOutcomeStart + singleContractInfo.allOutcomes.length) + indexOfOutcomeStart + singleContractInfo.allOutcomes.length + ) val contractDesc = singleContractInfo.contractDescriptor val (numOutcomes, isMultiDigit, paramsOpt) = contractDesc match { @@ -1116,11 +1199,13 @@ trait DLCTest { (outcomeValueMap.length, false, None) case NumericContractDescriptor(_, numDigits, _) => val paramsOpt = contractInfo.oracleInfos.head match { - case NumericMultiOracleInfo(_, - _, - maxErrorExp, - minFailExp, - maximizeCoverage) => + case NumericMultiOracleInfo( + _, + _, + maxErrorExp, + minFailExp, + maximizeCoverage + ) => Some(OracleParamsV0TLV(maxErrorExp, minFailExp, maximizeCoverage)) case _: OracleInfo => None } @@ -1150,8 +1235,9 @@ trait DLCTest { } } - def executeRefundCase(contractParams: ContractParams)(implicit - ec: ExecutionContext): Future[Assertion] = { + def executeRefundCase( + contractParams: ContractParams + )(implicit ec: ExecutionContext): Future[Assertion] = { constructAndSetupDLC(contractParams) .map { case (dlcOffer, offerSetup, dlcAccept, acceptSetup, _) => val offerOutcome = dlcOffer.executeRefundDLC(offerSetup) @@ -1171,8 +1257,8 @@ trait DLCTest { acceptSetup: SetupDLC, dlcAccept: TestDLCClient, oracleSigs: Vector[OracleSignatures], - outcome: OracleOutcome)(implicit - ec: ExecutionContext): Future[Assertion] = { + outcome: OracleOutcome + )(implicit ec: ExecutionContext): Future[Assertion] = { val aggR = outcome.aggregateNonce val aggS = outcome match { case EnumOracleOutcome(oracles, _) => @@ -1237,20 +1323,24 @@ trait DLCTest { val (offerOracleSig, offerDLCOutcome) = DLCStatus - .calculateOutcomeAndSig(isInitiator = true, - offer, - accept, - sign, - acceptOutcome.cet) + .calculateOutcomeAndSig( + isInitiator = true, + offer, + accept, + sign, + acceptOutcome.cet + ) .get val (acceptOracleSig, acceptDLCOutcome) = DLCStatus - .calculateOutcomeAndSig(isInitiator = false, - offer, - accept, - sign, - offerOutcome.cet) + .calculateOutcomeAndSig( + isInitiator = false, + offer, + accept, + sign, + offerOutcome.cet + ) .get assert(offerDLCOutcome == outcome) @@ -1262,8 +1352,8 @@ trait DLCTest { /** Synchronously runs the test function on each paramsToTest in turn. */ def runTestsForParam[T](paramsToTest: Vector[T])( - test: T => Future[Assertion])(implicit - ec: ExecutionContext): Future[Assertion] = { + test: T => Future[Assertion] + )(implicit ec: ExecutionContext): Future[Assertion] = { paramsToTest.foldLeft(Future.successful(Assertions.succeed)) { case (fut, param) => fut.flatMap { _ => diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTestUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTestUtil.scala index 0d4fa1dfef..083683222a 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTestUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/DLCTestUtil.scala @@ -20,7 +20,8 @@ object DLCTestUtil { def genValues(size: Int, totalAmount: CurrencyUnit): Vector[Satoshis] = { val vals = if (size < 2) { throw new IllegalArgumentException( - s"Size must be at least two, got $size") + s"Size must be at least two, got $size" + ) } else if (size == 2) { Vector(totalAmount.satoshis, Satoshis.zero) } else { @@ -35,9 +36,8 @@ object DLCTestUtil { def genContractDescriptors( outcomes: Vector[String], - totalInput: CurrencyUnit): ( - EnumContractDescriptor, - EnumContractDescriptor) = { + totalInput: CurrencyUnit + ): (EnumContractDescriptor, EnumContractDescriptor) = { val outcomeMap = outcomes .map(EnumOutcome.apply) @@ -52,17 +52,16 @@ object DLCTestUtil { /** Generates a collared forward contract. * * If roundingIntervals is noRounding and numRounds > 0, then - * roundingIntervals is ignored and instead the contract is rounded - * in numRounds different ways in between the collars. - * Otherwise roundingIntervals is used. + * roundingIntervals is ignored and instead the contract is rounded in + * numRounds different ways in between the collars. Otherwise + * roundingIntervals is used. */ def genMultiDigitContractInfo( numDigits: Int, totalCollateral: CurrencyUnit, roundingIntervals: RoundingIntervals = RoundingIntervals.noRounding, - numRounds: Int = 0): ( - NumericContractDescriptor, - NumericContractDescriptor) = { + numRounds: Int = 0 + ): (NumericContractDescriptor, NumericContractDescriptor) = { val overMaxValue = Math.pow(2, numDigits).toLong // Left collar goes from [0, botCollar] val botCollar = NumberUtil.randomLong(overMaxValue / 2) @@ -91,8 +90,8 @@ object DLCTestUtil { val intervalStart = ((numRounds - num) * botCollar + num * topCollar) / numRounds val roundingMod = 1L << num - RoundingIntervals.IntervalStart(BigDecimal(intervalStart), - roundingMod) + RoundingIntervals + .IntervalStart(BigDecimal(intervalStart), roundingMod) } RoundingIntervals(intervalStarts) } else roundingIntervals diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/TestDLCClient.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/TestDLCClient.scala index ffae250293..e52c57a1b1 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/TestDLCClient.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/dlc/TestDLCClient.scala @@ -24,15 +24,21 @@ import org.bitcoins.crypto._ import scala.concurrent.{ExecutionContext, Future} -/** This case class allows for the construction and execution of - * Discreet Log Contracts between two parties running on this machine (for tests). +/** This case class allows for the construction and execution of Discreet Log + * Contracts between two parties running on this machine (for tests). * - * @param offer The DLCOffer associated with this DLC - * @param accept The DLCAccept (without sigs) associated with this DLC - * @param isInitiator True if this client sends the offer message - * @param fundingPrivKey This client's funding private key for this event - * @param payoutPrivKey This client's payout private key for this event - * @param fundingUtxos This client's funding BitcoinUTXOSpendingInfo collection + * @param offer + * The DLCOffer associated with this DLC + * @param accept + * The DLCAccept (without sigs) associated with this DLC + * @param isInitiator + * True if this client sends the offer message + * @param fundingPrivKey + * This client's funding private key for this event + * @param payoutPrivKey + * This client's payout private key for this event + * @param fundingUtxos + * This client's funding BitcoinUTXOSpendingInfo collection */ case class TestDLCClient( offer: DLCMessage.DLCOffer, @@ -40,16 +46,18 @@ case class TestDLCClient( isInitiator: Boolean, fundingPrivKey: ECPrivateKey, payoutPrivKey: ECPrivateKey, - fundingUtxos: Vector[ScriptSignatureParams[InputInfo]])(implicit - ec: ExecutionContext) { + fundingUtxos: Vector[ScriptSignatureParams[InputInfo]] +)(implicit ec: ExecutionContext) { val dlcTxBuilder: DLCTxBuilder = DLCTxBuilder(offer, accept) - val dlcTxSigner: DLCTxSigner = DLCTxSigner(dlcTxBuilder, - isInitiator, - fundingPrivKey, - payoutPrivKey, - RegTest, - fundingUtxos) + val dlcTxSigner: DLCTxSigner = DLCTxSigner( + dlcTxBuilder, + isInitiator, + fundingPrivKey, + payoutPrivKey, + RegTest, + fundingUtxos + ) private val dlcExecutor = DLCExecutor(dlcTxSigner) @@ -61,15 +69,14 @@ case class TestDLCClient( lazy val fundingTxIdBE: DoubleSha256DigestBE = fundingTx.txIdBE - /** Sets up the non-initiator's DLC given functions for sending - * CETSignatures to the initiator as well as receiving CETSignatures - * and FundingSignatures from them + /** Sets up the non-initiator's DLC given functions for sending CETSignatures + * to the initiator as well as receiving CETSignatures and FundingSignatures + * from them */ def setupDLCAccept( sendSigs: (CETSignatures, PartialSignature) => Future[Unit], - getSigs: Future[ - (CETSignatures, PartialSignature, FundingSignatures)]): Future[ - SetupDLC] = { + getSigs: Future[(CETSignatures, PartialSignature, FundingSignatures)] + ): Future[SetupDLC] = { require(!isInitiator, "You should call setupDLCOffer") for { @@ -85,9 +92,9 @@ case class TestDLCClient( } } - /** Sets up the initiator's DLC given functions for getting CETSignatures - * from the non-initiator as well as sending signatures to them, and lastly - * a Future which will be populated with the broadcasted (or relayed) fully + /** Sets up the initiator's DLC given functions for getting CETSignatures from + * the non-initiator as well as sending signatures to them, and lastly a + * Future which will be populated with the broadcasted (or relayed) fully * signed funding transaction */ def setupDLCOffer( @@ -95,8 +102,10 @@ case class TestDLCClient( sendSigs: ( CETSignatures, PartialSignature, - FundingSignatures) => Future[Unit], - getFundingTx: Future[Transaction]): Future[SetupDLC] = { + FundingSignatures + ) => Future[Unit], + getFundingTx: Future[Transaction] + ): Future[SetupDLC] = { require(isInitiator, "You should call setupDLCAccept") for { @@ -120,8 +129,8 @@ case class TestDLCClient( def executeDLC( dlcSetup: SetupDLC, - oracleSigsF: Future[Vector[OracleSignatures]]): Future[ - ExecutedDLCOutcome] = { + oracleSigsF: Future[Vector[OracleSignatures]] + ): Future[ExecutedDLCOutcome] = { oracleSigsF.map { oracleSigs => dlcExecutor.executeDLC(dlcSetup, oracleSigs) } @@ -154,7 +163,8 @@ object TestDLCClient { remoteChangeSPK: ScriptPubKey, remoteChangeSerialId: UInt64, fundOutputSerialId: UInt64, - network: BitcoinNetwork)(implicit ec: ExecutionContext): TestDLCClient = { + network: BitcoinNetwork + )(implicit ec: ExecutionContext): TestDLCClient = { val pubKeys = DLCPublicKeys.fromPrivKeys( fundingPrivKey, payoutPrivKey, @@ -183,46 +193,52 @@ object TestDLCClient { val remoteChangeAddress = BitcoinAddress.fromScriptPubKey(remoteChangeSPK, network) - val (offerOutcomes, - offerPubKeys, - offerPayoutSerialId, - offerInput, - offerFundingInputs, - offerChangeAddress, - offerChangeSerialId, - acceptPubKeys, - acceptPayoutSerialId, - acceptInput, - acceptFundingInputs, - acceptChangeAddress, - acceptChangeSerialId) = if (isInitiator) { - (outcomes, - pubKeys, - payoutSerialId, - input, - fundingInputs, - changeAddress, - changeSerialId, - remotePubKeys, - remotePayoutSerialId, - remoteInput, - remoteFundingInputs, - remoteChangeAddress, - remoteChangeSerialId) + val ( + offerOutcomes, + offerPubKeys, + offerPayoutSerialId, + offerInput, + offerFundingInputs, + offerChangeAddress, + offerChangeSerialId, + acceptPubKeys, + acceptPayoutSerialId, + acceptInput, + acceptFundingInputs, + acceptChangeAddress, + acceptChangeSerialId + ) = if (isInitiator) { + ( + outcomes, + pubKeys, + payoutSerialId, + input, + fundingInputs, + changeAddress, + changeSerialId, + remotePubKeys, + remotePayoutSerialId, + remoteInput, + remoteFundingInputs, + remoteChangeAddress, + remoteChangeSerialId + ) } else { - (remoteOutcomes, - remotePubKeys, - remotePayoutSerialId, - remoteInput, - remoteFundingInputs, - remoteChangeAddress, - remoteChangeSerialId, - pubKeys, - payoutSerialId, - input, - fundingInputs, - changeAddress, - changeSerialId) + ( + remoteOutcomes, + remotePubKeys, + remotePayoutSerialId, + remoteInput, + remoteFundingInputs, + remoteChangeAddress, + remoteChangeSerialId, + pubKeys, + payoutSerialId, + input, + fundingInputs, + changeAddress, + changeSerialId + ) } val offer = DLCMessage.DLCOffer( @@ -243,7 +259,8 @@ object TestDLCClient { case _: SingleContractInfo => DLCAccept.NoNegotiationFields case DisjointUnionContractInfo(contracts) => DLCAccept.NegotiationFieldsV2( - contracts.map(_ => DLCAccept.NoNegotiationFields)) + contracts.map(_ => DLCAccept.NoNegotiationFields) + ) } val accept = DLCMessage.DLCAcceptWithoutSigs( @@ -257,11 +274,13 @@ object TestDLCClient { tempContractId = offer.tempContractId ) - TestDLCClient(offer, - accept, - isInitiator, - fundingPrivKey, - payoutPrivKey, - fundingUtxos.map(_.spendingInfo)) + TestDLCClient( + offer, + accept, + isInitiator, + fundingPrivKey, + payoutPrivKey, + fundingUtxos.map(_.spendingInfo) + ) } } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/AddressGenerator.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/AddressGenerator.scala index bd126e86e9..88cc38bfdd 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/AddressGenerator.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/AddressGenerator.scala @@ -39,16 +39,19 @@ sealed trait AddressGenerator { def bech32mAddress: Gen[Bech32mAddress] = for { (witSPK, _) <- ScriptGenerators.witnessScriptPubKey.suchThat( - _._1.witnessVersion != WitnessVersion0) + _._1.witnessVersion != WitnessVersion0 + ) network <- ChainParamsGenerator.networkParams } yield Bech32mAddress(witSPK, network) def bitcoinAddress: Gen[BitcoinAddress] = - Gen.oneOf(p2pkhAddress, - decompressedP2pkhAddress, - p2shAddress, - bech32Address, - bech32mAddress) + Gen.oneOf( + p2pkhAddress, + decompressedP2pkhAddress, + p2shAddress, + bech32Address, + bech32mAddress + ) def address: Gen[Address] = bitcoinAddress } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/BlockchainElementsGenerator.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/BlockchainElementsGenerator.scala index 9fb91b63a2..bc7dfa4ebf 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/BlockchainElementsGenerator.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/BlockchainElementsGenerator.scala @@ -14,7 +14,9 @@ import scala.annotation.tailrec */ sealed abstract class BlockchainElementsGenerator { - /** Generates a block that contains the given txs, plus some more randomly generated ones */ + /** Generates a block that contains the given txs, plus some more randomly + * generated ones + */ def block(txs: Seq[Transaction]): Gen[Block] = for { randomNum <- Gen.choose(1, 10) @@ -24,8 +26,8 @@ sealed abstract class BlockchainElementsGenerator { header <- blockHeader(allTxs) } yield Block(header, allTxs) - /** Generates a random [[org.bitcoins.core.protocol.blockchain.Block Block]], note that we limit this - * to 10 transactions currently + /** Generates a random [[org.bitcoins.core.protocol.blockchain.Block Block]], + * note that we limit this to 10 transactions currently */ def block: Gen[Block] = for { @@ -33,7 +35,9 @@ sealed abstract class BlockchainElementsGenerator { txs <- TransactionGenerators.smallTransactions } yield Block(header, txs) - /** Generates a random [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] */ + /** Generates a random + * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] + */ def blockHeader: Gen[BlockHeader] = for { previousBlockHash <- CryptoGenerators.doubleSha256Digest @@ -41,7 +45,8 @@ sealed abstract class BlockchainElementsGenerator { } yield b /** Generates a random - * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] with the specified previousBlockHash + * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] with the + * specified previousBlockHash */ def blockHeader(previousBlockHash: DoubleSha256Digest): Gen[BlockHeader] = for { @@ -49,39 +54,46 @@ sealed abstract class BlockchainElementsGenerator { b <- blockHeader(previousBlockHash, nBits) } yield b - /** Generates a random [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] where you can specify - * the previousBlockHash and nBits + /** Generates a random + * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] where + * you can specify the previousBlockHash and nBits */ def blockHeader( previousBlockHash: DoubleSha256Digest, - nBits: UInt32): Gen[BlockHeader] = + nBits: UInt32 + ): Gen[BlockHeader] = for { numTxs <- Gen.choose(1, 5) txs <- Gen.listOfN(numTxs, TransactionGenerators.transaction) header <- blockHeader(previousBlockHash, nBits, txs) } yield header - /** Generates a [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]]] that has the fields - * set to the given values + /** Generates a + * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]]] that + * has the fields set to the given values */ def blockHeader( previousBlockHash: DoubleSha256Digest, nBits: UInt32, - txs: Seq[Transaction]): Gen[BlockHeader] = + txs: Seq[Transaction] + ): Gen[BlockHeader] = for { version <- NumberGenerator.int32s merkleRootHash = Merkle.computeMerkleRoot(txs) time <- NumberGenerator.uInt32s nonce <- NumberGenerator.uInt32s - } yield BlockHeader(version, - previousBlockHash, - merkleRootHash, - time, - nBits, - nonce) + } yield BlockHeader( + version, + previousBlockHash, + merkleRootHash, + time, + nBits, + nonce + ) - /** Generates a [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] that has a merkle root - * hash corresponding to the given txs + /** Generates a + * [[org.bitcoins.core.protocol.blockchain.BlockHeader BlockHeader]] that has + * a merkle root hash corresponding to the given txs */ def blockHeader(txs: Seq[Transaction]): Gen[BlockHeader] = for { @@ -90,9 +102,9 @@ sealed abstract class BlockchainElementsGenerator { header <- blockHeader(previousBlockHash, nBits, txs) } yield header - /** Generates a chain of valid headers of the size specified by num, - * 'valid' means their nBits are the same and each header properly - * references the previous block header's hash + /** Generates a chain of valid headers of the size specified by num, 'valid' + * means their nBits are the same and each header properly references the + * previous block header's hash */ def validHeaderChain(num: Long): Gen[Seq[BlockHeader]] = { blockHeader.flatMap { startHeader => @@ -102,11 +114,13 @@ sealed abstract class BlockchainElementsGenerator { def validHeaderChain( num: Long, - startHeader: BlockHeader): Gen[Seq[BlockHeader]] = { + startHeader: BlockHeader + ): Gen[Seq[BlockHeader]] = { @tailrec def loop( remainingHeaders: Long, - accum: Seq[BlockHeader]): Seq[BlockHeader] = { + accum: Seq[BlockHeader] + ): Seq[BlockHeader] = { if (remainingHeaders == 0) accum.reverse else { val nextHeader = buildBlockHeader(accum.head.hash, accum.head.nBits) @@ -118,15 +132,18 @@ sealed abstract class BlockchainElementsGenerator { private def buildBlockHeader( prevBlockHash: DoubleSha256Digest, - nBits: UInt32): BlockHeader = { - //nonce for the unique hash + nBits: UInt32 + ): BlockHeader = { + // nonce for the unique hash val nonce = NumberGenerator.uInt32s.sampleSome - BlockHeader(Int32.one, - prevBlockHash, - EmptyTransaction.txId, - UInt32.one, - nBits, - nonce) + BlockHeader( + Int32.one, + prevBlockHash, + EmptyTransaction.txId, + UInt32.one, + nBits, + nonce + ) } } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/BloomFilterGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/BloomFilterGenerators.scala index 75f6517dac..48c50123f5 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/BloomFilterGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/BloomFilterGenerators.scala @@ -19,7 +19,8 @@ abstract class BloomFilterGenerator { /** Loads a generic bloom filter with the given byte vectors and returns it */ def bloomFilter( - byteVectors: scala.collection.Seq[ByteVector]): Gen[BloomFilter] = + byteVectors: scala.collection.Seq[ByteVector] + ): Gen[BloomFilter] = for { filter <- bloomFilter } yield filter.insertByteVectors(byteVectors) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CreditingTxGen.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CreditingTxGen.scala index 220601a05f..c18489ce5d 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CreditingTxGen.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CreditingTxGen.scala @@ -49,27 +49,31 @@ sealed abstract class CreditingTxGen { } def nonP2WSHOutput: Gen[ScriptSignatureParams[InputInfo]] = { - //note, cannot put a p2wpkh here - Gen.oneOf(p2pkOutput, - p2pkhOutput, - /*p2pkWithTimeoutOutput,*/ - multiSigOutput, /*cltvOutput,*/ csvOutput, - multiSignatureWithTimeoutOutput, - conditionalOutput) + // note, cannot put a p2wpkh here + Gen.oneOf( + p2pkOutput, + p2pkhOutput, + /*p2pkWithTimeoutOutput,*/ + multiSigOutput, /*cltvOutput,*/ csvOutput, + multiSignatureWithTimeoutOutput, + conditionalOutput + ) } def nonP2WSHOutputs: Gen[Seq[ScriptSignatureParams[InputInfo]]] = Gen.choose(min, max).flatMap(n => Gen.listOfN(n, nonP2WSHOutput)) def rawOutput: Gen[ScriptSignatureParams[InputInfo]] = { - Gen.oneOf(p2pkOutput, - p2pkhOutput, - p2pkWithTimeoutOutput, - multiSigOutput, - cltvOutput, - csvOutput, - multiSignatureWithTimeoutOutput, - conditionalOutput) + Gen.oneOf( + p2pkOutput, + p2pkhOutput, + p2pkWithTimeoutOutput, + multiSigOutput, + cltvOutput, + csvOutput, + multiSignatureWithTimeoutOutput, + conditionalOutput + ) } def rawOutputs: Gen[Seq[ScriptSignatureParams[InputInfo]]] = @@ -102,7 +106,8 @@ sealed abstract class CreditingTxGen { P2SHNestedSegwitV0InputInfo(_, _, witness, _, _), _, _, - _) => + _ + ) => witness.stack.exists(_.length > ScriptInterpreter.MAX_PUSH_SIZE) case _ => true } @@ -126,7 +131,9 @@ sealed abstract class CreditingTxGen { def output: Gen[ScriptSignatureParams[InputInfo]] = Gen.oneOf(nonCltvOutputGens).flatMap(identity) - /** Either a list of non-CLTV outputs or a single CLTV output, with proportional probability */ + /** Either a list of non-CLTV outputs or a single CLTV output, with + * proportional probability + */ def outputs: Gen[Seq[ScriptSignatureParams[InputInfo]]] = { val cltvGen = Gen .oneOf(cltvOutput, p2pkWithTimeoutOutput) @@ -141,7 +148,8 @@ sealed abstract class CreditingTxGen { // For some reason this breaks in scala 2.13 without the explicit type param Gen.frequency[Seq[ScriptSignatureParams[InputInfo]]]( (cltvSize, cltvGen), - (nonCltvSize, nonCltvGen)) + (nonCltvSize, nonCltvGen) + ) } /** Generates a crediting tx with a p2pk spk at the returned index */ @@ -165,8 +173,8 @@ sealed abstract class CreditingTxGen { Gen.choose(min, max).flatMap(n => Gen.listOfN(n, p2pkWithTimeoutOutput)) } - /** Generates a transaction that has a p2pkh output at the returned index. This - * output can be spent by the returned ECPrivateKey + /** Generates a transaction that has a p2pkh output at the returned index. + * This output can be spent by the returned ECPrivateKey */ def p2pkhOutput: Gen[ScriptSignatureParams[InputInfo]] = ScriptGenerators.p2pkhScriptPubKey.flatMap { p2pkh => @@ -194,8 +202,8 @@ sealed abstract class CreditingTxGen { } } - def multiSignatureWithTimeoutOutputs: Gen[ - Seq[ScriptSignatureParams[InputInfo]]] = { + def multiSignatureWithTimeoutOutputs + : Gen[Seq[ScriptSignatureParams[InputInfo]]] = { Gen .choose(min, max) .flatMap(n => Gen.listOfN(n, multiSignatureWithTimeoutOutput)) @@ -337,7 +345,8 @@ sealed abstract class CreditingTxGen { build(witSPK, signers, None, Some(scriptWit)) case _ => throw new IllegalArgumentException( - "nonP2WSHOutput created a non RawScriptPubKey") + "nonP2WSHOutput created a non RawScriptPubKey" + ) } } @@ -364,11 +373,14 @@ sealed abstract class CreditingTxGen { BaseTransaction(tc.validLockVersion, Nil, outputs, tc.lockTime) ScriptSignatureParams( InputInfo( - TransactionOutPoint(creditingTx.txId, - UInt32.apply(outputIndex)), + TransactionOutPoint( + creditingTx.txId, + UInt32.apply(outputIndex) + ), TransactionOutput( creditingTx.outputs(outputIndex).value, - creditingTx.outputs(outputIndex).scriptPubKey), + creditingTx.outputs(outputIndex).scriptPubKey + ), Some(spk), Some(wit), ConditionalPath.NoCondition, @@ -390,23 +402,28 @@ sealed abstract class CreditingTxGen { private def computeAllTrueConditionalPath( spk: ScriptPubKey, redeemScript: Option[ScriptPubKey], - scriptWitness: Option[ScriptWitness]): ConditionalPath = { + scriptWitness: Option[ScriptWitness] + ): ConditionalPath = { spk match { case conditional: ConditionalScriptPubKey => ConditionalPath.ConditionTrue( - computeAllTrueConditionalPath(conditional.trueSPK, None, None)) + computeAllTrueConditionalPath(conditional.trueSPK, None, None) + ) case _: P2PKWithTimeoutScriptPubKey => ConditionalPath.nonNestedTrue case lockTimeScriptPubKey: LockTimeScriptPubKey => - computeAllTrueConditionalPath(lockTimeScriptPubKey.nestedScriptPubKey, - None, - None) + computeAllTrueConditionalPath( + lockTimeScriptPubKey.nestedScriptPubKey, + None, + None + ) case _: RawScriptPubKey | _: P2WPKHWitnessSPKV0 => ConditionalPath.NoCondition case _: P2SHScriptPubKey => redeemScript match { case None => throw new IllegalArgumentException( - "Expected redeem script for P2SH") + "Expected redeem script for P2SH" + ) case Some(script) => computeAllTrueConditionalPath(script, None, scriptWitness) } @@ -416,14 +433,17 @@ sealed abstract class CreditingTxGen { computeAllTrueConditionalPath(witness.redeemScript, None, None) case _ => throw new IllegalArgumentException( - "Expected P2WSHWitness for P2WSH") + "Expected P2WSHWitness for P2WSH" + ) } case _: TaprootScriptPubKey => throw new IllegalArgumentException( - s"Unexpected (unsupported) taproot SPK: $spk") + s"Unexpected (unsupported) taproot SPK: $spk" + ) case _: UnassignedWitnessScriptPubKey => throw new IllegalArgumentException( - s"Unexpected unassigned witness SPK: $spk") + s"Unexpected unassigned witness SPK: $spk" + ) } } @@ -431,8 +451,8 @@ sealed abstract class CreditingTxGen { spk: ScriptPubKey, signers: Seq[Sign], redeemScript: Option[ScriptPubKey], - scriptWitness: Option[ScriptWitness]): Gen[ - ScriptSignatureParams[InputInfo]] = + scriptWitness: Option[ScriptWitness] + ): Gen[ScriptSignatureParams[InputInfo]] = nonEmptyOutputs.flatMap { outputs => CryptoGenerators.hashType.flatMap { hashType => Gen.choose(0, outputs.size - 1).map { idx => @@ -460,21 +480,26 @@ sealed abstract class CreditingTxGen { def inputsAndOutputs( outputsToUse: Gen[Seq[ScriptSignatureParams[InputInfo]]] = outputs, destinationGenerator: CurrencyUnit => Gen[Seq[TransactionOutput]] = - TransactionGenerators.smallOutputs): Gen[ - (Seq[ScriptSignatureParams[InputInfo]], Seq[TransactionOutput])] = { + TransactionGenerators.smallOutputs + ): Gen[(Seq[ScriptSignatureParams[InputInfo]], Seq[TransactionOutput])] = { inputsAndP2SHOutputs( outputsToUse, - destinationGenerator.andThen(_.map(_.map(x => (x, ScriptPubKey.empty))))) + destinationGenerator.andThen(_.map(_.map(x => (x, ScriptPubKey.empty)))) + ) .map(x => (x._1, x._2.map(_._1))) } def inputsAndP2SHOutputs( outputsToUse: Gen[Seq[ScriptSignatureParams[InputInfo]]] = outputs, destinationGenerator: CurrencyUnit => Gen[ - Seq[(TransactionOutput, ScriptPubKey)]] = - TransactionGenerators.smallP2SHOutputs): Gen[( - Seq[ScriptSignatureParams[InputInfo]], - Seq[(TransactionOutput, ScriptPubKey)])] = { + Seq[(TransactionOutput, ScriptPubKey)] + ] = TransactionGenerators.smallP2SHOutputs + ): Gen[ + ( + Seq[ScriptSignatureParams[InputInfo]], + Seq[(TransactionOutput, ScriptPubKey)] + ) + ] = { outputsToUse .flatMap { creditingTxsInfo => val creditingOutputs = creditingTxsInfo.map(c => c.output) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CryptoGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CryptoGenerators.scala index ff023bad02..5f527208eb 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CryptoGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CryptoGenerators.scala @@ -95,16 +95,14 @@ sealed abstract class CryptoGenerators { mnemonicCode256Bits ) - /** Generates a BIP39 valid mnemonic - * phrase + /** Generates a BIP39 valid mnemonic phrase */ def mnemonicPhrase: Gen[Vector[String]] = for { code <- mnemonicCode } yield code.words - /** Generates a valid BIP39 seed from - * an mnemonic with no password + /** Generates a valid BIP39 seed from an mnemonic with no password */ def bip39SeedNoPassword: Gen[BIP39Seed] = for { @@ -112,14 +110,14 @@ sealed abstract class CryptoGenerators { } yield BIP39Seed.fromMnemonic(code) /** Generates a password that can be used with bip39 - * @see https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#From_mnemonic_to_seed + * @see + * https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#From_mnemonic_to_seed */ def bip39Password: Gen[String] = { Gen.alphaNumStr } - /** Generates a valid BIP39 seed from - * an mnemonic with a random password + /** Generates a valid BIP39 seed from an mnemonic with a random password */ def bip39SeedWithPassword: Gen[BIP39Seed] = for { @@ -128,11 +126,11 @@ sealed abstract class CryptoGenerators { } yield BIP39Seed.fromMnemonic(code, pass) def privateKey: Gen[ECPrivateKey] = { - //purposefully don't reach for cryptographically strong - //number generation, we want determinism to reproduce failed - //test cases. If we don't generate the private key with scalacheck - //we won't be able to reproduce the test case with a seed - //see: https://github.com/bitcoin-s/bitcoin-s/issues/1339 + // purposefully don't reach for cryptographically strong + // number generation, we want determinism to reproduce failed + // test cases. If we don't generate the private key with scalacheck + // we won't be able to reproduce the test case with a seed + // see: https://github.com/bitcoin-s/bitcoin-s/issues/1339 NumberGenerator.bytevector(32).map { vec => ECPrivateKey.fromBytes(vec) } @@ -171,15 +169,17 @@ sealed abstract class CryptoGenerators { def xOnlyPubKey: Gen[XOnlyPubKey] = publicKey.map(_.toXOnly) /** Generate a sequence of private keys - * @param num maximum number of keys to generate + * @param num + * maximum number of keys to generate * @return */ def privateKeySeq(num: Int): Gen[Seq[ECPrivateKey]] = Gen.listOfN(num, privateKey) - /** Generates a sequence of private keys, and determines an amount of 'required' private keys - * that a transaction needs to be signed with - * @param num the maximum number of keys to generate + /** Generates a sequence of private keys, and determines an amount of + * 'required' private keys that a transaction needs to be signed with + * @param num + * the maximum number of keys to generate * @return */ def privateKeySeqWithRequiredSigs(num: Int): Gen[(Seq[ECPrivateKey], Int)] = { @@ -194,8 +194,8 @@ sealed abstract class CryptoGenerators { } } - /** Generates a random number of private keys less than 15. - * Also generates a random 'requiredSigs' number that a transaction needs to be signed with + /** Generates a random number of private keys less than 15. Also generates a + * random 'requiredSigs' number that a transaction needs to be signed with */ def privateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] = for { @@ -203,7 +203,9 @@ sealed abstract class CryptoGenerators { keysAndRequiredSigs <- privateKeySeqWithRequiredSigs(num) } yield keysAndRequiredSigs - /** A generator with 7 or less private keys -- useful for creating smaller scripts */ + /** A generator with 7 or less private keys -- useful for creating smaller + * scripts + */ def smallPrivateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] = for { num <- Gen.choose(0, 7) @@ -273,7 +275,8 @@ sealed abstract class CryptoGenerators { } /** Generates a sequence of [[DoubleSha256Digest DoubleSha256Digest]] - * @param num the number of digets to generate + * @param num + * the number of digets to generate * @return */ def doubleSha256DigestSeq(num: Int): Gen[Seq[DoubleSha256Digest]] = diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CurrencyUnitGenerator.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CurrencyUnitGenerator.scala index 4808fb52ba..9793d246cf 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CurrencyUnitGenerator.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/CurrencyUnitGenerator.scala @@ -21,8 +21,8 @@ trait CurrencyUnitGenerator { def positiveSatoshis: Gen[Satoshis] = Gen.choose(0, Long.MaxValue).map(Satoshis.apply) - /** Generates a postiive satoshi value that is 'realistic'. This current 'realistic' range - * is from 0 to 1,000,000 bitcoin + /** Generates a postiive satoshi value that is 'realistic'. This current + * 'realistic' range is from 0 to 1,000,000 bitcoin */ def positiveRealistic: Gen[Satoshis] = Gen.choose(0, Bitcoins(1000000).satoshis.toLong).map { n => diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/FeeUnitGen.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/FeeUnitGen.scala index b215d44129..ba0da4bb9a 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/FeeUnitGen.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/FeeUnitGen.scala @@ -30,15 +30,15 @@ abstract class FeeUnitGen { } yield SatoshisPerVirtualByte(curr) } - /** Choose between different sets of Satoshi sizes so we get a better distribution */ + /** Choose between different sets of Satoshi sizes so we get a better + * distribution + */ private def realisticFee: Gen[Satoshis] = { Gen.oneOf(lowFee, highFee, exorbitantFee) } /** Max fee between 101 - 100 sats. So we can have - * 1. 100 sats/byte - * 2. 100 sats/vbyte - * 3. 100 sats/kb + * 1. 100 sats/byte 2. 100 sats/vbyte 3. 100 sats/kb */ private def lowFee: Gen[Satoshis] = { Gen @@ -47,9 +47,7 @@ abstract class FeeUnitGen { } /** Max fee between 0 - 300 sats. So we can have - * 1. 300 sats/byte - * 2. 300 sats/vbyte - * 3. 300 sats/kb + * 1. 300 sats/byte 2. 300 sats/vbyte 3. 300 sats/kb */ private def highFee: Gen[Satoshis] = { Gen @@ -58,12 +56,10 @@ abstract class FeeUnitGen { } /** Max fee between 301 - 1,000 sats. So we can have - * 1. 1,000 sats/byte - * 2. 1,000 sats/vbyte - * 3. 1,000 sats/kb + * 1. 1,000 sats/byte 2. 1,000 sats/vbyte 3. 1,000 sats/kb * - * Anything higher can cause a bitcoind to reject the transaction - * for paying too high a fee + * Anything higher can cause a bitcoind to reject the transaction for paying + * too high a fee */ private def exorbitantFee: Gen[Satoshis] = { Gen @@ -72,10 +68,12 @@ abstract class FeeUnitGen { } def feeUnit: Gen[FeeUnit] = - Gen.oneOf(satsPerByte, - satsPerKiloByte, - satsPerVirtualByte, - satsPerKiloWeight) + Gen.oneOf( + satsPerByte, + satsPerKiloByte, + satsPerVirtualByte, + satsPerKiloWeight + ) /** Generates a FeeUnit based on the maxFee allowed for a transaction */ def feeUnit(maxFee: Long): Gen[FeeUnit] = { diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/HDGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/HDGenerators.scala index a0a7890da4..15be751b16 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/HDGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/HDGenerators.scala @@ -96,10 +96,12 @@ object HDGenerators { accountIndex <- NumberGenerator.positiveInts addressIndex <- NumberGenerator.positiveInts chainType <- hdChainType - } yield LegacyHDPath(coinType = coinType, - addressIndex = addressIndex, - accountIndex = accountIndex, - chainType = chainType) + } yield LegacyHDPath( + coinType = coinType, + addressIndex = addressIndex, + accountIndex = accountIndex, + chainType = chainType + ) def segwithHdPath: Gen[SegWitHDPath] = for { @@ -107,10 +109,12 @@ object HDGenerators { accountIndex <- NumberGenerator.positiveInts addressIndex <- NumberGenerator.positiveInts chainType <- hdChainType - } yield SegWitHDPath(coinType = coinType, - addressIndex = addressIndex, - accountIndex = accountIndex, - chainType = chainType) + } yield SegWitHDPath( + coinType = coinType, + addressIndex = addressIndex, + accountIndex = accountIndex, + chainType = chainType + ) def nestedSegwithHdPath: Gen[NestedSegWitHDPath] = for { @@ -118,10 +122,12 @@ object HDGenerators { accountIndex <- NumberGenerator.positiveInts addressIndex <- NumberGenerator.positiveInts chainType <- hdChainType - } yield NestedSegWitHDPath(coinType = coinType, - addressIndex = addressIndex, - accountIndex = accountIndex, - chainType = chainType) + } yield NestedSegWitHDPath( + coinType = coinType, + addressIndex = addressIndex, + accountIndex = accountIndex, + chainType = chainType + ) def hdPath: Gen[HDPath] = Gen.oneOf(legacyHdPath, segwithHdPath, nestedSegwithHdPath) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/LnMessageGen.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/LnMessageGen.scala index 01b9c8d560..e8494aee93 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/LnMessageGen.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/LnMessageGen.scala @@ -44,8 +44,8 @@ trait LnMessageGen extends TLVGen { dlcAcceptTLV(offer).map(LnMessage.apply) } - def dlcOfferMessageAcceptMessage: Gen[ - (LnMessage[DLCOfferTLV], LnMessage[DLCAcceptTLV])] = { + def dlcOfferMessageAcceptMessage + : Gen[(LnMessage[DLCOfferTLV], LnMessage[DLCAcceptTLV])] = { dlcOfferTLVAcceptTLV.map { case (offer, accept) => (LnMessage(offer), LnMessage(accept)) } @@ -57,14 +57,14 @@ trait LnMessageGen extends TLVGen { def dlcSignMessage( offer: DLCOfferTLV, - accept: DLCAcceptTLV): Gen[LnMessage[DLCSignTLV]] = { + accept: DLCAcceptTLV + ): Gen[LnMessage[DLCSignTLV]] = { dlcSignTLV(offer, accept).map(LnMessage.apply) } - def dlcOfferMessageAcceptMessageSignMessage: Gen[( - LnMessage[DLCOfferTLV], - LnMessage[DLCAcceptTLV], - LnMessage[DLCSignTLV])] = { + def dlcOfferMessageAcceptMessageSignMessage: Gen[ + (LnMessage[DLCOfferTLV], LnMessage[DLCAcceptTLV], LnMessage[DLCSignTLV]) + ] = { dlcOfferTLVAcceptTLVSignTLV.map { case (offer, accept, sign) => (LnMessage(offer), LnMessage(accept), LnMessage(sign)) } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/MerkleGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/MerkleGenerators.scala index fbf5776e91..a194ff0786 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/MerkleGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/MerkleGenerators.scala @@ -17,40 +17,43 @@ abstract class MerkleGenerator { /** Generates a merkle block with the given txs matched inside the * [[org.bitcoins.core.protocol.blockchain.PartialMerkleTree PartialMerkleTree]] */ - def merkleBlockWithInsertedTxIds(txs: Seq[Transaction]): Gen[ - (MerkleBlock, Block, Seq[DoubleSha256Digest])] = + def merkleBlockWithInsertedTxIds( + txs: Seq[Transaction] + ): Gen[(MerkleBlock, Block, Seq[DoubleSha256Digest])] = for { block <- BlockchainElementsGenerator.block(txs) txIds = txs.map(_.txId) merkleBlock = MerkleBlock(block, txIds) } yield (merkleBlock, block, txIds) - /** Returns a [[org.bitcoins.core.protocol.blockchain.MerkleBlock MerkleBlock]] including the sequence of hashes inserted in to the bloom filter */ - def merkleBlockWithInsertedTxIds: Gen[ - (MerkleBlock, Block, Seq[DoubleSha256Digest])] = + /** Returns a + * [[org.bitcoins.core.protocol.blockchain.MerkleBlock MerkleBlock]] + * including the sequence of hashes inserted in to the bloom filter + */ + def merkleBlockWithInsertedTxIds + : Gen[(MerkleBlock, Block, Seq[DoubleSha256Digest])] = for { - //TODO: Revisit this later, I've limited this to increase test speed. If I increase this from 5 tests take a lot longer + // TODO: Revisit this later, I've limited this to increase test speed. If I increase this from 5 tests take a lot longer rand <- Gen.choose(1, 5) txs <- Gen.listOfN(rand, TransactionGenerators.transaction) result <- merkleBlockWithInsertedTxIds(txs) } yield result - /** Returns a [[org.bitcoins.core.protocol.blockchain.MerkleBlock MerkleBlock]] created with a [[org.bitcoins.core.bloom.BloomFilter BloomFilter]], with the block it was created from - * and the transactions that were matched inside of that block - * NOTE: Since bloom filters can produce false positives, it is possible that there will be - * matches in the parital merkle tree that SHOULD NOT be matched. Bloom filters do not guaratnee no - * false negatives. + /** Returns a + * [[org.bitcoins.core.protocol.blockchain.MerkleBlock MerkleBlock]] created + * with a [[org.bitcoins.core.bloom.BloomFilter BloomFilter]], with the block + * it was created from and the transactions that were matched inside of that + * block NOTE: Since bloom filters can produce false positives, it is + * possible that there will be matches in the parital merkle tree that SHOULD + * NOT be matched. Bloom filters do not guaratnee no false negatives. * @return */ def merkleBlockCreatedWithBloomFilter: Gen[ - ( - MerkleBlock, - Block, - scala.collection.Seq[DoubleSha256Digest], - BloomFilter)] = + (MerkleBlock, Block, scala.collection.Seq[DoubleSha256Digest], BloomFilter) + ] = for { block <- BlockchainElementsGenerator.block - //choose some random txs in the block to put in the bloom filter + // choose some random txs in the block to put in the bloom filter txIds <- Gen.someOf(block.transactions.map(_.txId)) initialFilter <- BloomFilterGenerator.bloomFilter(txIds.map(_.bytes)) } yield { @@ -58,16 +61,19 @@ abstract class MerkleGenerator { (merkleBlock, block, txIds, loadedFilter) } - /** Generates a partial merkle tree with a sequence of txids and a flag indicating if the txid was matched */ - def partialMerkleTree: Gen[ - (PartialMerkleTree, Seq[(Boolean, DoubleSha256Digest)])] = + /** Generates a partial merkle tree with a sequence of txids and a flag + * indicating if the txid was matched + */ + def partialMerkleTree + : Gen[(PartialMerkleTree, Seq[(Boolean, DoubleSha256Digest)])] = for { randomNum <- Gen.choose(1, 25) txMatches <- txIdsWithMatchIndication(randomNum) } yield (PartialMerkleTree(txMatches), txMatches) - /** Generates a transaction ids with a boolean indicator if they match the bloom filter or not - * this is useful for testing partial merkle trees as this is how they are built. + /** Generates a transaction ids with a boolean indicator if they match the + * bloom filter or not this is useful for testing partial merkle trees as + * this is how they are built. * @return */ private def txIdWithMatchIndication: Gen[(Boolean, DoubleSha256Digest)] = @@ -76,9 +82,12 @@ abstract class MerkleGenerator { bool <- Gen.choose(0, 1) } yield (bool == 1, hash) - /** Generates a list of txids with a boolean indicator signifying if it matched the bloom filter or not */ + /** Generates a list of txids with a boolean indicator signifying if it + * matched the bloom filter or not + */ def txIdsWithMatchIndication( - num: Int): Gen[Seq[(Boolean, DoubleSha256Digest)]] = + num: Int + ): Gen[Seq[(Boolean, DoubleSha256Digest)]] = Gen.listOfN(num, txIdWithMatchIndication) } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/NumberGenerator.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/NumberGenerator.scala index a4280f4c2a..cb8a843aaa 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/NumberGenerator.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/NumberGenerator.scala @@ -47,8 +47,8 @@ trait NumberGenerator { def uInt16: Gen[UInt16] = Gen.choose(0, 65535).map(UInt16(_)) - /** Generates a number in the range 0 <= x <= 2 ^^32 - 1 - * then wraps it in a UInt32 + /** Generates a number in the range 0 <= x <= 2 ^^32 - 1 then wraps it in a + * UInt32 */ def uInt32s: Gen[UInt32] = Gen.choose(0L, (NumberUtil.pow2(32) - 1).toLong).map(UInt32(_)) @@ -64,8 +64,7 @@ trait NumberGenerator { def bigIntsUInt64Range: Gen[BigInt] = positiveBigInts.filter(_ < (BigInt(1) << 64)) - /** Generates a number in the range 0 <= x < 2^^64 - * then wraps it in a UInt64 + /** Generates a number in the range 0 <= x < 2^^64 then wraps it in a UInt64 */ def uInt64s: Gen[UInt64] = uInt64 @@ -131,8 +130,10 @@ trait NumberGenerator { /** Generates a random GCS P parameter. * - * Bit parameter for GCS, cannot be more than 32 as we will have a number too large for a UInt64. - * @see [[https://github.com/Roasbeef/btcutil/blob/b5d74480bb5b02a15a9266cbeae37ecf9dd6ffca/gcs/gcs.go#L67]] + * Bit parameter for GCS, cannot be more than 32 as we will have a number too + * large for a UInt64. + * @see + * [[https://github.com/Roasbeef/btcutil/blob/b5d74480bb5b02a15a9266cbeae37ecf9dd6ffca/gcs/gcs.go#L67]] */ def genP: Gen[UInt8] = { Gen.choose(0, 32).map(UInt8(_)) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/PSBTGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/PSBTGenerators.scala index 5fed719d35..7e695f6509 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/PSBTGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/PSBTGenerators.scala @@ -65,7 +65,8 @@ object PSBTGenerators { } private def unknownGlobals( - num: Int): Gen[Vector[GlobalPSBTRecord.Unknown]] = { + num: Int + ): Gen[Vector[GlobalPSBTRecord.Unknown]] = { Gen .listOfN(num, unknownGlobal) .map(_.groupBy(_.key).map(_._2.head).toVector) @@ -100,7 +101,8 @@ object PSBTGenerators { } private def unknownOutputs( - num: Int): Gen[Vector[OutputPSBTRecord.Unknown]] = { + num: Int + ): Gen[Vector[OutputPSBTRecord.Unknown]] = { Gen .listOfN(num, unknownOutput) .map(_.groupBy(_.key).map(_._2.head).toVector) @@ -126,23 +128,28 @@ object PSBTGenerators { def psbtWithUnknownVersion: Gen[PSBT] = { for { psbt <- psbtWithUnknowns - versionNumber <- Gen.choose(min = PSBT.knownVersions.last.toLong, - max = UInt32.max.toLong) + versionNumber <- Gen.choose( + min = PSBT.knownVersions.last.toLong, + max = UInt32.max.toLong + ) } yield { val newGlobal = GlobalPSBTMap( - psbt.globalMap.elements :+ Version(UInt32(versionNumber))) + psbt.globalMap.elements :+ Version(UInt32(versionNumber)) + ) PSBT(newGlobal, psbt.inputMaps, psbt.outputMaps) } } - def psbtToBeSigned: Gen[ - (PSBT, Seq[ScriptSignatureParams[InputInfo]], FeeUnit)] = { + def psbtToBeSigned + : Gen[(PSBT, Seq[ScriptSignatureParams[InputInfo]], FeeUnit)] = { psbtWithBuilder(finalized = false).map { case (psbt, FinalizedTxWithSigningInfo(_, infos), fee) => val newInputsMaps = psbt.inputMaps.map { map => - InputPSBTMap(map.elements.filterNot(element => - PSBTInputKeyId.fromBytes(element.key) == PartialSignatureKeyId)) + InputPSBTMap( + map.elements.filterNot(element => + PSBTInputKeyId.fromBytes(element.key) == PartialSignatureKeyId) + ) } (PSBT(psbt.globalMap, newInputsMaps, psbt.outputMaps), infos, fee) @@ -151,8 +158,8 @@ object PSBTGenerators { def orderSpendingInfos( unsignedTx: Transaction, - creditingTxsInfo: Vector[ScriptSignatureParams[InputInfo]]): Vector[ - ScriptSignatureParams[InputInfo]] = { + creditingTxsInfo: Vector[ScriptSignatureParams[InputInfo]] + ): Vector[ScriptSignatureParams[InputInfo]] = { unsignedTx.inputs.toVector.map { input => val infoOpt = creditingTxsInfo.find(_.outPoint == input.previousOutput) @@ -160,7 +167,8 @@ object PSBTGenerators { case Some(info) => info case None => throw new RuntimeException( - "CreditingTxGen.inputsAndOutputs is being inconsistent") + "CreditingTxGen.inputsAndOutputs is being inconsistent" + ) } } } @@ -170,7 +178,8 @@ object PSBTGenerators { creditingTxsInfo: Seq[ScriptSignatureParams[InputInfo]], destinations: Seq[TransactionOutput], changeSPK: ScriptPubKey, - fee: FeeUnit): (PSBT, FinalizedTxWithSigningInfo, FeeUnit) = { + fee: FeeUnit + ): (PSBT, FinalizedTxWithSigningInfo, FeeUnit) = { val lockTime = TxUtil.calcLockTime(creditingTxsInfo).get val inputs = InputUtil.calcSequenceForInputs(creditingTxsInfo) @@ -180,7 +189,8 @@ object PSBTGenerators { val finalizer = StandardNonInteractiveFinalizer( creditingTxsInfo.toVector.map(_.inputInfo), fee, - changeSPK) + changeSPK + ) builder.setFinalizer(finalizer) val unsignedTx = builder.setFinalizer(finalizer).buildTx() @@ -195,13 +205,16 @@ object PSBTGenerators { PSBT.fromUnsignedTxAndInputs(unsignedTx, orderedTxInfos) } - (psbt, - FinalizedTxWithSigningInfo(unsignedTx, creditingTxsInfo.toVector), - fee) + ( + psbt, + FinalizedTxWithSigningInfo(unsignedTx, creditingTxsInfo.toVector), + fee + ) } def psbtWithBuilder( - finalized: Boolean): Gen[(PSBT, FinalizedTxWithSigningInfo, FeeUnit)] = { + finalized: Boolean + ): Gen[(PSBT, FinalizedTxWithSigningInfo, FeeUnit)] = { for { (creditingTxsInfo, destinations) <- CreditingTxGen.inputsAndOutputs() (changeSPK, _) <- ScriptGenerators.scriptPubKey @@ -213,19 +226,21 @@ object PSBTGenerators { } fee <- FeeUnitGen.feeUnit(maxFee) } yield { - psbtAndBuilderFromInputs(finalized = finalized, - creditingTxsInfo = creditingTxsInfo, - destinations = destinations, - changeSPK = changeSPK, - fee = fee) + psbtAndBuilderFromInputs( + finalized = finalized, + creditingTxsInfo = creditingTxsInfo, + destinations = destinations, + changeSPK = changeSPK, + fee = fee + ) } } def psbtWithBuilderAndP2SHOutputs( finalized: Boolean, outputGen: CurrencyUnit => Gen[Seq[(TransactionOutput, ScriptPubKey)]] = - TransactionGenerators.smallP2SHOutputs): Gen[ - (PSBT, FinalizedTxWithSigningInfo, Seq[ScriptPubKey])] = { + TransactionGenerators.smallP2SHOutputs + ): Gen[(PSBT, FinalizedTxWithSigningInfo, Seq[ScriptPubKey])] = { for { (creditingTxsInfo, outputs) <- CreditingTxGen.inputsAndP2SHOutputs(destinationGenerator = outputGen) @@ -239,23 +254,28 @@ object PSBTGenerators { } fee <- FeeUnitGen.feeUnit(maxFee) } yield { - val p = psbtAndBuilderFromInputs(finalized = finalized, - creditingTxsInfo = creditingTxsInfo, - destinations = outputs.map(_._1), - changeSPK = changeSPK._1, - fee = fee) + val p = psbtAndBuilderFromInputs( + finalized = finalized, + creditingTxsInfo = creditingTxsInfo, + destinations = outputs.map(_._1), + changeSPK = changeSPK._1, + fee = fee + ) (p._1, p._2, outputs.map(_._2)) } } - def psbtWithBuilderAndP2WSHOutputs(finalized: Boolean): Gen[ - (PSBT, FinalizedTxWithSigningInfo, Seq[ScriptPubKey])] = - psbtWithBuilderAndP2SHOutputs(finalized, - TransactionGenerators.smallP2WSHOutputs) + def psbtWithBuilderAndP2WSHOutputs( + finalized: Boolean + ): Gen[(PSBT, FinalizedTxWithSigningInfo, Seq[ScriptPubKey])] = + psbtWithBuilderAndP2SHOutputs( + finalized, + TransactionGenerators.smallP2WSHOutputs + ) - def finalizedPSBTWithBuilder: Gen[ - (PSBT, FinalizedTxWithSigningInfo, FeeUnit)] = { + def finalizedPSBTWithBuilder + : Gen[(PSBT, FinalizedTxWithSigningInfo, FeeUnit)] = { psbtWithBuilder(finalized = true) } @@ -263,7 +283,9 @@ object PSBTGenerators { finalizedPSBTWithBuilder.map(_._1) } - /** Generates a PSBT that is ready to be finalized but where no input map has been finalized */ + /** Generates a PSBT that is ready to be finalized but where no input map has + * been finalized + */ def fullNonFinalizedPSBT: Gen[PSBT] = { psbtWithBuilder(finalized = false).map(_._1) } @@ -285,8 +307,8 @@ object PSBTGenerators { } } - /** Generates an arbitrary unfinalized PSBT by generating a full unfinalized PSBT - * and randomly removing records + /** Generates an arbitrary unfinalized PSBT by generating a full unfinalized + * PSBT and randomly removing records */ def arbitraryPSBT: Gen[PSBT] = { psbtWithUnknowns.map { psbt => diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ScriptGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ScriptGenerators.scala index b1e612b922..040ad77989 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ScriptGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ScriptGenerators.scala @@ -36,13 +36,13 @@ sealed abstract class ScriptGenerators { val timeout = 30.seconds val defaultMaxDepth: Int = 2 - /** Since redeem scripts are pushed onto the stack, this function - * checks that the redeem script is not too large for a push operation. + /** Since redeem scripts are pushed onto the stack, this function checks that + * the redeem script is not too large for a push operation. */ private[gen] def redeemScriptTooBig(redeemScript: ScriptPubKey): Boolean = { redeemScript.compactSizeUInt.toInt + CompactSizeUInt( - UInt64( - ScriptInterpreter.MAX_PUSH_SIZE)).bytes.length >= ScriptInterpreter.MAX_PUSH_SIZE + UInt64(ScriptInterpreter.MAX_PUSH_SIZE) + ).bytes.length >= ScriptInterpreter.MAX_PUSH_SIZE } private def truncate[A, B, C](tuple: (A, B, C)): (A, B) = (tuple._1, tuple._2) @@ -52,7 +52,8 @@ sealed abstract class ScriptGenerators { sig <- CryptoGenerators.digitalSignature hashType <- CryptoGenerators.hashType digitalSignature = ECDigitalSignature( - sig.bytes ++ ByteVector.fromByte(hashType.byte)) + sig.bytes ++ ByteVector.fromByte(hashType.byte) + ) } yield P2PKScriptSignature(digitalSignature) def p2pkhScriptSignature: Gen[P2PKHScriptSignature] = @@ -61,7 +62,8 @@ sealed abstract class ScriptGenerators { hash <- CryptoGenerators.doubleSha256Digest hashType <- CryptoGenerators.hashType signature = ECDigitalSignature.fromBytes( - privKey.sign(hash).bytes ++ ByteVector.fromByte(hashType.byte)) + privKey.sign(hash).bytes ++ ByteVector.fromByte(hashType.byte) + ) } yield P2PKHScriptSignature(signature, privKey.publicKey) def p2pkWithTimeoutScriptSignature: Gen[ConditionalScriptSignature] = @@ -70,7 +72,8 @@ sealed abstract class ScriptGenerators { hash <- CryptoGenerators.doubleSha256Digest hashType <- CryptoGenerators.hashType signature = ECDigitalSignature.fromBytes( - privKey.sign(hash).bytes ++ ByteVector.fromByte(hashType.byte)) + privKey.sign(hash).bytes ++ ByteVector.fromByte(hashType.byte) + ) beforeTimeout <- NumberGenerator.bool } yield P2PKWithTimeoutScriptSignature(beforeTimeout, signature) @@ -83,7 +86,8 @@ sealed abstract class ScriptGenerators { } yield for { privKey <- privKeys } yield ECDigitalSignature.fromBytes( - privKey.sign(hash).bytes ++ ByteVector.fromByte(hashType.byte)) + privKey.sign(hash).bytes ++ ByteVector.fromByte(hashType.byte) + ) signatures.map(sigs => MultiSignatureScriptSignature(sigs)) } @@ -108,10 +112,12 @@ sealed abstract class ScriptGenerators { def nonLockTimeConditionalScriptSignature: Gen[ConditionalScriptSignature] = { Gen - .oneOf(p2pkScriptSignature, - p2pkhScriptSignature, - multiSignatureScriptSignature, - emptyScriptSignature) + .oneOf( + p2pkScriptSignature, + p2pkhScriptSignature, + multiSignatureScriptSignature, + emptyScriptSignature + ) .flatMap { scriptSig => NumberGenerator.bool.map { condition => ConditionalScriptSignature(scriptSig, condition) @@ -123,8 +129,9 @@ sealed abstract class ScriptGenerators { /** Generates a P2SH script signature * - * @note the redeem script and the script signature DO NOT evaluate to true - * if executed by [[org.bitcoins.core.script.interpreter.ScriptInterpreter]] + * @note + * the redeem script and the script signature DO NOT evaluate to true if + * executed by [[org.bitcoins.core.script.interpreter.ScriptInterpreter]] */ def p2shScriptSignature: Gen[P2SHScriptSignature] = for { @@ -157,17 +164,21 @@ sealed abstract class ScriptGenerators { p2pkh = P2PKHScriptPubKey(pubKey) } yield (p2pkh, privKey) - def p2pkWithTimeoutScriptPubKey: Gen[ - (P2PKWithTimeoutScriptPubKey, Seq[ECPrivateKey])] = + def p2pkWithTimeoutScriptPubKey + : Gen[(P2PKWithTimeoutScriptPubKey, Seq[ECPrivateKey])] = for { privKey <- CryptoGenerators.privateKey timeoutPrivKey <- CryptoGenerators.privateKey lockTime <- NumberGenerator.timeLockScriptNumbers } yield { - (P2PKWithTimeoutScriptPubKey(privKey.publicKey, - lockTime, - timeoutPrivKey.publicKey), - Vector(privKey, timeoutPrivKey)) + ( + P2PKWithTimeoutScriptPubKey( + privKey.publicKey, + lockTime, + timeoutPrivKey.publicKey + ), + Vector(privKey, timeoutPrivKey) + ) } def cltvScriptPubKey: Gen[(CLTVScriptPubKey, Seq[ECPrivateKey])] = { @@ -175,7 +186,8 @@ sealed abstract class ScriptGenerators { } def cltvScriptPubKey( - maxDepth: Int): Gen[(CLTVScriptPubKey, Seq[ECPrivateKey])] = + maxDepth: Int + ): Gen[(CLTVScriptPubKey, Seq[ECPrivateKey])] = for { num <- NumberGenerator.timeLockScriptNumbers (cltv, privKeys, num) <- cltvScriptPubKey(num, maxDepth) @@ -183,7 +195,8 @@ sealed abstract class ScriptGenerators { def cltvScriptPubKey( num: ScriptNumber, - maxDepth: Int): Gen[(CLTVScriptPubKey, Seq[ECPrivateKey], ScriptNumber)] = + maxDepth: Int + ): Gen[(CLTVScriptPubKey, Seq[ECPrivateKey], ScriptNumber)] = for { (scriptPubKey, privKeys) <- nonLocktimeRawScriptPubKey(maxDepth - 1) } yield { @@ -191,16 +204,17 @@ sealed abstract class ScriptGenerators { (cltv, privKeys, num) } - def nonConditionalCltvScriptPubKey: Gen[ - (CLTVScriptPubKey, Seq[ECPrivateKey])] = { + def nonConditionalCltvScriptPubKey + : Gen[(CLTVScriptPubKey, Seq[ECPrivateKey])] = { for { num <- NumberGenerator.timeLockScriptNumbers (cltv, privKeys, num) <- nonConditionalCltvScriptPubKey(num) } yield (cltv, privKeys) } - def nonConditionalCltvScriptPubKey(num: ScriptNumber): Gen[ - (CLTVScriptPubKey, Seq[ECPrivateKey], ScriptNumber)] = + def nonConditionalCltvScriptPubKey( + num: ScriptNumber + ): Gen[(CLTVScriptPubKey, Seq[ECPrivateKey], ScriptNumber)] = for { (scriptPubKey, privKeys) <- nonConditionalNonLocktimeRawScriptPubKey } yield { @@ -214,7 +228,8 @@ sealed abstract class ScriptGenerators { def csvScriptPubKey( num: ScriptNumber, - maxDepth: Int): Gen[(CSVScriptPubKey, Seq[ECPrivateKey], ScriptNumber)] = + maxDepth: Int + ): Gen[(CSVScriptPubKey, Seq[ECPrivateKey], ScriptNumber)] = for { (scriptPubKey, privKeys) <- nonLocktimeRawScriptPubKey(maxDepth - 1) } yield { @@ -223,15 +238,17 @@ sealed abstract class ScriptGenerators { } def csvScriptPubKey( - maxDepth: Int): Gen[(CSVScriptPubKey, Seq[ECPrivateKey])] = + maxDepth: Int + ): Gen[(CSVScriptPubKey, Seq[ECPrivateKey])] = for { (scriptPubKey, privKeys) <- nonLocktimeRawScriptPubKey(maxDepth - 1) num <- NumberGenerator.timeLockScriptNumbers csv = CSVScriptPubKey(num, scriptPubKey) } yield (csv, privKeys) - def nonConditionalCsvScriptPubKey(num: ScriptNumber): Gen[ - (CSVScriptPubKey, Seq[ECPrivateKey], ScriptNumber)] = { + def nonConditionalCsvScriptPubKey( + num: ScriptNumber + ): Gen[(CSVScriptPubKey, Seq[ECPrivateKey], ScriptNumber)] = { for { (scriptPubKey, privKeys) <- nonConditionalNonLocktimeRawScriptPubKey } yield { @@ -240,8 +257,8 @@ sealed abstract class ScriptGenerators { } } - def nonConditionalCsvScriptPubKey: Gen[ - (CSVScriptPubKey, Seq[ECPrivateKey])] = { + def nonConditionalCsvScriptPubKey + : Gen[(CSVScriptPubKey, Seq[ECPrivateKey])] = { for { (scriptPubKey, privKeys) <- nonConditionalNonLocktimeRawScriptPubKey num <- NumberGenerator.timeLockScriptNumbers @@ -249,8 +266,8 @@ sealed abstract class ScriptGenerators { } yield (csv, privKeys) } - def multiSigScriptPubKey: Gen[ - (MultiSignatureScriptPubKey, Seq[ECPrivateKey])] = + def multiSigScriptPubKey + : Gen[(MultiSignatureScriptPubKey, Seq[ECPrivateKey])] = for { (privateKeys, requiredSigs) <- CryptoGenerators.privateKeySeqWithRequiredSigs @@ -259,8 +276,8 @@ sealed abstract class ScriptGenerators { MultiSignatureScriptPubKey(requiredSigs, pubKeys) } yield (multiSignatureScriptPubKey, privateKeys.take(requiredSigs)) - def smallMultiSigScriptPubKey: Gen[ - (MultiSignatureScriptPubKey, Seq[ECPrivateKey])] = + def smallMultiSigScriptPubKey + : Gen[(MultiSignatureScriptPubKey, Seq[ECPrivateKey])] = for { (privateKeys, requiredSigs) <- CryptoGenerators.smallPrivateKeySeqWithRequiredSigs @@ -269,9 +286,11 @@ sealed abstract class ScriptGenerators { MultiSignatureScriptPubKey(requiredSigs, pubKeys) } yield (multiSignatureScriptPubKey, privateKeys.take(requiredSigs)) - /** Generates a random P2SHScriptPubKey as well as it's corresponding private keys and redeem script */ - def p2shScriptPubKey: Gen[ - (P2SHScriptPubKey, Seq[ECPrivateKey], ScriptPubKey)] = + /** Generates a random P2SHScriptPubKey as well as it's corresponding private + * keys and redeem script + */ + def p2shScriptPubKey + : Gen[(P2SHScriptPubKey, Seq[ECPrivateKey], ScriptPubKey)] = for { (randomScriptPubKey, privKeys) <- randomNonP2SHScriptPubKey @@ -292,10 +311,12 @@ sealed abstract class ScriptGenerators { /** Creates a ConditionalScriptPubKey with keys for the true case * - * @param maxDepth The maximum level of nesting allowed within this conditional. + * @param maxDepth + * The maximum level of nesting allowed within this conditional. */ def conditionalScriptPubKey( - maxDepth: Int): Gen[(ConditionalScriptPubKey, Seq[ECPrivateKey])] = { + maxDepth: Int + ): Gen[(ConditionalScriptPubKey, Seq[ECPrivateKey])] = { conditionalOperation.flatMap { op => if (maxDepth > 0) { for { @@ -313,7 +334,8 @@ sealed abstract class ScriptGenerators { /** Creates a ConditionalScriptPubKey with keys for the true case */ def nonLocktimeConditionalScriptPubKey( - maxDepth: Int): Gen[(ConditionalScriptPubKey, Seq[ECPrivateKey])] = { + maxDepth: Int + ): Gen[(ConditionalScriptPubKey, Seq[ECPrivateKey])] = { conditionalOperation.flatMap { op => if (maxDepth > 0) { for { @@ -329,8 +351,8 @@ sealed abstract class ScriptGenerators { } } - def multiSignatureWithTimeoutScriptPubKey: Gen[ - (MultiSignatureWithTimeoutScriptPubKey, Seq[ECPrivateKey])] = { + def multiSignatureWithTimeoutScriptPubKey + : Gen[(MultiSignatureWithTimeoutScriptPubKey, Seq[ECPrivateKey])] = { multiSigScriptPubKey.flatMap { case (multiSig, keys) => cltvScriptPubKey.map { case (cltv, _) => (MultiSignatureWithTimeoutScriptPubKey(multiSig, cltv), keys) @@ -344,7 +366,9 @@ sealed abstract class ScriptGenerators { privKey <- CryptoGenerators.privateKey } yield (P2WPKHWitnessSPKV0(privKey.publicKey), Seq(privKey)) - /** Generates a random P2WSHWitnessSPKV0 as well as it's corresponding private keys and redeem script */ + /** Generates a random P2WSHWitnessSPKV0 as well as it's corresponding private + * keys and redeem script + */ def p2wshSPKV0: Gen[(P2WSHWitnessSPKV0, Seq[ECPrivateKey], ScriptPubKey)] = rawScriptPubKey .suchThat { case (spk, _) => @@ -366,12 +390,12 @@ sealed abstract class ScriptGenerators { } } - /** Creates an unassigned witness scriptPubKey. - * Currently this is any witness script pubkey besides + /** Creates an unassigned witness scriptPubKey. Currently this is any witness + * script pubkey besides * [[org.bitcoins.core.protocol.script.WitnessScriptPubKeyV0 WitnessScriptPubKeyV0]] */ - def unassignedWitnessScriptPubKey: Gen[ - (UnassignedWitnessScriptPubKey, Seq[ECPrivateKey])] = + def unassignedWitnessScriptPubKey + : Gen[(UnassignedWitnessScriptPubKey, Seq[ECPrivateKey])] = for { (witV0, privKeys) <- p2wpkhSPKV0 version <- Gen.oneOf(WitnessScriptPubKey.unassignedWitVersions) @@ -382,8 +406,8 @@ sealed abstract class ScriptGenerators { def witnessScriptPubKey: Gen[(WitnessScriptPubKey, Seq[ECPrivateKey])] = Gen.oneOf(assignedWitnessScriptPubKey, unassignedWitnessScriptPubKey) - def assignedWitnessScriptPubKey: Gen[ - (WitnessScriptPubKey, Seq[ECPrivateKey])] = { + def assignedWitnessScriptPubKey + : Gen[(WitnessScriptPubKey, Seq[ECPrivateKey])] = { Gen.oneOf(p2wpkhSPKV0, p2wshSPKV0.map(truncate), witnessScriptPubKeyV1) } @@ -398,9 +422,11 @@ sealed abstract class ScriptGenerators { p2pkhScriptPubKey.map(privKeyToSeq(_)), p2pkWithTimeoutScriptPubKey, cltvScriptPubKey(defaultMaxDepth).suchThat( - !_._1.nestedScriptPubKey.isInstanceOf[CSVScriptPubKey]), + !_._1.nestedScriptPubKey.isInstanceOf[CSVScriptPubKey] + ), csvScriptPubKey(defaultMaxDepth).suchThat( - !_._1.nestedScriptPubKey.isInstanceOf[CLTVScriptPubKey]), + !_._1.nestedScriptPubKey.isInstanceOf[CLTVScriptPubKey] + ), multiSigScriptPubKey, p2wpkhSPKV0, unassignedWitnessScriptPubKey, @@ -410,20 +436,23 @@ sealed abstract class ScriptGenerators { } def randomNonLockTimeScriptSig: Gen[ScriptSignature] = { - Gen.oneOf(p2pkScriptSignature, - p2pkhScriptSignature, - multiSignatureScriptSignature, - emptyScriptSignature, - p2shScriptSignature, - nonLockTimeConditionalScriptSignature) + Gen.oneOf( + p2pkScriptSignature, + p2pkhScriptSignature, + multiSignatureScriptSignature, + emptyScriptSignature, + p2shScriptSignature, + nonLockTimeConditionalScriptSignature + ) } def lockTimeScriptPubKey( - maxDepth: Int): Gen[(LockTimeScriptPubKey, Seq[ECPrivateKey])] = + maxDepth: Int + ): Gen[(LockTimeScriptPubKey, Seq[ECPrivateKey])] = Gen.oneOf(cltvScriptPubKey(maxDepth), csvScriptPubKey(maxDepth)) - def nonConditionalLockTimeScriptPubKey: Gen[ - (LockTimeScriptPubKey, Seq[ECPrivateKey])] = + def nonConditionalLockTimeScriptPubKey + : Gen[(LockTimeScriptPubKey, Seq[ECPrivateKey])] = Gen.oneOf(nonConditionalCltvScriptPubKey, nonConditionalCsvScriptPubKey) def lockTimeScriptSig: Gen[LockTimeScriptSignature] = @@ -449,8 +478,8 @@ sealed abstract class ScriptGenerators { ) } - def nonWitnessScriptPubKey: Gen[ - (NonWitnessScriptPubKey, Seq[ECPrivateKey])] = { + def nonWitnessScriptPubKey + : Gen[(NonWitnessScriptPubKey, Seq[ECPrivateKey])] = { Gen.oneOf( p2pkScriptPubKey.map(privKeyToSeq), p2pkhScriptPubKey.map(privKeyToSeq), @@ -465,8 +494,8 @@ sealed abstract class ScriptGenerators { ) } - def nonConditionalNonLocktimeRawScriptPubKey: Gen[ - (RawScriptPubKey, Seq[ECPrivateKey])] = { + def nonConditionalNonLocktimeRawScriptPubKey + : Gen[(RawScriptPubKey, Seq[ECPrivateKey])] = { Gen.oneOf( p2pkScriptPubKey.map(privKeyToSeq), p2pkhScriptPubKey.map(privKeyToSeq), @@ -476,7 +505,8 @@ sealed abstract class ScriptGenerators { } def nonLocktimeRawScriptPubKey( - maxDepth: Int): Gen[(RawScriptPubKey, Seq[ECPrivateKey])] = { + maxDepth: Int + ): Gen[(RawScriptPubKey, Seq[ECPrivateKey])] = { Gen.oneOf( p2pkScriptPubKey.map(privKeyToSeq), p2pkhScriptPubKey.map(privKeyToSeq), @@ -486,8 +516,8 @@ sealed abstract class ScriptGenerators { ) } - def nonConditionalRawScriptPubKey: Gen[ - (RawScriptPubKey, Seq[ECPrivateKey])] = { + def nonConditionalRawScriptPubKey + : Gen[(RawScriptPubKey, Seq[ECPrivateKey])] = { Gen.oneOf( p2pkScriptPubKey.map(privKeyToSeq), p2pkhScriptPubKey.map(privKeyToSeq), @@ -503,7 +533,8 @@ sealed abstract class ScriptGenerators { } def rawScriptPubKey( - maxDepth: Int): Gen[(RawScriptPubKey, Seq[ECPrivateKey])] = { + maxDepth: Int + ): Gen[(RawScriptPubKey, Seq[ECPrivateKey])] = { Gen.oneOf( p2pkScriptPubKey.map(privKeyToSeq), p2pkhScriptPubKey.map(privKeyToSeq), @@ -526,9 +557,9 @@ sealed abstract class ScriptGenerators { emptyScriptSignature, p2shScriptSignature, conditionalScriptSignature - //NOTE: This are commented out because it fail serializatoin symmetry - //sicne we cannot properly type CSV/CLTV ScriptSigs w/o it's SPK - //csvScriptSignature, cltvScriptSignature + // NOTE: This are commented out because it fail serializatoin symmetry + // sicne we cannot properly type CSV/CLTV ScriptSigs w/o it's SPK + // csvScriptSignature, cltvScriptSignature ) } @@ -543,12 +574,12 @@ sealed abstract class ScriptGenerators { ) } - /** Generates a `ScriptSignature` corresponding to the type of - * `ScriptPubKey` given. - * Note: Does NOT generate a correct/valid signature + /** Generates a `ScriptSignature` corresponding to the type of `ScriptPubKey` + * given. Note: Does NOT generate a correct/valid signature */ private def pickCorrespondingScriptSignature( - scriptPubKey: ScriptPubKey): Gen[ScriptSignature] = + scriptPubKey: ScriptPubKey + ): Gen[ScriptSignature] = scriptPubKey match { case _: P2PKScriptPubKey => p2pkScriptSignature case _: P2PKHScriptPubKey => p2pkhScriptSignature @@ -567,18 +598,19 @@ sealed abstract class ScriptGenerators { _: WitnessCommitment) => throw new IllegalArgumentException( "Cannot pick for p2sh script pubkey, " + - "non standard script pubkey or witness commitment got: " + x) + "non standard script pubkey or witness commitment got: " + x + ) } /** Generates a signed `P2PKScriptSignature` that spends the * `P2PKScriptPubKey` correctly * - * @return the signed `P2PKScriptSignature`, - * the `P2PKScriptPubKey` it spends, and the - * `ECPrivateKey` used to sign the scriptSig + * @return + * the signed `P2PKScriptSignature`, the `P2PKScriptPubKey` it spends, and + * the `ECPrivateKey` used to sign the scriptSig */ - def signedP2PKScriptSignature: Gen[ - (P2PKScriptSignature, P2PKScriptPubKey, ECPrivateKey)] = + def signedP2PKScriptSignature + : Gen[(P2PKScriptSignature, P2PKScriptPubKey, ECPrivateKey)] = for { privateKey <- CryptoGenerators.privateKey hashType <- CryptoGenerators.hashType @@ -590,33 +622,38 @@ sealed abstract class ScriptGenerators { (spendingTx, inputIndex) = TransactionGenerators.buildSpendingTransaction( creditingTx, EmptyScriptSignature, - outputIndex) + outputIndex + ) spendingInfo = ScriptSignatureParams( - P2PKInputInfo(TransactionOutPoint(creditingTx.txIdBE, inputIndex), - creditingTx.outputs(outputIndex.toInt).value, - scriptPubKey), + P2PKInputInfo( + TransactionOutPoint(creditingTx.txIdBE, inputIndex), + creditingTx.outputs(outputIndex.toInt).value, + scriptPubKey + ), creditingTx, privateKey, hashType ) - txSigComponent = P2PKSigner.sign(spendingInfo, - spendingTx, - isDummySignature = false) - //add the signature to the scriptSig instead of having an empty scriptSig + txSigComponent = P2PKSigner.sign( + spendingInfo, + spendingTx, + isDummySignature = false + ) + // add the signature to the scriptSig instead of having an empty scriptSig signedScriptSig = txSigComponent.scriptSignature .asInstanceOf[P2PKScriptSignature] } yield (signedScriptSig, scriptPubKey, privateKey) - /** Generates a signed `P2PKHScriptSignature` that - * spends the `P2PKHScriptPubKey` correctly + /** Generates a signed `P2PKHScriptSignature` that spends the + * `P2PKHScriptPubKey` correctly * - * @return the signed `P2PKHScriptSignature`, the - * `P2PKHScriptPubKey` it spends, and the - * `ECPrivateKey` used to sign the scriptSig + * @return + * the signed `P2PKHScriptSignature`, the `P2PKHScriptPubKey` it spends, + * and the `ECPrivateKey` used to sign the scriptSig */ - def signedP2PKHScriptSignature: Gen[ - (P2PKHScriptSignature, P2PKHScriptPubKey, ECPrivateKey)] = { + def signedP2PKHScriptSignature + : Gen[(P2PKHScriptSignature, P2PKHScriptPubKey, ECPrivateKey)] = { for { privateKey <- CryptoGenerators.privateKey hashType <- CryptoGenerators.hashType @@ -628,18 +665,23 @@ sealed abstract class ScriptGenerators { (unsignedTx, inputIndex) = TransactionGenerators.buildSpendingTransaction( creditingTx, EmptyScriptSignature, - outputIndex) + outputIndex + ) spendingInfo = ScriptSignatureParams( - P2PKHInputInfo(TransactionOutPoint(creditingTx.txIdBE, inputIndex), - creditingTx.outputs(outputIndex.toInt).value, - privateKey.publicKey), + P2PKHInputInfo( + TransactionOutPoint(creditingTx.txIdBE, inputIndex), + creditingTx.outputs(outputIndex.toInt).value, + privateKey.publicKey + ), creditingTx, privateKey, hashType ) - txSigComponent = P2PKHSigner.sign(spendingInfo, - unsignedTx, - isDummySignature = false) + txSigComponent = P2PKHSigner.sign( + spendingInfo, + unsignedTx, + isDummySignature = false + ) signedScriptSig = txSigComponent.scriptSignature .asInstanceOf[P2PKHScriptSignature] @@ -647,7 +689,8 @@ sealed abstract class ScriptGenerators { } def signedP2PKWithTimeoutScriptSignature: Gen[ - (ConditionalScriptSignature, P2PKWithTimeoutScriptPubKey, ECPrivateKey)] = + (ConditionalScriptSignature, P2PKWithTimeoutScriptPubKey, ECPrivateKey) + ] = for { (spk, privKeys) <- p2pkWithTimeoutScriptPubKey hashType <- CryptoGenerators.hashType @@ -663,32 +706,37 @@ sealed abstract class ScriptGenerators { TransactionOutPoint(creditingTx.txIdBE, inputIndex), creditingTx.outputs(outputIndex.toInt).value, spk, - isBeforeTimeout = true), + isBeforeTimeout = true + ), creditingTx, privKey, hashType ) - val txSigComponent = P2PKWithTimeoutSigner.sign(spendingInfo, - spendingTx, - isDummySignature = false) + val txSigComponent = P2PKWithTimeoutSigner.sign( + spendingInfo, + spendingTx, + isDummySignature = false + ) val signedScriptSig = txSigComponent.scriptSignature.asInstanceOf[ConditionalScriptSignature] (signedScriptSig, spk, privKey) } - /** Generates a signed - * `MultiSignatureScriptSignature` that spends the - * `MultiSignatureScriptPubKey` correctly - * ti - * @return the signed `MultiSignatureScriptSignature`, - * the `MultiSignatureScriptPubKey` it spends and the - * sequence of `ECPrivateKey` used to sign the scriptSig + /** Generates a signed `MultiSignatureScriptSignature` that spends the + * `MultiSignatureScriptPubKey` correctly ti + * @return + * the signed `MultiSignatureScriptSignature`, the + * `MultiSignatureScriptPubKey` it spends and the sequence of + * `ECPrivateKey` used to sign the scriptSig */ - def signedMultiSignatureScriptSignature: Gen[( - MultiSignatureScriptSignature, - MultiSignatureScriptPubKey, - Seq[ECPrivateKey])] = + def signedMultiSignatureScriptSignature: Gen[ + ( + MultiSignatureScriptSignature, + MultiSignatureScriptPubKey, + Seq[ECPrivateKey] + ) + ] = for { (privateKeysWithExtra, requiredSigs) <- CryptoGenerators.privateKeySeqWithRequiredSigs @@ -705,12 +753,14 @@ sealed abstract class ScriptGenerators { (spendingTx, inputIndex) = TransactionGenerators.buildSpendingTransaction( creditingTx, scriptSig, - outputIndex) + outputIndex + ) spendingInfo = ScriptSignatureParams( MultiSignatureInputInfo( TransactionOutPoint(creditingTx.txIdBE, inputIndex), creditingTx.outputs(outputIndex.toInt).value, - multiSigScriptPubKey), + multiSigScriptPubKey + ), creditingTx, privateKeys.toVector, hashType @@ -722,10 +772,9 @@ sealed abstract class ScriptGenerators { .asInstanceOf[MultiSignatureScriptSignature] } yield (signedScriptSig, multiSigScriptPubKey, privateKeys) - def signedConditionalScriptSignature: Gen[( - ConditionalScriptSignature, - ConditionalScriptPubKey, - Seq[ECPrivateKey])] = { + def signedConditionalScriptSignature: Gen[ + (ConditionalScriptSignature, ConditionalScriptPubKey, Seq[ECPrivateKey]) + ] = { val signed = Gen.oneOf( packageToSequenceOfPrivateKeys(signedP2PKHScriptSignature), packageToSequenceOfPrivateKeys(signedP2PKScriptSignature), @@ -739,18 +788,23 @@ sealed abstract class ScriptGenerators { signed.flatMap { case (scriptSig, spk, keys) => conditionalOperation.flatMap { op => rawScriptPubKey(defaultMaxDepth).map(_._1).map { spk2 => - (ConditionalScriptSignature(scriptSig, true), - ConditionalScriptPubKey(op, spk, spk2), - keys) + ( + ConditionalScriptSignature(scriptSig, true), + ConditionalScriptPubKey(op, spk, spk2), + keys + ) } } } } - def signedMultiSignatureWithTimeoutScriptSignature: Gen[( - ConditionalScriptSignature, - MultiSignatureWithTimeoutScriptPubKey, - Seq[ECPrivateKey])] = { + def signedMultiSignatureWithTimeoutScriptSignature: Gen[ + ( + ConditionalScriptSignature, + MultiSignatureWithTimeoutScriptPubKey, + Seq[ECPrivateKey] + ) + ] = { NumberGenerator.bool.flatMap { condition => signedMultiSignatureScriptSignature.flatMap { case (multiSigScriptSig, multiSigSPK, multiSigKeys) => @@ -759,37 +813,41 @@ sealed abstract class ScriptGenerators { val spk = MultiSignatureWithTimeoutScriptPubKey(multiSigSPK, cltvSPK) if (condition) { - (ConditionalScriptSignature(multiSigScriptSig, condition), - spk, - multiSigKeys) + ( + ConditionalScriptSignature(multiSigScriptSig, condition), + spk, + multiSigKeys + ) } else { - (ConditionalScriptSignature(cltvScriptSig, condition), - spk, - cltvKeys) + ( + ConditionalScriptSignature(cltvScriptSig, condition), + spk, + cltvKeys + ) } } } } } - /** Generates a signed `P2SHScriptSignature` - * that spends from a `P2SHScriptPubKey` correctly + /** Generates a signed `P2SHScriptSignature` that spends from a + * `P2SHScriptPubKey` correctly * - * @return the signed `P2SHScriptSignature`, - * the `P2SHScriptPubKey` it spends, and the - * sequence of `ECPrivateKey` - * used to sign the scriptSig + * @return + * the signed `P2SHScriptSignature`, the `P2SHScriptPubKey` it spends, and + * the sequence of `ECPrivateKey` used to sign the scriptSig */ - def signedP2SHScriptSignature: Gen[ - (P2SHScriptSignature, P2SHScriptPubKey, Seq[ECPrivateKey])] = + def signedP2SHScriptSignature + : Gen[(P2SHScriptSignature, P2SHScriptPubKey, Seq[ECPrivateKey])] = for { (scriptSig, redeemScript, privateKeys) <- chooseSignedScriptSig p2SHScriptPubKey = P2SHScriptPubKey(redeemScript) p2SHScriptSignature = P2SHScriptSignature(scriptSig, redeemScript) } yield (p2SHScriptSignature, p2SHScriptPubKey, privateKeys) - /** Utility function to compute how many signatures will be required in the inner-most true case. - * For use with CLTV and CSV ScriptSignature generation. + /** Utility function to compute how many signatures will be required in the + * inner-most true case. For use with CLTV and CSV ScriptSignature + * generation. */ @tailrec private def findRequiredSigs(conditional: ConditionalScriptPubKey): Int = { @@ -799,7 +857,8 @@ sealed abstract class ScriptGenerators { findRequiredSigs(nestedConditional) case _: LockTimeScriptPubKey => throw new IllegalArgumentException( - "This shouldn't happen since we are using nonLocktimeRawScriptPubKey") + "This shouldn't happen since we are using nonLocktimeRawScriptPubKey" + ) case _: P2PKHScriptPubKey | _: P2PKScriptPubKey | _: P2PKWithTimeoutScriptPubKey => 1 @@ -809,16 +868,15 @@ sealed abstract class ScriptGenerators { } } - /** @return the signed `CLTVScriptSignature`, the - * `CLTVScriptPubKey` it spends, and the - * sequences of `ECPrivateKey` - * used to sign the scriptSig + /** @return + * the signed `CLTVScriptSignature`, the `CLTVScriptPubKey` it spends, and + * the sequences of `ECPrivateKey` used to sign the scriptSig */ def signedCLTVScriptSignature( cltvLockTime: ScriptNumber, lockTime: UInt32, - sequence: UInt32): Gen[ - (CLTVScriptSignature, CLTVScriptPubKey, Seq[ECPrivateKey])] = + sequence: UInt32 + ): Gen[(CLTVScriptSignature, CLTVScriptPubKey, Seq[ECPrivateKey])] = for { (scriptPubKey, privKeys) <- nonLocktimeRawScriptPubKey(defaultMaxDepth) hashType <- CryptoGenerators.hashType @@ -826,57 +884,65 @@ sealed abstract class ScriptGenerators { } yield scriptPubKey match { case m: MultiSignatureScriptPubKey => val requiredSigs = m.requiredSigs - val cltvScriptSig = lockTimeHelper(Some(lockTime), - sequence, - cltv, - privKeys, - Some(requiredSigs), - hashType) + val cltvScriptSig = lockTimeHelper( + Some(lockTime), + sequence, + cltv, + privKeys, + Some(requiredSigs), + hashType + ) (cltvScriptSig.asInstanceOf[CLTVScriptSignature], cltv, privKeys) case conditional: ConditionalScriptPubKey => - val cltvScriptSig = lockTimeHelper(Some(lockTime), - sequence, - cltv, - privKeys, - Some(findRequiredSigs(conditional)), - hashType) + val cltvScriptSig = lockTimeHelper( + Some(lockTime), + sequence, + cltv, + privKeys, + Some(findRequiredSigs(conditional)), + hashType + ) (cltvScriptSig.asInstanceOf[CLTVScriptSignature], cltv, privKeys) case _: P2PKHScriptPubKey | _: P2PKScriptPubKey => - val cltvScriptSig = lockTimeHelper(Some(lockTime), - sequence, - cltv, - privKeys, - None, - hashType) + val cltvScriptSig = lockTimeHelper( + Some(lockTime), + sequence, + cltv, + privKeys, + None, + hashType + ) (cltvScriptSig.asInstanceOf[CLTVScriptSignature], cltv, privKeys) case EmptyScriptPubKey => - val cltvScriptSig = lockTimeHelper(Some(lockTime), - sequence, - cltv, - privKeys, - Some(0), - hashType) + val cltvScriptSig = lockTimeHelper( + Some(lockTime), + sequence, + cltv, + privKeys, + Some(0), + hashType + ) (cltvScriptSig.asInstanceOf[CLTVScriptSignature], cltv, privKeys) case _: CLTVScriptPubKey | _: P2PKWithTimeoutScriptPubKey | _: CSVScriptPubKey | _: NonStandardScriptPubKey | _: WitnessCommitment => throw new IllegalArgumentException( "We only " + - "want to generate P2PK, P2PKH, and MultiSig ScriptSignatures when creating a CSVScriptSignature") + "want to generate P2PK, P2PKH, and MultiSig ScriptSignatures when creating a CSVScriptSignature" + ) } - /** Generates a signed `CLTVScriptSignature` that spends - * from a `CLTVScriptSignature` correctly + /** Generates a signed `CLTVScriptSignature` that spends from a + * `CLTVScriptSignature` correctly * - * @return the signed `CSVScriptSignature`, the - * `CSVScriptPubKey` it spends, and the - * sequences of `ECPrivateKey` - * used to sign the scriptSig + * @return + * the signed `CSVScriptSignature`, the `CSVScriptPubKey` it spends, and + * the sequences of `ECPrivateKey` used to sign the scriptSig */ def signedCSVScriptSignature( csvScriptNum: ScriptNumber, - sequence: UInt32): Gen[ - (CSVScriptSignature, CSVScriptPubKey, Seq[ECPrivateKey])] = + sequence: UInt32 + ): Gen[(CSVScriptSignature, CSVScriptPubKey, Seq[ECPrivateKey])] = for { (scriptPubKey, privKeys) <- nonLocktimeRawScriptPubKey(defaultMaxDepth) hashType <- CryptoGenerators.hashType @@ -884,20 +950,24 @@ sealed abstract class ScriptGenerators { } yield scriptPubKey match { case m: MultiSignatureScriptPubKey => val requiredSigs = m.requiredSigs - val csvScriptSig = lockTimeHelper(None, - sequence, - csv, - privKeys, - Some(requiredSigs), - hashType) + val csvScriptSig = lockTimeHelper( + None, + sequence, + csv, + privKeys, + Some(requiredSigs), + hashType + ) (csvScriptSig.asInstanceOf[CSVScriptSignature], csv, privKeys) case conditional: ConditionalScriptPubKey => - val csvScriptSig = lockTimeHelper(None, - sequence, - csv, - privKeys, - Some(findRequiredSigs(conditional)), - hashType) + val csvScriptSig = lockTimeHelper( + None, + sequence, + csv, + privKeys, + Some(findRequiredSigs(conditional)), + hashType + ) (csvScriptSig.asInstanceOf[CSVScriptSignature], csv, privKeys) case _: P2PKHScriptPubKey | _: P2PKScriptPubKey => val csvScriptSig = @@ -912,19 +982,20 @@ sealed abstract class ScriptGenerators { _: WitnessCommitment => throw new IllegalArgumentException( "We only " + - "want to generate P2PK, P2PKH, and MultiSig ScriptSignatures when creating a CLTVScriptSignature.") + "want to generate P2PK, P2PKH, and MultiSig ScriptSignatures when creating a CLTVScriptSignature." + ) } - def signedCSVScriptSignature: Gen[ - (CSVScriptSignature, CSVScriptPubKey, Seq[ECPrivateKey])] = + def signedCSVScriptSignature + : Gen[(CSVScriptSignature, CSVScriptPubKey, Seq[ECPrivateKey])] = for { (csv, privKeys) <- csvScriptPubKey(defaultMaxDepth) sequence <- NumberGenerator.uInt32s scriptSig <- signedCSVScriptSignature(csv.locktime, sequence) } yield scriptSig - def signedCLTVScriptSignature: Gen[ - (CLTVScriptSignature, CLTVScriptPubKey, Seq[ECPrivateKey])] = + def signedCLTVScriptSignature + : Gen[(CLTVScriptSignature, CLTVScriptPubKey, Seq[ECPrivateKey])] = for { (cltv, privKeys) <- cltvScriptPubKey(defaultMaxDepth) txLockTime <- NumberGenerator.uInt32s @@ -933,12 +1004,12 @@ sealed abstract class ScriptGenerators { signedCLTVScriptSignature(cltv.locktime, txLockTime, sequence) } yield scriptSig - /** Generates a `LockTimeScriptSignature` and - * `LockTimeScriptPubKey` pair that are valid when - * run through the interpreter + /** Generates a `LockTimeScriptSignature` and `LockTimeScriptPubKey` pair that + * are valid when run through the interpreter */ def signedLockTimeScriptSignature: Gen[ - (LockTimeScriptSignature, LockTimeScriptPubKey, Seq[ECPrivateKey])] = { + (LockTimeScriptSignature, LockTimeScriptPubKey, Seq[ECPrivateKey]) + ] = { Gen.oneOf(signedCSVScriptSignature, signedCLTVScriptSignature) } @@ -949,7 +1020,8 @@ sealed abstract class ScriptGenerators { lock: LockTimeScriptPubKey, privateKeys: Seq[ECPrivateKey], requiredSigs: Option[Int], - hashType: HashType): LockTimeScriptSignature = { + hashType: HashType + ): LockTimeScriptSignature = { val tc = TransactionConstants val pubKeys = privateKeys.map(_.publicKey) val (creditingTx, outputIndex) = @@ -961,19 +1033,23 @@ sealed abstract class ScriptGenerators { EmptyScriptSignature, outputIndex, lockTime.getOrElse(tc.lockTime), - sequence) + sequence + ) val output = TransactionOutput(CurrencyUnits.zero, lock) val txSignatureComponent = BaseTxSigComponent( unsignedSpendingTx, inputIndex, output, - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) val txSignatures: Seq[ECDigitalSignature] = for { i <- 0 until requiredSigs.getOrElse(1) - } yield TransactionSignatureCreator.createSig(txSignatureComponent, - privateKeys(i), - hashType) + } yield TransactionSignatureCreator.createSig( + txSignatureComponent, + privateKeys(i), + hashType + ) lock match { case csv: CSVScriptPubKey => @@ -993,18 +1069,23 @@ sealed abstract class ScriptGenerators { P2SHScriptPubKey, Seq[ECPrivateKey], TransactionWitness, - CurrencyUnit)] = + CurrencyUnit + ) + ] = for { (witness, wtxSigComponent, privKeys) <- WitnessGenerators.signedP2WPKHTransactionWitness p2shScriptPubKey = P2SHScriptPubKey(wtxSigComponent.scriptPubKey) p2shScriptSig = P2SHScriptSignature( - wtxSigComponent.scriptPubKey.asInstanceOf[WitnessScriptPubKey]) - } yield (p2shScriptSig, - p2shScriptPubKey, - privKeys, - witness, - wtxSigComponent.amount) + wtxSigComponent.scriptPubKey.asInstanceOf[WitnessScriptPubKey] + ) + } yield ( + p2shScriptSig, + p2shScriptPubKey, + privKeys, + witness, + wtxSigComponent.amount + ) def signedP2SHP2WSHScriptSignature: Gen[ ( @@ -1012,29 +1093,32 @@ sealed abstract class ScriptGenerators { P2SHScriptPubKey, Seq[ECPrivateKey], TransactionWitness, - CurrencyUnit)] = + CurrencyUnit + ) + ] = for { (witness, wtxSigComponent, privKeys) <- WitnessGenerators.signedP2WSHTransactionWitness p2shScriptPubKey = P2SHScriptPubKey(wtxSigComponent.scriptPubKey) p2shScriptSig = P2SHScriptSignature(wtxSigComponent.scriptPubKey) - } yield (p2shScriptSig, - p2shScriptPubKey, - privKeys, - witness, - wtxSigComponent.amount) + } yield ( + p2shScriptSig, + p2shScriptPubKey, + privKeys, + witness, + wtxSigComponent.amount + ) - /** This function chooses a random signed `ScriptSignature` - * that is NOT a `P2SHScriptSignature`, - * `CSVScriptSignature`, - * `CLTVScriptSignature`, or any witness type + /** This function chooses a random signed `ScriptSignature` that is NOT a + * `P2SHScriptSignature`, `CSVScriptSignature`, `CLTVScriptSignature`, or any + * witness type * - * @return the signed `ScriptSignature`, - * the `ScriptPubKey` it is spending, - * and the sequence of `ECPrivateKey` used to sign it + * @return + * the signed `ScriptSignature`, the `ScriptPubKey` it is spending, and the + * sequence of `ECPrivateKey` used to sign it */ - def chooseSignedScriptSig: Gen[ - (ScriptSignature, ScriptPubKey, Seq[ECPrivateKey])] = { + def chooseSignedScriptSig + : Gen[(ScriptSignature, ScriptPubKey, Seq[ECPrivateKey])] = { Gen.oneOf( packageToSequenceOfPrivateKeys(signedP2PKScriptSignature), packageToSequenceOfPrivateKeys(signedP2PKHScriptSignature), @@ -1042,12 +1126,11 @@ sealed abstract class ScriptGenerators { ) } - /** Generates a random `ScriptSignature`, the - * `ScriptPubKey` it is spending, and the - * `ECPrivateKey` needed to spend it. + /** Generates a random `ScriptSignature`, the `ScriptPubKey` it is spending, + * and the `ECPrivateKey` needed to spend it. */ - def randomScriptSig: Gen[ - (ScriptSignature, ScriptPubKey, Seq[ECPrivateKey])] = { + def randomScriptSig + : Gen[(ScriptSignature, ScriptPubKey, Seq[ECPrivateKey])] = { val witP2SHP2WPKH = signedP2SHP2WPKHScriptSignature.map(x => (x._1, x._2, x._3)) val witP2SHP2WSH = @@ -1067,17 +1150,22 @@ sealed abstract class ScriptGenerators { ) } - /** Simply converts one private key in the generator to a sequence of private keys */ + /** Simply converts one private key in the generator to a sequence of private + * keys + */ private def packageToSequenceOfPrivateKeys[SPK <: ScriptPubKey]( - gen: Gen[(ScriptSignature, SPK, ECPrivateKey)]): Gen[ - (ScriptSignature, SPK, Seq[ECPrivateKey])] = + gen: Gen[(ScriptSignature, SPK, ECPrivateKey)] + ): Gen[(ScriptSignature, SPK, Seq[ECPrivateKey])] = for { (scriptSig, scriptPubKey, privateKey) <- gen } yield (scriptSig, scriptPubKey, Seq(privateKey)) - /** Simply converts one private key in the generator to a sequence of private keys */ + /** Simply converts one private key in the generator to a sequence of private + * keys + */ private def privKeyToSeq[T]( - tuple: (T, ECPrivateKey)): (T, Seq[ECPrivateKey]) = { + tuple: (T, ECPrivateKey) + ): (T, Seq[ECPrivateKey]) = { val (s, key) = tuple (s, Seq(key)) } @@ -1085,11 +1173,12 @@ sealed abstract class ScriptGenerators { private def lockTimeHelperScriptSig( lock: LockTimeScriptPubKey, sigs: Seq[ECDigitalSignature], - keys: Seq[ECPublicKey]): LockTimeScriptSignature = { + keys: Seq[ECPublicKey] + ): LockTimeScriptSignature = { val nestedScriptSig = lock.nestedScriptPubKey match { - case _: P2PKScriptPubKey => P2PKScriptSignature(sigs.head) - case _: P2PKHScriptPubKey => P2PKHScriptSignature(sigs.head, keys.head) + case _: P2PKScriptPubKey => P2PKScriptSignature(sigs.head) + case _: P2PKHScriptPubKey => P2PKHScriptSignature(sigs.head, keys.head) case _: MultiSignatureScriptPubKey => MultiSignatureScriptSignature(sigs) case conditional: ConditionalScriptPubKey => val spk = lock match { @@ -1104,11 +1193,13 @@ sealed abstract class ScriptGenerators { CSVScriptSignature(TrivialTrueScriptSignature) case _: LockTimeScriptPubKey | _: P2PKWithTimeoutScriptPubKey => throw new IllegalArgumentException( - "Cannot have a nested locktimeScriptPubKey inside a lockTimeScriptPubKey") + "Cannot have a nested locktimeScriptPubKey inside a lockTimeScriptPubKey" + ) case x @ (_: NonStandardScriptPubKey | _: WitnessCommitment) => throw new IllegalArgumentException( "A NonStandardScriptPubKey/P2SHScriptPubKey/WitnessCommitment cannot be" + - "the underlying scriptSig in a CSVScriptSignature. Got: " + x) + "the underlying scriptSig in a CSVScriptSignature. Got: " + x + ) } lock match { diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/StringGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/StringGenerators.scala index 0cc5806b95..059fdcc624 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/StringGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/StringGenerators.scala @@ -63,12 +63,12 @@ trait StringGenerators { def genUTF8String: Gen[String] = { for { bytes <- NumberGenerator.bytes - //this is done to get postgres tests working with utf8 strings - //I don't think we want to keep this here, as this seems like an exploit that is possible - //do we want to narrow the DLC spec or something? What is the point of having a - //null character in a UTF8 string for our purposes any way? - //To reproduce, use PG_ENABLED=1 and comment out the line below when running dlcOracleTest/test - //see: https://stackoverflow.com/a/1348551/967713 + // this is done to get postgres tests working with utf8 strings + // I don't think we want to keep this here, as this seems like an exploit that is possible + // do we want to narrow the DLC spec or something? What is the point of having a + // null character in a UTF8 string for our purposes any way? + // To reproduce, use PG_ENABLED=1 and comment out the line below when running dlcOracleTest/test + // see: https://stackoverflow.com/a/1348551/967713 noZero = bytes.filterNot(_ == 0x0) str = new String(noZero.toArray, StandardCharsets.UTF_8) } yield str diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/TLVGen.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/TLVGen.scala index bed6551fa0..d0026ce448 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/TLVGen.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/TLVGen.scala @@ -107,19 +107,21 @@ trait TLVGen { } yield EnumEventDescriptorV0TLV(outcomes.toVector) } - def digitDecompositionEventDescriptorV0TLV: Gen[ - DigitDecompositionEventDescriptorV0TLV] = { + def digitDecompositionEventDescriptorV0TLV + : Gen[DigitDecompositionEventDescriptorV0TLV] = { for { base <- NumberGenerator.uInt16 isSigned <- NumberGenerator.bool numDigits <- Gen.choose(2, 20) unit <- StringGenerators.genUTF8String precision <- NumberGenerator.int32s - } yield DigitDecompositionEventDescriptorV0TLV(base, - isSigned, - numDigits, - unit, - precision) + } yield DigitDecompositionEventDescriptorV0TLV( + base, + isSigned, + numDigits, + unit, + precision + ) } def eventDescriptorTLV: Gen[EventDescriptorTLV] = @@ -134,10 +136,12 @@ trait TLVGen { Gen .listOfN(desc.noncesNeeded, CryptoGenerators.schnorrNonce) .map(_.toVector) - } yield OracleEventV0TLV(OrderedNonces.fromUnsorted(nonces).toVector, - maturity, - desc, - uri) + } yield OracleEventV0TLV( + OrderedNonces.fromUnsorted(nonces).toVector, + maturity, + desc, + uri + ) } def oracleAnnouncementV0TLV: Gen[OracleAnnouncementV0TLV] = { @@ -165,8 +169,8 @@ trait TLVGen { } yield OracleAttestmentV0TLV(eventId, pubkey, sigs.toVector, outcomes) } - def contractDescriptorV0TLVWithTotalCollateral: Gen[ - (ContractDescriptorV0TLV, Satoshis)] = { + def contractDescriptorV0TLVWithTotalCollateral + : Gen[(ContractDescriptorV0TLV, Satoshis)] = { for { numOutcomes <- Gen.choose(2, 10) outcomes <- Gen.listOfN(numOutcomes, StringGenerators.genString) @@ -185,8 +189,8 @@ trait TLVGen { contractDescriptorV0TLVWithTotalCollateral.map(_._1) } - def contractDescriptorV1TLVWithTotalCollateral: Gen[ - (ContractDescriptorV1TLV, Satoshis)] = { + def contractDescriptorV1TLVWithTotalCollateral + : Gen[(ContractDescriptorV1TLV, Satoshis)] = { for { numDigits <- Gen.choose(3, 7) totalInput <- @@ -204,10 +208,12 @@ trait TLVGen { contractDescriptorV1TLVWithTotalCollateral.map(_._1) } - def contractDescriptorTLVWithTotalCollateral: Gen[ - (ContractDescriptorTLV, Satoshis)] = { - Gen.oneOf(contractDescriptorV0TLVWithTotalCollateral, - contractDescriptorV1TLVWithTotalCollateral) + def contractDescriptorTLVWithTotalCollateral + : Gen[(ContractDescriptorTLV, Satoshis)] = { + Gen.oneOf( + contractDescriptorV0TLVWithTotalCollateral, + contractDescriptorV1TLVWithTotalCollateral + ) } def oracleInfoV0TLV(outcomes: Vector[String]): Gen[OracleInfoV0TLV] = { @@ -219,7 +225,9 @@ trait TLVGen { OracleAnnouncementV0TLV.dummyForEventsAndKeys( privKey, rValue, - outcomes.map(EnumOutcome.apply))) + outcomes.map(EnumOutcome.apply) + ) + ) } } @@ -311,25 +319,30 @@ trait TLVGen { } } - def oracleInfoV0TLVWithKeys: Gen[ - (OracleInfoV0TLV, ECPrivateKey, ECPrivateKey)] = { + def oracleInfoV0TLVWithKeys + : Gen[(OracleInfoV0TLV, ECPrivateKey, ECPrivateKey)] = { for { privKey <- CryptoGenerators.privateKey kValue <- CryptoGenerators.privateKey outcomes <- Gen.listOf(StringGenerators.genUTF8String) } yield { - (OracleInfoV0TLV( - OracleAnnouncementV0TLV.dummyForEventsAndKeys( - privKey, - kValue.schnorrNonce, - outcomes.toVector.map(EnumOutcome.apply))), - privKey, - kValue) + ( + OracleInfoV0TLV( + OracleAnnouncementV0TLV.dummyForEventsAndKeys( + privKey, + kValue.schnorrNonce, + outcomes.toVector.map(EnumOutcome.apply) + ) + ), + privKey, + kValue + ) } } - def fundingInputP2WPKHTLV(ignoreSerialIds: Vector[UInt64] = - Vector.empty): Gen[FundingInputV0TLV] = { + def fundingInputP2WPKHTLV( + ignoreSerialIds: Vector[UInt64] = Vector.empty + ): Gen[FundingInputV0TLV] = { for { prevTx <- TransactionGenerators.realisticTransactionWitnessOut prevTxVout <- Gen.choose(0, prevTx.outputs.length - 1) @@ -338,30 +351,35 @@ trait TLVGen { newOutput = prevTx.outputs(prevTxVout).copy(scriptPubKey = spk) newPrevTx = prevTx match { case transaction: NonWitnessTransaction => - BaseTransaction(transaction.version, - transaction.inputs, - transaction.outputs.updated(prevTxVout, newOutput), - transaction.lockTime) + BaseTransaction( + transaction.version, + transaction.inputs, + transaction.outputs.updated(prevTxVout, newOutput), + transaction.lockTime + ) case wtx: WitnessTransaction => wtx.copy(outputs = wtx.outputs.updated(prevTxVout, newOutput)) } } yield { - DLCFundingInputP2WPKHV0(DLCMessage.genSerialId(ignoreSerialIds), - newPrevTx, - UInt32(prevTxVout), - sequence).toTLV + DLCFundingInputP2WPKHV0( + DLCMessage.genSerialId(ignoreSerialIds), + newPrevTx, + UInt32(prevTxVout), + sequence + ).toTLV } } - def fundingInputV0TLV(ignoreSerialIds: Vector[UInt64] = Vector.empty): Gen[ - FundingInputV0TLV] = { + def fundingInputV0TLV( + ignoreSerialIds: Vector[UInt64] = Vector.empty + ): Gen[FundingInputV0TLV] = { fundingInputP2WPKHTLV(ignoreSerialIds) // Soon to be Gen.oneOf } def fundingInputV0TLVs( collateralNeeded: CurrencyUnit, - ignoreSerialIds: Vector[UInt64] = Vector.empty): Gen[ - Vector[FundingInputV0TLV]] = { + ignoreSerialIds: Vector[UInt64] = Vector.empty + ): Gen[Vector[FundingInputV0TLV]] = { for { numInputs <- Gen.choose(0, 5) inputs <- Gen.listOfN(numInputs, fundingInputV0TLV(ignoreSerialIds)) @@ -382,7 +400,8 @@ trait TLVGen { wtx.copy(outputs = newOutputs) case EmptyTransaction => throw new RuntimeException( - "FundingInputV0TLV generator malfunction") + "FundingInputV0TLV generator malfunction" + ) } inputs.toVector :+ input.copy(prevTx = newPrevTx) } else { @@ -419,7 +438,8 @@ trait TLVGen { def dlcOfferTLV: Gen[DLCOfferTLV] = { for { chainHash <- Gen.oneOf( - Networks.knownNetworks.map(_.chainParams.genesisBlock.blockHeader.hash)) + Networks.knownNetworks.map(_.chainParams.genesisBlock.blockHeader.hash) + ) contractInfo <- contractInfoV0TLV fundingPubKey <- CryptoGenerators.publicKey payoutAddress <- AddressGenerator.bitcoinAddress @@ -431,7 +451,8 @@ trait TLVGen { changeSerialId <- NumberGenerator.uInt64 fundOutputSerialId <- NumberGenerator.uInt64.suchThat(_ != changeSerialId) feeRate <- CurrencyUnitGenerator.positiveRealistic.map( - SatoshisPerVirtualByte.apply) + SatoshisPerVirtualByte.apply + ) timeout1 <- NumberGenerator.uInt32s timeout2 <- NumberGenerator.uInt32s } yield { @@ -442,7 +463,7 @@ trait TLVGen { } DLCOfferTLV( - protocolVersionOpt = None, //TODO: Comeback and change this + protocolVersionOpt = None, // TODO: Comeback and change this contractFlags = 0.toByte, chainHash = chainHash, contractInfo = contractInfo, @@ -461,17 +482,19 @@ trait TLVGen { } } - def dlcOfferTLVWithOracleKeys: Gen[ - (DLCOfferTLV, ECPrivateKey, ECPrivateKey)] = { + def dlcOfferTLVWithOracleKeys + : Gen[(DLCOfferTLV, ECPrivateKey, ECPrivateKey)] = { for { offer <- dlcOfferTLV (oracleInfo, oraclePrivKey, oracleRValue) <- oracleInfoV0TLVWithKeys } yield { - (offer.copy(contractInfo = offer.contractInfo - .asInstanceOf[ContractInfoV0TLV] - .copy(oracleInfo = oracleInfo)), - oraclePrivKey, - oracleRValue) + ( + offer.copy(contractInfo = offer.contractInfo + .asInstanceOf[ContractInfoV0TLV] + .copy(oracleInfo = oracleInfo)), + oraclePrivKey, + oracleRValue + ) } } @@ -511,12 +534,14 @@ trait TLVGen { fundingPubKey <- CryptoGenerators.publicKey payoutAddress <- AddressGenerator.bitcoinAddress payoutSerialId <- NumberGenerator.uInt64.suchThat( - _ != offer.payoutSerialId) + _ != offer.payoutSerialId + ) acceptCollateral = (contractInfo.totalCollateral - offer.offererCollateralSatoshis).satoshis.toLong fundingInputs <- fundingInputV0TLVs( Satoshis(acceptCollateral), - offer.fundingInputs.map(_.inputSerialId)) + offer.fundingInputs.map(_.inputSerialId) + ) changeAddress <- AddressGenerator.bitcoinAddress changeSerialId <- NumberGenerator.uInt64.suchThat(num => num != offer.changeSerialId && num != offer.fundOutputSerialId) @@ -546,8 +571,8 @@ trait TLVGen { } yield (offer, accept) } - def dlcOfferTLVAcceptTLVWithOracleKeys: Gen[ - (DLCOfferTLV, DLCAcceptTLV, ECPrivateKey, ECPrivateKey)] = { + def dlcOfferTLVAcceptTLVWithOracleKeys + : Gen[(DLCOfferTLV, DLCAcceptTLV, ECPrivateKey, ECPrivateKey)] = { for { (offer, privKey, kVal) <- dlcOfferTLVWithOracleKeys accept <- dlcAcceptTLV(offer) @@ -575,8 +600,10 @@ trait TLVGen { } yield { val deserOffer = DLCOffer.fromTLV(offer) val builder = - DLCTxBuilder(deserOffer, - DLCAccept.fromTLV(accept, deserOffer).withoutSigs) + DLCTxBuilder( + deserOffer, + DLCAccept.fromTLV(accept, deserOffer).withoutSigs + ) val fundingTx = builder.buildFundingTx val contractId = fundingTx.txIdBE.bytes.xor(accept.tempContractId.bytes) @@ -584,8 +611,8 @@ trait TLVGen { } } - def dlcOfferTLVAcceptTLVSignTLV: Gen[ - (DLCOfferTLV, DLCAcceptTLV, DLCSignTLV)] = { + def dlcOfferTLVAcceptTLVSignTLV + : Gen[(DLCOfferTLV, DLCAcceptTLV, DLCSignTLV)] = { for { (offer, accept) <- dlcOfferTLVAcceptTLV sign <- dlcSignTLV(offer, accept) @@ -593,7 +620,8 @@ trait TLVGen { } def dlcOfferTLVAcceptTLVSignTLVWithOralceKeys: Gen[ - (DLCOfferTLV, DLCAcceptTLV, DLCSignTLV, ECPrivateKey, ECPrivateKey)] = { + (DLCOfferTLV, DLCAcceptTLV, DLCSignTLV, ECPrivateKey, ECPrivateKey) + ] = { for { (offer, accept, privKey, kValue) <- dlcOfferTLVAcceptTLVWithOracleKeys sign <- dlcSignTLV(offer, accept) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/TransactionGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/TransactionGenerators.scala index 6e488f4676..70d3a9299c 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/TransactionGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/TransactionGenerators.scala @@ -17,7 +17,9 @@ import scala.annotation.tailrec object TransactionGenerators { - /** Responsible for generating [[org.bitcoins.core.protocol.transaction.TransactionOutPoint TransactionOutPoint]] */ + /** Responsible for generating + * [[org.bitcoins.core.protocol.transaction.TransactionOutPoint TransactionOutPoint]] + */ def outPoint: Gen[TransactionOutPoint] = for { txId <- CryptoGenerators.doubleSha256Digest @@ -30,7 +32,9 @@ object TransactionGenerators { satoshis <- CurrencyUnitGenerator.positiveRealistic } yield TransactionOutput(satoshis, spk) - /** Generates a random [[org.bitcoins.core.protocol.transaction.TransactionOutput TransactionOutput]] */ + /** Generates a random + * [[org.bitcoins.core.protocol.transaction.TransactionOutput TransactionOutput]] + */ def output: Gen[TransactionOutput] = for { satoshis <- CurrencyUnitGenerator.satoshis @@ -39,8 +43,8 @@ object TransactionGenerators { def outputs = Gen.listOf(output) - /** Outputs that only have a positive amount of satoshis, techinically the bitcoin protocol allows you - * to have negative value outputs + /** Outputs that only have a positive amount of satoshis, techinically the + * bitcoin protocol allows you to have negative value outputs */ def realisticOutput: Gen[TransactionOutput] = CurrencyUnitGenerator.positiveRealistic.flatMap { amt => @@ -65,7 +69,9 @@ object TransactionGenerators { def smallOutputsTo(spk: ScriptPubKey): Gen[Seq[TransactionOutput]] = Gen.choose(1, 5).flatMap(i => Gen.listOfN(i, outputTo(spk))) - /** Generates a small list of [[org.bitcoins.core.protocol.transaction.TransactionOutput TransactionOutput]] */ + /** Generates a small list of + * [[org.bitcoins.core.protocol.transaction.TransactionOutput TransactionOutput]] + */ def smallOutputs: Gen[Seq[TransactionOutput]] = Gen.choose(0, 5).flatMap(i => Gen.listOfN(i, output)) @@ -75,7 +81,8 @@ object TransactionGenerators { def loop( remaining: Int, remainingAmount: CurrencyUnit, - accum: Seq[CurrencyUnit]): Seq[CurrencyUnit] = { + accum: Seq[CurrencyUnit] + ): Seq[CurrencyUnit] = { if (remaining <= 0) { accum } else { @@ -100,11 +107,13 @@ object TransactionGenerators { } } - /** Creates a small sequence of outputs whose total sum is <= totalAmount - * @return Sequence of outputs and corresponding Redeem Scripts + /** Creates a small sequence of outputs whose total sum is <= totalAmount + * @return + * Sequence of outputs and corresponding Redeem Scripts */ - def smallP2SHOutputs(totalAmount: CurrencyUnit): Gen[ - Seq[(TransactionOutput, ScriptPubKey)]] = { + def smallP2SHOutputs( + totalAmount: CurrencyUnit + ): Gen[Seq[(TransactionOutput, ScriptPubKey)]] = { val amts = genAmounts(totalAmount) val spks = Gen.listOfN(amts.size, ScriptGenerators.p2shScriptPubKey) spks.flatMap { s => @@ -114,8 +123,9 @@ object TransactionGenerators { } } - def smallP2WSHOutputs(totalAmount: CurrencyUnit): Gen[ - Seq[(TransactionOutput, ScriptPubKey)]] = { + def smallP2WSHOutputs( + totalAmount: CurrencyUnit + ): Gen[Seq[(TransactionOutput, ScriptPubKey)]] = { val amts = genAmounts(totalAmount) val spks = Gen.listOfN(amts.size, ScriptGenerators.p2wshSPKV0) spks.flatMap { s => @@ -125,7 +135,9 @@ object TransactionGenerators { } } - /** Generates a random [[org.bitcoins.core.protocol.transaction.TransactionInput TransactionInput]] */ + /** Generates a random + * [[org.bitcoins.core.protocol.transaction.TransactionInput TransactionInput]] + */ def input: Gen[TransactionInput] = for { outPoint <- outPoint @@ -134,14 +146,16 @@ object TransactionGenerators { randomNum <- Gen.choose(0, 10) } yield { if (randomNum == 0) { - //gives us a coinbase input + // gives us a coinbase input CoinbaseInput(scriptSig, sequenceNumber) } else TransactionInput(outPoint, scriptSig, sequenceNumber) } def inputs: Gen[List[TransactionInput]] = Gen.nonEmptyListOf(input) - /** Generates a small list of [[org.bitcoins.core.protocol.transaction.TransactionInput TransactionInput]] */ + /** Generates a small list of + * [[org.bitcoins.core.protocol.transaction.TransactionInput TransactionInput]] + */ def smallInputs: Gen[Seq[TransactionInput]] = Gen.choose(1, 5).flatMap(i => Gen.listOfN(i, input)) @@ -165,14 +179,18 @@ object TransactionGenerators { } yield OutputReference(outPoint, output) } - /** Generates an arbitrary [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] - * This transaction's [[org.bitcoins.core.protocol.transaction.TransactionInput TransactionInput]]s + /** Generates an arbitrary + * [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] This + * transaction's + * [[org.bitcoins.core.protocol.transaction.TransactionInput TransactionInput]]s * will not evaluate to true inside of the * [[org.bitcoins.core.script.interpreter.ScriptInterpreter ScriptInterpreter]] */ def transactions: Gen[Seq[Transaction]] = Gen.listOf(transaction) - /** Generates a small list of [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] */ + /** Generates a small list of + * [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] + */ def smallTransactions: Gen[Seq[Transaction]] = Gen.choose(0, 10).flatMap(i => Gen.listOfN(i, transaction)) @@ -187,8 +205,10 @@ object TransactionGenerators { Gen.oneOf(realisticBaseTransaction, realisiticWitnessTransaction) def realisticTransactionWitnessOut: Gen[Transaction] = - Gen.oneOf(realisticBaseTransactionWitnessOut, - realisiticWitnessTransactionWitnessOut) + Gen.oneOf( + realisticBaseTransactionWitnessOut, + realisiticWitnessTransactionWitnessOut + ) /** Generates a transaction where at least one output pays to the given SPK */ def transactionTo(spk: ScriptPubKey): Gen[Transaction] = @@ -224,7 +244,9 @@ object TransactionGenerators { } yield BaseTransaction(version, is, os, lockTime) } - /** Generates a legacy transaction with at least one output paying to the given SPK */ + /** Generates a legacy transaction with at least one output paying to the + * given SPK + */ def baseTransactionTo(spk: ScriptPubKey): Gen[BaseTransaction] = for { version <- NumberGenerator.int32s @@ -235,17 +257,18 @@ object TransactionGenerators { /** To avoid duplicating logic */ private def witnessTxHelper( - outputs: Seq[TransactionOutput]): Gen[WitnessTransaction] = { + outputs: Seq[TransactionOutput] + ): Gen[WitnessTransaction] = { for { version <- NumberGenerator.int32s - //we cannot have zero witnesses on a WitnessTx - //https://github.com/bitcoin/bitcoin/blob/e8cfe1ee2d01c493b758a67ad14707dca15792ea/src/primitives/transaction.h#L276-L281 + // we cannot have zero witnesses on a WitnessTx + // https://github.com/bitcoin/bitcoin/blob/e8cfe1ee2d01c493b758a67ad14707dca15792ea/src/primitives/transaction.h#L276-L281 is <- smallInputsNonEmpty lockTime <- NumberGenerator.uInt32s - //we have to have atleast one NON `EmptyScriptWitness` for a tx to be a valid WitnessTransaction, otherwise we - //revert to using the `BaseTransaction` serialization format - //notice we use the old serialization format if all witnesses are empty - //https://github.com/bitcoin/bitcoin/blob/e8cfe1ee2d01c493b758a67ad14707dca15792ea/src/primitives/transaction.h#L276-L281 + // we have to have atleast one NON `EmptyScriptWitness` for a tx to be a valid WitnessTransaction, otherwise we + // revert to using the `BaseTransaction` serialization format + // notice we use the old serialization format if all witnesses are empty + // https://github.com/bitcoin/bitcoin/blob/e8cfe1ee2d01c493b758a67ad14707dca15792ea/src/primitives/transaction.h#L276-L281 witness <- WitnessGenerators .transactionWitness(is.size) @@ -253,7 +276,9 @@ object TransactionGenerators { } yield WitnessTransaction(version, is, outputs, lockTime, witness) } - /** Generates a random [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] */ + /** Generates a random + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] + */ def witnessTransaction: Gen[WitnessTransaction] = for { os <- smallOutputs @@ -280,10 +305,13 @@ object TransactionGenerators { } yield tx } - /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates a - * [[org.bitcoins.core.protocol.script.P2PKScriptPubKey P2PKScriptPubKey]] from that private key - * Finally creates a [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] - * that spends the [[org.bitcoins.core.protocol.script.P2PKScriptPubKey P2PKScriptPubKey]] correctly + /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates + * a [[org.bitcoins.core.protocol.script.P2PKScriptPubKey P2PKScriptPubKey]] + * from that private key Finally creates a + * [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that + * spends the + * [[org.bitcoins.core.protocol.script.P2PKScriptPubKey P2PKScriptPubKey]] + * correctly */ def signedP2PKTransaction: Gen[(BaseTxSigComponent, ECPrivateKey)] = for { @@ -297,13 +325,17 @@ object TransactionGenerators { signedTx, inputIndex, output, - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) } yield (signedTxSignatureComponent, privateKey) - /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates a - * [[org.bitcoins.core.protocol.script.P2PKScriptPubKey P2PKHScriptPubKey]] from that private key - * Finally creates [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that spends the - * [[org.bitcoins.core.protocol.script.P2PKScriptPubKey P2PKHScriptPubKey]] correctly + /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates + * a [[org.bitcoins.core.protocol.script.P2PKScriptPubKey P2PKHScriptPubKey]] + * from that private key Finally creates + * [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that + * spends the + * [[org.bitcoins.core.protocol.script.P2PKScriptPubKey P2PKHScriptPubKey]] + * correctly */ def signedP2PKHTransaction: Gen[(BaseTxSigComponent, ECPrivateKey)] = for { @@ -317,13 +349,18 @@ object TransactionGenerators { signedTx, inputIndex, output, - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) } yield (signedTxSignatureComponent, privateKey) - /** Creates a sequence of [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates a - * [[org.bitcoins.core.protocol.script.MultiSignatureScriptPubKey MultiSignatureScriptPubKey]] from those - * private keys. Finally creates a [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that - * spends the [[org.bitcoins.core.protocol.script.MultiSignatureScriptPubKey MultiSignatureScriptPubKey]] correctly + /** Creates a sequence of [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], + * then creates a + * [[org.bitcoins.core.protocol.script.MultiSignatureScriptPubKey MultiSignatureScriptPubKey]] + * from those private keys. Finally creates a + * [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that + * spends the + * [[org.bitcoins.core.protocol.script.MultiSignatureScriptPubKey MultiSignatureScriptPubKey]] + * correctly */ def signedMultiSigTransaction: Gen[(BaseTxSigComponent, Seq[ECPrivateKey])] = for { @@ -337,11 +374,13 @@ object TransactionGenerators { signedTx, inputIndex, output, - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) } yield (signedTxSignatureComponent, privateKeys) /** Creates a transaction which contains a - * [[org.bitcoins.core.protocol.script.P2SHScriptSignature P2SHScriptSignature]] that correctly spends a + * [[org.bitcoins.core.protocol.script.P2SHScriptSignature P2SHScriptSignature]] + * that correctly spends a * [[org.bitcoins.core.protocol.script.P2SHScriptPubKey P2SHScriptPubKey]] */ def signedP2SHTransaction: Gen[(BaseTxSigComponent, Seq[ECPrivateKey])] = @@ -349,28 +388,37 @@ object TransactionGenerators { (signedScriptSig, scriptPubKey, privateKey) <- ScriptGenerators.signedP2SHScriptSignature (creditingTx, outputIndex) = buildCreditingTransaction( - signedScriptSig.redeemScript) + signedScriptSig.redeemScript + ) (signedTx, inputIndex) = buildSpendingTransaction(creditingTx, signedScriptSig, outputIndex) - output = TransactionOutput(creditingTx.outputs(outputIndex.toInt).value, - scriptPubKey) + output = TransactionOutput( + creditingTx.outputs(outputIndex.toInt).value, + scriptPubKey + ) signedTxSignatureComponent = BaseTxSigComponent( signedTx, inputIndex, output, - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) } yield (signedTxSignatureComponent, privateKey) - /** Generates a validly constructed CLTV transaction, which has a 50/50 chance of being spendable or unspendable. */ + /** Generates a validly constructed CLTV transaction, which has a 50/50 chance + * of being spendable or unspendable. + */ def randomCLTVTransaction: Gen[(BaseTxSigComponent, Seq[ECPrivateKey])] = { Gen.oneOf(unspendableCLTVTransaction, spendableCLTVTransaction) } - /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates a - * [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]] from that private key - * Finally creates a [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that CANNNOT spend the - * [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]] because the LockTime requirement - * is not satisfied (i.e. the transaction's lockTime has not surpassed the CLTV value in the + /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates + * a [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]] + * from that private key Finally creates a + * [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that + * CANNNOT spend the + * [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]] + * because the LockTime requirement is not satisfied (i.e. the transaction's + * lockTime has not surpassed the CLTV value in the * [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]]) * * @return @@ -382,17 +430,21 @@ object TransactionGenerators { (scriptSig, scriptPubKey, privKeys) <- ScriptGenerators .signedCLTVScriptSignature(cltvLockTime, txLockTime, sequence) - unspendable = lockTimeTxHelper(scriptSig, - scriptPubKey, - privKeys, - sequence, - Some(txLockTime)) + unspendable = lockTimeTxHelper( + scriptSig, + scriptPubKey, + privKeys, + sequence, + Some(txLockTime) + ) } yield unspendable - /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates a - * [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]] from that private key. - * Finally creates a [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that can successfully - * spend the [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]] + /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates + * a [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]] + * from that private key. Finally creates a + * [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that + * can successfully spend the + * [[org.bitcoins.core.protocol.script.CLTVScriptPubKey CLTVScriptPubKey]] */ def spendableCLTVTransaction: Gen[(BaseTxSigComponent, Seq[ECPrivateKey])] = for { @@ -401,17 +453,21 @@ object TransactionGenerators { (scriptSig, scriptPubKey, privKeys) <- ScriptGenerators .signedCLTVScriptSignature(cltvLockTime, txLockTime, sequence) - spendable = lockTimeTxHelper(scriptSig, - scriptPubKey, - privKeys, - sequence, - Some(txLockTime)) + spendable = lockTimeTxHelper( + scriptSig, + scriptPubKey, + privKeys, + sequence, + Some(txLockTime) + ) } yield spendable - /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates a - * [[org.bitcoins.core.protocol.script.CSVScriptPubKey CSVScriptPubKey]] from that private key. - * Finally creates a [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that can - * successfully spend the [[org.bitcoins.core.protocol.script.CSVScriptPubKey CSVScriptPubKey]] + /** Creates a [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]], then creates + * a [[org.bitcoins.core.protocol.script.CSVScriptPubKey CSVScriptPubKey]] + * from that private key. Finally creates a + * [[org.bitcoins.core.protocol.transaction.Transaction Transaction]] that + * can successfully spend the + * [[org.bitcoins.core.protocol.script.CSVScriptPubKey CSVScriptPubKey]] */ def spendableCSVTransaction: Gen[(BaseTxSigComponent, Seq[ECPrivateKey])] = for { @@ -428,19 +484,23 @@ object TransactionGenerators { def csvTransaction( csvScriptNum: ScriptNumber, - sequence: UInt32): Gen[(BaseTxSigComponent, Seq[ECPrivateKey])] = + sequence: UInt32 + ): Gen[(BaseTxSigComponent, Seq[ECPrivateKey])] = for { (signedScriptSig, csvScriptPubKey, privateKeys) <- ScriptGenerators .signedCSVScriptSignature(csvScriptNum, sequence) - } yield lockTimeTxHelper(signedScriptSig, - csvScriptPubKey, - privateKeys, - sequence, - None) + } yield lockTimeTxHelper( + signedScriptSig, + csvScriptPubKey, + privateKeys, + sequence, + None + ) - /** Generates a [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] that has all of - * it's inputs signed correctly + /** Generates a + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] + * that has all of it's inputs signed correctly */ def signedP2WPKHTransaction: Gen[(WitnessTxSigComponent, Seq[ECPrivateKey])] = for { @@ -448,36 +508,40 @@ object TransactionGenerators { WitnessGenerators.signedP2WPKHTransactionWitness } yield (wBaseTxSigComponent, privKeys) - /** Generates a [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] that has an input - * spends a raw P2WSH [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] + /** Generates a + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] + * that has an input spends a raw P2WSH + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] */ - def signedP2WSHP2PKTransaction: Gen[ - (WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = + def signedP2WSHP2PKTransaction + : Gen[(WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for { (_, wBaseTxSigComponent, privKeys) <- WitnessGenerators.signedP2WSHP2PKTransactionWitness } yield (wBaseTxSigComponent, privKeys) - /** Generates a [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] that has an - * input spends a raw P2WSH [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] + /** Generates a + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] + * that has an input spends a raw P2WSH + * [[org.bitcoins.core.protocol.script.WitnessScriptPubKey WitnessScriptPubKey]] */ - def signedP2WSHP2PKHTransaction: Gen[ - (WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = + def signedP2WSHP2PKHTransaction + : Gen[(WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for { (_, wBaseTxSigComponent, privKeys) <- WitnessGenerators.signedP2WSHP2PKHTransactionWitness } yield (wBaseTxSigComponent, privKeys) - def signedP2WSHMultiSigTransaction: Gen[ - (WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = + def signedP2WSHMultiSigTransaction + : Gen[(WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for { (_, wBaseTxSigComponent, privKeys) <- WitnessGenerators.signedP2WSHMultiSigTransactionWitness } yield (wBaseTxSigComponent, privKeys) /** Creates a signed P2SH(P2WPKH) transaction */ - def signedP2SHP2WPKHTransaction: Gen[ - (WitnessTxSigComponent, Seq[ECPrivateKey])] = + def signedP2SHP2WPKHTransaction + : Gen[(WitnessTxSigComponent, Seq[ECPrivateKey])] = for { (signedScriptSig, scriptPubKey, privKeys, witness, amount) <- ScriptGenerators.signedP2SHP2WPKHScriptSignature @@ -488,36 +552,44 @@ object TransactionGenerators { creditingTx, signedScriptSig, outputIndex, - witness) - output = TransactionOutput(creditingTx.outputs(outputIndex.toInt).value, - scriptPubKey) + witness + ) + output = TransactionOutput( + creditingTx.outputs(outputIndex.toInt).value, + scriptPubKey + ) signedTxSignatureComponent = WitnessTxSigComponent( signedTx, inputIndex, output, PreviousOutputMap.empty, - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) } yield (signedTxSignatureComponent, privKeys) - def signedP2WSHTransaction: Gen[ - (WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = { - Gen.oneOf(signedP2WSHP2PKTransaction, - signedP2WSHP2PKHTransaction, - signedP2WSHMultiSigTransaction) + def signedP2WSHTransaction + : Gen[(WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = { + Gen.oneOf( + signedP2WSHP2PKTransaction, + signedP2WSHP2PKHTransaction, + signedP2WSHMultiSigTransaction + ) } /** Creates a signed P2SH(P2WSH) transaction */ - def signedP2SHP2WSHTransaction: Gen[ - (WitnessTxSigComponent, Seq[ECPrivateKey])] = + def signedP2SHP2WSHTransaction + : Gen[(WitnessTxSigComponent, Seq[ECPrivateKey])] = for { (witness, wBaseTxSigComponent, privKeys) <- WitnessGenerators.signedP2WSHTransactionWitness p2shScriptPubKey = P2SHScriptPubKey(wBaseTxSigComponent.scriptPubKey) p2shScriptSig = P2SHScriptSignature( - wBaseTxSigComponent.scriptPubKey.asInstanceOf[WitnessScriptPubKey]) + wBaseTxSigComponent.scriptPubKey.asInstanceOf[WitnessScriptPubKey] + ) (creditingTx, outputIndex) = buildCreditingTransaction( p2shScriptSig.redeemScript, - wBaseTxSigComponent.amount) + wBaseTxSigComponent.amount + ) sequence = wBaseTxSigComponent.transaction .inputs(wBaseTxSigComponent.inputIndex.toInt) @@ -530,19 +602,25 @@ object TransactionGenerators { outputIndex, locktime, sequence, - witness) - output = TransactionOutput(creditingTx.outputs(outputIndex.toInt).value, - p2shScriptPubKey) + witness + ) + output = TransactionOutput( + creditingTx.outputs(outputIndex.toInt).value, + p2shScriptPubKey + ) signedTxSignatureComponent = WitnessTxSigComponent( signedTx, inputIndex, output, PreviousOutputMap.empty, - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) } yield (signedTxSignatureComponent, privKeys) /** Builds a spending transaction according to bitcoin core - * @return the built spending transaction and the input index for the script signature + * @return + * the built spending transaction and the input index for the script + * signature */ def buildSpendingTransaction( version: Int32, @@ -550,15 +628,18 @@ object TransactionGenerators { scriptSignature: ScriptSignature, outputIndex: UInt32, locktime: UInt32, - sequence: UInt32): (Transaction, UInt32) = { + sequence: UInt32 + ): (Transaction, UInt32) = { val output = TransactionOutput(CurrencyUnits.zero, EmptyScriptPubKey) - buildSpendingTransaction(version, - creditingTx, - scriptSignature, - outputIndex, - locktime, - sequence, - Seq(output)) + buildSpendingTransaction( + version, + creditingTx, + scriptSignature, + outputIndex, + locktime, + sequence, + Seq(output) + ) } def buildSpendingTransaction( @@ -568,7 +649,8 @@ object TransactionGenerators { outputIndex: UInt32, locktime: UInt32, sequence: UInt32, - outputs: Seq[TransactionOutput]): (Transaction, UInt32) = { + outputs: Seq[TransactionOutput] + ): (Transaction, UInt32) = { val os = if (outputs.isEmpty) { Seq(TransactionOutput(CurrencyUnits.zero, EmptyScriptPubKey)) } else { @@ -580,36 +662,48 @@ object TransactionGenerators { (tx, UInt32.zero) } - /** Builds a spending transaction according to bitcoin core with max sequence and a locktime of zero. - * @return the built spending transaction and the input index for the script signature + /** Builds a spending transaction according to bitcoin core with max sequence + * and a locktime of zero. + * @return + * the built spending transaction and the input index for the script + * signature */ def buildSpendingTransaction( creditingTx: Transaction, scriptSignature: ScriptSignature, - outputIndex: UInt32): (Transaction, UInt32) = { - buildSpendingTransaction(TransactionConstants.version, - creditingTx, - scriptSignature, - outputIndex, - TransactionConstants.lockTime, - TransactionConstants.sequence) + outputIndex: UInt32 + ): (Transaction, UInt32) = { + buildSpendingTransaction( + TransactionConstants.version, + creditingTx, + scriptSignature, + outputIndex, + TransactionConstants.lockTime, + TransactionConstants.sequence + ) } - /** Builds a spending [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] with the given parameters */ + /** Builds a spending + * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] + * with the given parameters + */ def buildSpendingTransaction( creditingTx: Transaction, scriptSignature: ScriptSignature, outputIndex: UInt32, locktime: UInt32, sequence: UInt32, - witness: TransactionWitness): (WitnessTransaction, UInt32) = { - buildSpendingTransaction(TransactionConstants.version, - creditingTx, - scriptSignature, - outputIndex, - locktime, - sequence, - witness) + witness: TransactionWitness + ): (WitnessTransaction, UInt32) = { + buildSpendingTransaction( + TransactionConstants.version, + creditingTx, + scriptSignature, + outputIndex, + locktime, + sequence, + witness + ) } def buildSpendingTransaction( @@ -619,17 +713,20 @@ object TransactionGenerators { outputIndex: UInt32, locktime: UInt32, sequence: UInt32, - witness: TransactionWitness): (WitnessTransaction, UInt32) = { + witness: TransactionWitness + ): (WitnessTransaction, UInt32) = { val outputs = dummyOutputs - buildSpendingTransaction(version, - creditingTx, - scriptSignature, - outputIndex, - locktime, - sequence, - witness, - outputs) + buildSpendingTransaction( + version, + creditingTx, + scriptSignature, + outputIndex, + locktime, + sequence, + witness, + outputs + ) } def dummyOutputs: Seq[TransactionOutput] = @@ -643,23 +740,29 @@ object TransactionGenerators { locktime: UInt32, sequence: UInt32, witness: TransactionWitness, - outputs: Seq[TransactionOutput]): (WitnessTransaction, UInt32) = { + outputs: Seq[TransactionOutput] + ): (WitnessTransaction, UInt32) = { val outpoint = TransactionOutPoint(creditingTx.txId, outputIndex) val input = TransactionInput(outpoint, scriptSignature, sequence) - (WitnessTransaction(version, Seq(input), outputs, locktime, witness), - UInt32.zero) + ( + WitnessTransaction(version, Seq(input), outputs, locktime, witness), + UInt32.zero + ) } def buildSpendingTransaction( creditingTx: Transaction, scriptSignature: ScriptSignature, outputIndex: UInt32, - witness: TransactionWitness): (WitnessTransaction, UInt32) = { - buildSpendingTransaction(TransactionConstants.version, - creditingTx, - scriptSignature, - outputIndex, - witness) + witness: TransactionWitness + ): (WitnessTransaction, UInt32) = { + buildSpendingTransaction( + TransactionConstants.version, + creditingTx, + scriptSignature, + outputIndex, + witness + ) } def buildSpendingTransaction( @@ -667,52 +770,63 @@ object TransactionGenerators { creditingTx: Transaction, scriptSignature: ScriptSignature, outputIndex: UInt32, - witness: TransactionWitness): (WitnessTransaction, UInt32) = { + witness: TransactionWitness + ): (WitnessTransaction, UInt32) = { val locktime = TransactionConstants.lockTime val sequence = TransactionConstants.sequence - buildSpendingTransaction(version, - creditingTx, - scriptSignature, - outputIndex, - locktime, - sequence, - witness) + buildSpendingTransaction( + version, + creditingTx, + scriptSignature, + outputIndex, + locktime, + sequence, + witness + ) } /** Mimics this test utility found in bitcoin core * https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/test/script_tests.cpp#L57 - * @return the transaction and the output index of the scriptPubKey + * @return + * the transaction and the output index of the scriptPubKey */ def buildCreditingTransaction( - scriptPubKey: ScriptPubKey): (Transaction, UInt32) = { - //this needs to be all zeros according to these 3 lines in bitcoin core - //https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/test/script_tests.cpp#L64 - //https://github.com/bitcoin/bitcoin/blob/80d1f2e48364f05b2cdf44239b3a1faa0277e58e/src/primitives/transaction.h#L32 - //https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/uint256.h#L40 + scriptPubKey: ScriptPubKey + ): (Transaction, UInt32) = { + // this needs to be all zeros according to these 3 lines in bitcoin core + // https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/test/script_tests.cpp#L64 + // https://github.com/bitcoin/bitcoin/blob/80d1f2e48364f05b2cdf44239b3a1faa0277e58e/src/primitives/transaction.h#L32 + // https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/uint256.h#L40 buildCreditingTransaction(TransactionConstants.version, scriptPubKey) } def buildCreditingTransaction( scriptPubKey: ScriptPubKey, - amount: CurrencyUnit): (Transaction, UInt32) = { - buildCreditingTransaction(TransactionConstants.version, - scriptPubKey, - amount) + amount: CurrencyUnit + ): (Transaction, UInt32) = { + buildCreditingTransaction( + TransactionConstants.version, + scriptPubKey, + amount + ) } /** Builds a crediting transaction with a transaction version parameter. - * Example: useful for creating transactions with scripts containing OP_CHECKSEQUENCEVERIFY. + * Example: useful for creating transactions with scripts containing + * OP_CHECKSEQUENCEVERIFY. * @return */ def buildCreditingTransaction( version: Int32, - scriptPubKey: ScriptPubKey): (Transaction, UInt32) = { + scriptPubKey: ScriptPubKey + ): (Transaction, UInt32) = { buildCreditingTransaction(version, scriptPubKey, CurrencyUnits.zero) } def buildCreditingTransaction( version: Int32, - output: TransactionOutput): (Transaction, UInt32) = { + output: TransactionOutput + ): (Transaction, UInt32) = { val outpoint = EmptyTransactionOutPoint buildCreditingTransaction(version, output, outpoint) } @@ -720,21 +834,25 @@ object TransactionGenerators { def buildCreditingTransaction( version: Int32, scriptPubKey: ScriptPubKey, - amount: CurrencyUnit): (Transaction, UInt32) = { + amount: CurrencyUnit + ): (Transaction, UInt32) = { buildCreditingTransaction(version, TransactionOutput(amount, scriptPubKey)) } def buildCreditingTransaction( version: Int32, output: TransactionOutput, - outpoint: TransactionOutPoint): (Transaction, UInt32) = { + outpoint: TransactionOutPoint + ): (Transaction, UInt32) = { val scriptSignature = ScriptSignature("0000") val input = TransactionInput(outpoint, scriptSignature, TransactionConstants.sequence) - val tx = BaseTransaction(version, - Seq(input), - Seq(output), - TransactionConstants.lockTime) + val tx = BaseTransaction( + version, + Seq(input), + Seq(output), + TransactionConstants.lockTime + ) (tx, UInt32.zero) } @@ -743,65 +861,85 @@ object TransactionGenerators { lock: LockTimeScriptPubKey, privKeys: Seq[ECPrivateKey], sequence: UInt32, - lockTime: Option[UInt32]): (BaseTxSigComponent, Seq[ECPrivateKey]) = { + lockTime: Option[UInt32] + ): (BaseTxSigComponent, Seq[ECPrivateKey]) = { val (creditingTx, outputIndex) = buildCreditingTransaction(TransactionConstants.validLockVersion, lock) - //Transaction version must not be less than 2 for a CSV transaction + // Transaction version must not be less than 2 for a CSV transaction val (signedSpendingTx, inputIndex) = buildSpendingTransaction( TransactionConstants.validLockVersion, creditingTx, signedScriptSig, outputIndex, lockTime.getOrElse(TransactionConstants.lockTime), - sequence) + sequence + ) val output = creditingTx.outputs(outputIndex.toInt) val baseTxSigComponent = BaseTxSigComponent( signedSpendingTx, inputIndex, output, - Policy.standardScriptVerifyFlags) + Policy.standardScriptVerifyFlags + ) (baseTxSigComponent, privKeys) } - /** Determines if the transaction input's sequence value and CSV script sequence value are of the same type - * (i.e. determines whether both are a timestamp or block-height) + /** Determines if the transaction input's sequence value and CSV script + * sequence value are of the same type (i.e. determines whether both are a + * timestamp or block-height) */ private def csvLockTimesOfSameType( - sequenceNumbers: (ScriptNumber, UInt32)): Boolean = { - LockTimeInterpreter.isCSVLockByRelativeLockTime(sequenceNumbers._1, - sequenceNumbers._2) || - LockTimeInterpreter.isCSVLockByBlockHeight(sequenceNumbers._1, - sequenceNumbers._2) + sequenceNumbers: (ScriptNumber, UInt32) + ): Boolean = { + LockTimeInterpreter.isCSVLockByRelativeLockTime( + sequenceNumbers._1, + sequenceNumbers._2 + ) || + LockTimeInterpreter.isCSVLockByBlockHeight( + sequenceNumbers._1, + sequenceNumbers._2 + ) } - /** Generates a pair of CSV values: a transaction input sequence, and a CSV script sequence value, such that the txInput - * sequence mask is always greater than the script sequence mask (i.e. generates values for a validly constructed and spendable CSV transaction) + /** Generates a pair of CSV values: a transaction input sequence, and a CSV + * script sequence value, such that the txInput sequence mask is always + * greater than the script sequence mask (i.e. generates values for a validly + * constructed and spendable CSV transaction) */ def spendableCSVValues: Gen[(ScriptNumber, UInt32)] = { - Gen.oneOf(validScriptNumberAndSequenceForBlockHeight, - validScriptNumberAndSequenceForRelativeLockTime) + Gen.oneOf( + validScriptNumberAndSequenceForBlockHeight, + validScriptNumberAndSequenceForRelativeLockTime + ) } - /** To indicate that we should evaulate a [[org.bitcoins.core.script.locktime.OP_CHECKSEQUENCEVERIFY OP_CSV]] - * operation based on - * blockheight we need 1 << 22 bit turned off. See BIP68 for more details + /** To indicate that we should evaulate a + * [[org.bitcoins.core.script.locktime.OP_CHECKSEQUENCEVERIFY OP_CSV]] + * operation based on blockheight we need 1 << 22 bit turned off. See BIP68 + * for more details */ private def lockByBlockHeightBitSet: UInt32 = UInt32("ffbfffff") - /** Generates a [[org.bitcoins.core.number.UInt32 UInt32]] s.t. the block height bit is set according to BIP68 */ + /** Generates a [[org.bitcoins.core.number.UInt32 UInt32]] s.t. the block + * height bit is set according to BIP68 + */ private def sequenceForBlockHeight: Gen[UInt32] = validCSVSequence.map { n => val result: UInt32 = n & lockByBlockHeightBitSet - require(LockTimeInterpreter.isCSVLockByBlockHeight(result), - "Block height locktime bit was not set: " + result) + require( + LockTimeInterpreter.isCSVLockByBlockHeight(result), + "Block height locktime bit was not set: " + result + ) result } - /** Generates a [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and - * [[org.bitcoins.core.number.UInt32 UInt32]] s.t. the pair can be spent by an OP_CSV operation + /** Generates a + * [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and + * [[org.bitcoins.core.number.UInt32 UInt32]] s.t. the pair can be spent by + * an OP_CSV operation */ - private def validScriptNumberAndSequenceForBlockHeight: Gen[ - (ScriptNumber, UInt32)] = { + private def validScriptNumberAndSequenceForBlockHeight + : Gen[(ScriptNumber, UInt32)] = { sequenceForBlockHeight.flatMap { s => val seqMasked = TransactionConstants.sequenceLockTimeMask val validScriptNums = s & seqMasked @@ -814,26 +952,33 @@ object TransactionGenerators { } } - /** Generates a [[org.bitcoins.core.number.UInt32 UInt32]] with the locktime bit set according to BIP68 */ + /** Generates a [[org.bitcoins.core.number.UInt32 UInt32]] with the locktime + * bit set according to BIP68 + */ private def sequenceForRelativeLockTime: Gen[UInt32] = validCSVSequence.map { n => val result = n | TransactionConstants.sequenceLockTimeTypeFlag - require(LockTimeInterpreter.isCSVLockByRelativeLockTime(result), - "Relative locktime bit was not set: " + result) + require( + LockTimeInterpreter.isCSVLockByRelativeLockTime(result), + "Relative locktime bit was not set: " + result + ) result } - /** Generates a valid [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and - * [[org.bitcoins.core.number.UInt32 UInt32]] s.t. the pair will evaluate to true by a OP_CSV operation + /** Generates a valid + * [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and + * [[org.bitcoins.core.number.UInt32 UInt32]] s.t. the pair will evaluate to + * true by a OP_CSV operation */ - private def validScriptNumberAndSequenceForRelativeLockTime: Gen[ - (ScriptNumber, UInt32)] = { + private def validScriptNumberAndSequenceForRelativeLockTime + : Gen[(ScriptNumber, UInt32)] = { sequenceForRelativeLockTime.flatMap { s => val seqMasked = TransactionConstants.sequenceLockTimeMask val validScriptNums = s & seqMasked Gen.choose(0L, validScriptNums.toLong).map { sn => val scriptNum = ScriptNumber( - sn | TransactionConstants.sequenceLockTimeTypeFlag.toLong) + sn | TransactionConstants.sequenceLockTimeTypeFlag.toLong + ) require(LockTimeInterpreter.isCSVLockByRelativeLockTime(scriptNum)) require(LockTimeInterpreter.isCSVLockByRelativeLockTime(s)) (scriptNum, s) @@ -841,20 +986,23 @@ object TransactionGenerators { } } - /** Generates a [[org.bitcoins.core.number.UInt32 UInt32]] s.t. the locktime enabled flag is set. - * See [[https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki BIP68]] for more info + /** Generates a [[org.bitcoins.core.number.UInt32 UInt32]] s.t. the locktime + * enabled flag is set. See + * [[https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki BIP68]] + * for more info */ private def validCSVSequence: Gen[UInt32] = NumberGenerator.uInt32s.map { n => - //makes sure the 1 << 31 is TURNED OFF, - //need this to generate spendable CSV values without discarding a bunch of test cases + // makes sure the 1 << 31 is TURNED OFF, + // need this to generate spendable CSV values without discarding a bunch of test cases val result = n & UInt32(0x7fffffff) require(LockTimeInterpreter.isLockTimeBitOff(ScriptNumber(result.toLong))) result } - /** Generates a pair of CSV values: a transaction input sequence, and a CSV script sequence value, such that - * the txInput sequence mask is always less than the script sequence mask (i.e. generates values for a validly + /** Generates a pair of CSV values: a transaction input sequence, and a CSV + * script sequence value, such that the txInput sequence mask is always less + * than the script sequence mask (i.e. generates values for a validly * constructed and NOT spendable CSV transaction). */ def unspendableCSVValues: Gen[(ScriptNumber, UInt32)] = @@ -866,8 +1014,10 @@ object TransactionGenerators { .suchThat(x => LockTimeInterpreter.isLockTimeBitOff(x)) } yield (csvScriptNum, sequence)).suchThat(x => !csvLockTimesOfSameType(x)) - /** generates a [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and - * [[org.bitcoins.core.number.UInt32 UInt32]] locktime for a transaction such that the tx will be spendable + /** generates a + * [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and + * [[org.bitcoins.core.number.UInt32 UInt32]] locktime for a transaction such + * that the tx will be spendable */ def spendableCLTVValues: Gen[(ScriptNumber, UInt32)] = for { @@ -875,8 +1025,10 @@ object TransactionGenerators { cltvLockTime <- sameLockTimeTypeSpendable(txLockTime) } yield (cltvLockTime, txLockTime) - /** Generates a [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and - * [[org.bitcoins.core.number.UInt32 UInt32]] locktime for a transaction such that the tx will be unspendable + /** Generates a + * [[org.bitcoins.core.script.constant.ScriptNumber ScriptNumber]] and + * [[org.bitcoins.core.number.UInt32 UInt32]] locktime for a transaction such + * that the tx will be unspendable */ def unspendableCLTVValues: Gen[(ScriptNumber, UInt32)] = for { @@ -885,13 +1037,16 @@ object TransactionGenerators { } yield (cltvLockTime, txLockTime) private def sameLockTimeTypeSpendable( - txLockTime: UInt32): Gen[ScriptNumber] = { + txLockTime: UInt32 + ): Gen[ScriptNumber] = { if (txLockTime < TransactionConstants.locktimeThreshold) { Gen.choose(0, txLockTime.toLong).map(ScriptNumber(_)) } else { Gen - .choose(TransactionConstants.locktimeThreshold.toLong, - txLockTime.toLong) + .choose( + TransactionConstants.locktimeThreshold.toLong, + txLockTime.toLong + ) .map(ScriptNumber(_)) } } @@ -899,8 +1054,10 @@ object TransactionGenerators { private def sameLockTimeUnspendable(txLockTime: UInt32): Gen[ScriptNumber] = { if (txLockTime < TransactionConstants.locktimeThreshold) { Gen - .choose(txLockTime.toLong + 1, - TransactionConstants.locktimeThreshold.toLong) + .choose( + txLockTime.toLong + 1, + TransactionConstants.locktimeThreshold.toLong + ) .map(ScriptNumber(_)) } else { Gen.choose(txLockTime.toLong + 1, UInt32.max.toLong).map(ScriptNumber(_)) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/WitnessGenerators.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/WitnessGenerators.scala index c0d9bd13a7..8bb548d9fa 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/WitnessGenerators.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/WitnessGenerators.scala @@ -18,11 +18,11 @@ sealed abstract class WitnessGenerators { /** Generates a random [[org.bitcoins.core.protocol.script.ScriptWitness]] */ def scriptWitness: Gen[ScriptWitness] = { - //TODO: I need to come back and uncomment out this code after fixing - //#111 on the issue tracker. We should be able to support an arbtirary byte vector, - //not only pre-defined script witness types + // TODO: I need to come back and uncomment out this code after fixing + // #111 on the issue tracker. We should be able to support an arbtirary byte vector, + // not only pre-defined script witness types - //0 include here to generate the EmptyScriptWitness + // 0 include here to generate the EmptyScriptWitness /* val stack: Gen[Seq[scodec.bits.ByteVector]] = Gen.choose(0,10).flatMap(n => Gen.listOfN(n, NumberGenerator.bytes)) stack.map { s: Seq[scodec.bits.ByteVector] => @@ -71,8 +71,8 @@ sealed abstract class WitnessGenerators { } yield TaprootScriptPath.annex +: annexBytes } - /** Generates a [[org.bitcoins.core.protocol.transaction.TransactionWitness]] with - * the specified number of witnesses + /** Generates a [[org.bitcoins.core.protocol.transaction.TransactionWitness]] + * with the specified number of witnesses */ def transactionWitness(numWitnesses: Int): Gen[TransactionWitness] = for { @@ -85,9 +85,11 @@ sealed abstract class WitnessGenerators { wit <- transactionWitness(num) } yield wit - /** Generates a validly signed [[org.bitcoins.core.protocol.transaction.TransactionWitness]] */ - def signedP2WPKHTransactionWitness: Gen[ - (TransactionWitness, WitnessTxSigComponent, Seq[ECPrivateKey])] = + /** Generates a validly signed + * [[org.bitcoins.core.protocol.transaction.TransactionWitness]] + */ + def signedP2WPKHTransactionWitness + : Gen[(TransactionWitness, WitnessTxSigComponent, Seq[ECPrivateKey])] = for { privKey <- CryptoGenerators.privateKey amount <- CurrencyUnitGenerator.satoshis @@ -98,11 +100,13 @@ sealed abstract class WitnessGenerators { witScriptPubKey, amount, unsignedScriptWitness, - None) + None + ) createdSig = TransactionSignatureCreator.createSig( unsignedWTxSigComponent, privKey, - hashType) + hashType + ) scriptWitness = P2WPKHWitnessV0(privKey.publicKey, createdSig) } yield { @@ -111,100 +115,121 @@ sealed abstract class WitnessGenerators { (witness, signedWtxSigComponent, Seq(privKey)) } - def signedP2WSHP2PKTransactionWitness: Gen[ - (TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = + def signedP2WSHP2PKTransactionWitness + : Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for { (scriptPubKey, privKeys) <- ScriptGenerators.p2pkScriptPubKey amount <- CurrencyUnitGenerator.satoshis hashType <- CryptoGenerators.hashType witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey) unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey) - u = createUnsignedRawWTxSigComponent(witScriptPubKey, - amount, - unsignedScriptWitness, - None) + u = createUnsignedRawWTxSigComponent( + witScriptPubKey, + amount, + unsignedScriptWitness, + None + ) createdSig = TransactionSignatureCreator.createSig(u, privKeys, hashType) signedScriptWitness = P2WSHWitnessV0(scriptPubKey, P2PKScriptSignature(createdSig)) oldTx = u.transaction txWitness = TransactionWitness( oldTx.witness.witnesses - .updated(u.inputIndex.toInt, signedScriptWitness)) - wtx = WitnessTransaction(oldTx.version, - oldTx.inputs, - oldTx.outputs, - oldTx.lockTime, - txWitness) + .updated(u.inputIndex.toInt, signedScriptWitness) + ) + wtx = WitnessTransaction( + oldTx.version, + oldTx.inputs, + oldTx.outputs, + oldTx.lockTime, + txWitness + ) signedWtxSigComponent = WitnessTxSigComponentRaw(wtx, u.inputIndex, u.output, u.flags) } yield (txWitness, signedWtxSigComponent, Seq(privKeys)) - def signedP2WSHP2PKHTransactionWitness: Gen[ - (TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = + def signedP2WSHP2PKHTransactionWitness + : Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for { (scriptPubKey, privKey) <- ScriptGenerators.p2pkhScriptPubKey amount <- CurrencyUnitGenerator.satoshis hashType <- CryptoGenerators.hashType witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey) unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey) - u = createUnsignedRawWTxSigComponent(witScriptPubKey, - amount, - unsignedScriptWitness, - None) + u = createUnsignedRawWTxSigComponent( + witScriptPubKey, + amount, + unsignedScriptWitness, + None + ) createdSig = TransactionSignatureCreator.createSig(u, privKey, hashType) signedScriptWitness = P2WSHWitnessV0( scriptPubKey, - P2PKHScriptSignature(createdSig, privKey.publicKey)) + P2PKHScriptSignature(createdSig, privKey.publicKey) + ) oldTx = u.transaction txWitness = TransactionWitness( oldTx.witness.witnesses - .updated(u.inputIndex.toInt, signedScriptWitness)) - wtx = WitnessTransaction(oldTx.version, - oldTx.inputs, - oldTx.outputs, - oldTx.lockTime, - txWitness) + .updated(u.inputIndex.toInt, signedScriptWitness) + ) + wtx = WitnessTransaction( + oldTx.version, + oldTx.inputs, + oldTx.outputs, + oldTx.lockTime, + txWitness + ) signedWtxSigComponent = WitnessTxSigComponentRaw(wtx, u.inputIndex, u.output, u.flags) } yield (txWitness, signedWtxSigComponent, Seq(privKey)) - def signedP2WSHMultiSigTransactionWitness: Gen[ - (TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = + def signedP2WSHMultiSigTransactionWitness + : Gen[(TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = for { (scriptPubKey, privKeys) <- ScriptGenerators.multiSigScriptPubKey amount <- CurrencyUnitGenerator.satoshis hashType <- CryptoGenerators.hashType witScriptPubKey = P2WSHWitnessSPKV0(scriptPubKey) unsignedScriptWitness = P2WSHWitnessV0(scriptPubKey) - u = createUnsignedRawWTxSigComponent(witScriptPubKey, - amount, - unsignedScriptWitness, - None) + u = createUnsignedRawWTxSigComponent( + witScriptPubKey, + amount, + unsignedScriptWitness, + None + ) signedScriptSig = multiSigScriptSigGenHelper(privKeys, scriptPubKey, u, hashType) signedScriptWitness = P2WSHWitnessV0(scriptPubKey, signedScriptSig) oldTx = u.transaction txWitness = TransactionWitness( oldTx.witness.witnesses - .updated(u.inputIndex.toInt, signedScriptWitness)) - wtx = WitnessTransaction(oldTx.version, - oldTx.inputs, - oldTx.outputs, - oldTx.lockTime, - txWitness) + .updated(u.inputIndex.toInt, signedScriptWitness) + ) + wtx = WitnessTransaction( + oldTx.version, + oldTx.inputs, + oldTx.outputs, + oldTx.lockTime, + txWitness + ) signedWtxSigComponent = WitnessTxSigComponentRaw(wtx, u.inputIndex, u.output, u.flags) } yield (txWitness, signedWtxSigComponent, privKeys) - /** Generates a random signed [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] - * with the corresponding [[org.bitcoins.core.crypto.WitnessTxSigComponent WitnessTxSigComponent]] + /** Generates a random signed + * [[org.bitcoins.core.protocol.transaction.TransactionWitness TransactionWitness]] + * with the corresponding + * [[org.bitcoins.core.crypto.WitnessTxSigComponent WitnessTxSigComponent]] * and [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]] */ def signedP2WSHTransactionWitness: Gen[ - (TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey])] = { - Gen.oneOf(signedP2WSHP2PKTransactionWitness, - signedP2WSHP2PKHTransactionWitness, - signedP2WSHMultiSigTransactionWitness) + (TransactionWitness, WitnessTxSigComponentRaw, Seq[ECPrivateKey]) + ] = { + Gen.oneOf( + signedP2WSHP2PKTransactionWitness, + signedP2WSHP2PKHTransactionWitness, + signedP2WSHMultiSigTransactionWitness + ) } /** Helps generate a signed @@ -214,62 +239,75 @@ sealed abstract class WitnessGenerators { privateKeys: Seq[ECPrivateKey], scriptPubKey: MultiSignatureScriptPubKey, unsignedWtxSigComponent: WitnessTxSigComponent, - hashType: HashType): MultiSignatureScriptSignature = { + hashType: HashType + ): MultiSignatureScriptSignature = { val requiredSigs = scriptPubKey.requiredSigs val txSignatures = for { i <- 0 until requiredSigs - } yield TransactionSignatureCreator.createSig(unsignedWtxSigComponent, - privateKeys(i), - hashType) + } yield TransactionSignatureCreator.createSig( + unsignedWtxSigComponent, + privateKeys(i), + hashType + ) - //add the signature to the scriptSig instead of having an empty scriptSig + // add the signature to the scriptSig instead of having an empty scriptSig val signedScriptSig = MultiSignatureScriptSignature(txSignatures) signedScriptSig } - /** Generates a random [[org.bitcoins.core.protocol.script.P2WPKHWitnessV0 P2PWPKHWitnessV0]] */ + /** Generates a random + * [[org.bitcoins.core.protocol.script.P2WPKHWitnessV0 P2PWPKHWitnessV0]] + */ def p2wpkhWitnessV0: Gen[P2WPKHWitnessV0] = for { publicKey <- CryptoGenerators.publicKey sig <- CryptoGenerators.digitalSignature } yield P2WPKHWitnessV0(publicKey, sig) - /** Generates a random [[org.bitcoins.core.protocol.script.P2WPKHWitnessV0 P2PWPKHWitnessV0]] */ + /** Generates a random + * [[org.bitcoins.core.protocol.script.P2WPKHWitnessV0 P2PWPKHWitnessV0]] + */ def p2wshWitnessV0: Gen[P2WSHWitnessV0] = for { (redeem, _) <- ScriptGenerators.rawScriptPubKey scriptSig <- ScriptGenerators.scriptSignature } yield P2WSHWitnessV0(redeem, scriptSig) - /** Takes a signed [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] and an unsignedTx - * and adds the witness to the unsigned + /** Takes a signed + * [[org.bitcoins.core.protocol.script.ScriptWitness ScriptWitness]] and an + * unsignedTx and adds the witness to the unsigned * [[org.bitcoins.core.protocol.transaction.WitnessTransaction WitnessTransaction]] */ def createSignedWTxComponent( witness: ScriptWitness, - unsignedWTxComponent: WitnessTxSigComponent): ( - TransactionWitness, - WitnessTxSigComponent) = { + unsignedWTxComponent: WitnessTxSigComponent + ): (TransactionWitness, WitnessTxSigComponent) = { val signedTxWitness = TransactionWitness.fromWitOpt(Vector(Some(witness))) val unsignedSpendingTx = unsignedWTxComponent.transaction - val signedSpendingTx = WitnessTransaction(unsignedSpendingTx.version, - unsignedSpendingTx.inputs, - unsignedSpendingTx.outputs, - unsignedSpendingTx.lockTime, - signedTxWitness) + val signedSpendingTx = WitnessTransaction( + unsignedSpendingTx.version, + unsignedSpendingTx.inputs, + unsignedSpendingTx.outputs, + unsignedSpendingTx.lockTime, + signedTxWitness + ) val signedWtxSigComponent = unsignedWTxComponent match { case wtxP2SH: WitnessTxSigComponentP2SH => - WitnessTxSigComponent(signedSpendingTx, - unsignedWTxComponent.inputIndex, - wtxP2SH.output, - PreviousOutputMap.empty, - unsignedWTxComponent.flags) + WitnessTxSigComponent( + signedSpendingTx, + unsignedWTxComponent.inputIndex, + wtxP2SH.output, + PreviousOutputMap.empty, + unsignedWTxComponent.flags + ) case wtxRaw: WitnessTxSigComponentRaw => - WitnessTxSigComponent(signedSpendingTx, - unsignedWTxComponent.inputIndex, - wtxRaw.output, - PreviousOutputMap.empty, - unsignedWTxComponent.flags) + WitnessTxSigComponent( + signedSpendingTx, + unsignedWTxComponent.inputIndex, + wtxRaw.output, + PreviousOutputMap.empty, + unsignedWTxComponent.flags + ) case _: TaprootTxSigComponent => sys.error(s"Cannot build signed taproot sig component yet") } @@ -284,7 +322,8 @@ sealed abstract class WitnessGenerators { witScriptPubKey: WitnessScriptPubKey, amount: CurrencyUnit, unsignedScriptWitness: ScriptWitness, - sequence: Option[UInt32]): WitnessTxSigComponentRaw = { + sequence: Option[UInt32] + ): WitnessTxSigComponentRaw = { val tc = TransactionConstants val flags = Policy.standardScriptVerifyFlags val witness = @@ -299,7 +338,8 @@ sealed abstract class WitnessGenerators { outputIndex, tc.lockTime, sequence.getOrElse(tc.sequence), - witness) + witness + ) val output = creditingTx.outputs(outputIndex.toInt) val unsignedWtxSigComponent = WitnessTxSigComponentRaw(unsignedSpendingTx, inputIndex, output, flags) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ln/LnInvoiceGen.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ln/LnInvoiceGen.scala index 358e3b9b98..7819dacd12 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ln/LnInvoiceGen.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ln/LnInvoiceGen.scala @@ -10,7 +10,8 @@ import org.scalacheck.Gen sealed abstract class LnInvoiceGen { - /** Generates a [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] + /** Generates a + * [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] * that does not contain a amount * @return */ @@ -20,14 +21,17 @@ sealed abstract class LnInvoiceGen { } } - /** Generates a [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] + /** Generates a + * [[org.bitcoins.core.protocol.ln.LnHumanReadablePart LnHumanReadablePart]] * with an amount encoded */ def lnHrpAmt: Gen[LnHumanReadablePart] = { ChainParamsGenerator.lnNetworkParams.flatMap { lnParam => LnCurrencyUnitGen.realisticLnInvoice.map { lcu => - LnHumanReadablePart.fromParamsAmount(network = lnParam, - amount = Some(lcu)) + LnHumanReadablePart.fromParamsAmount( + network = lnParam, + amount = Some(lcu) + ) } } } @@ -64,8 +68,8 @@ sealed abstract class LnInvoiceGen { } } - def descriptionOrDescriptionHashTag: Gen[ - Either[LnTag.DescriptionTag, LnTag.DescriptionHashTag]] = { + def descriptionOrDescriptionHashTag + : Gen[Either[LnTag.DescriptionTag, LnTag.DescriptionHashTag]] = { if (scala.util.Random.nextBoolean()) { descriptionTag.map(Left(_)) } else { @@ -123,7 +127,7 @@ sealed abstract class LnInvoiceGen { paymentHash <- paymentHashTag descOrHashTag <- descriptionOrDescriptionHashTag secret <- Gen.option(secret) - //optional fields + // optional fields expiryTime <- Gen.option(expiryTime) cltvExpiry <- Gen.option(cltvExpiry) fallbackAddress <- Gen.option(fallbackAddress) @@ -146,7 +150,7 @@ sealed abstract class LnInvoiceGen { paymentHash <- paymentHashTag descOrHashTag <- descriptionOrDescriptionHashTag secret <- secret - //optional fields + // optional fields expiryTime <- expiryTime cltvExpiry <- cltvExpiry fallbackAddress <- fallbackAddress @@ -188,7 +192,7 @@ sealed abstract class LnInvoiceGen { def lnInvoice(privateKey: ECPrivateKey): Gen[LnInvoice] = { for { hrp <- lnHrp - //timestamp is 35 bits according to BOLT11 + // timestamp is 35 bits according to BOLT11 timestamp <- invoiceTimestamp nodeIdOpt <- Gen.option(NodeId(privateKey.publicKey)) tags <- taggedFields(nodeIdOpt) @@ -200,10 +204,12 @@ sealed abstract class LnInvoiceGen { privateKey = privateKey ) - LnInvoice(hrp = hrp, - timestamp = timestamp, - lnTags = tags, - signature = signature) + LnInvoice( + hrp = hrp, + timestamp = timestamp, + lnTags = tags, + signature = signature + ) } } @@ -211,7 +217,7 @@ sealed abstract class LnInvoiceGen { for { privateKey <- CryptoGenerators.privateKey hrp <- lnHrp - //timestamp is 35 bits according to BOLT11 + // timestamp is 35 bits according to BOLT11 timestamp <- invoiceTimestamp } yield { val signature = LnInvoice.buildLnInvoiceSignature( @@ -221,10 +227,12 @@ sealed abstract class LnInvoiceGen { privateKey = privateKey ) - LnInvoice(hrp = hrp, - timestamp = timestamp, - lnTags = tags, - signature = signature) + LnInvoice( + hrp = hrp, + timestamp = timestamp, + lnTags = tags, + signature = signature + ) } } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ln/LnRouteGen.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ln/LnRouteGen.scala index 58c7719c01..6ce37a3ea0 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ln/LnRouteGen.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/ln/LnRouteGen.scala @@ -20,7 +20,7 @@ trait LnRouteGen { def feeBaseMSat: Gen[FeeBaseMSat] = for { - //note that the feebase msat is only 4 bytes + // note that the feebase msat is only 4 bytes u32 <- NumberGenerator.uInt32s } yield { val ms = MilliSatoshis(u32.toBigInt) @@ -39,11 +39,13 @@ trait LnRouteGen { baseFee <- feeBaseMSat feeProp <- feeProportionalMillionths cltvExpiryDelta <- NumberGenerator.positiveShort - } yield LnRoute(pubkey = pubKey, - shortChannelID = id, - feeBaseMsat = baseFee, - feePropMilli = feeProp, - cltvExpiryDelta = cltvExpiryDelta) + } yield LnRoute( + pubkey = pubKey, + shortChannelID = id, + feeBaseMsat = baseFee, + feePropMilli = feeProp, + cltvExpiryDelta = cltvExpiryDelta + ) def routes: Gen[Vector[LnRoute]] = { Gen diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/ControlMessageGenerator.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/ControlMessageGenerator.scala index 2e76818ffe..50ead3b848 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/ControlMessageGenerator.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/ControlMessageGenerator.scala @@ -42,7 +42,8 @@ object ControlMessageGenerator { /** Generates a random [[org.bitcoins.core.p2p.VersionMessage VersionMessage]] * - * @see [[https://bitcoin.org/en/developer-reference#version]] + * @see + * [[https://bitcoin.org/en/developer-reference#version]] */ def versionMessage: Gen[VersionMessage] = for { @@ -77,7 +78,8 @@ object ControlMessageGenerator { /** Generates a [[org.bitcoins.core.p2p.PingMessage]] * - * @see [[https://bitcoin.org/en/developer-reference#ping]] + * @see + * [[https://bitcoin.org/en/developer-reference#ping]] */ def pingMessage: Gen[PingMessage] = for { @@ -86,7 +88,8 @@ object ControlMessageGenerator { /** Generates a [[org.bitcoins.core.p2p.PongMessage]] * - * @see [[https://bitcoin.org/en/developer-reference#pong]] + * @see + * [[https://bitcoin.org/en/developer-reference#pong]] */ def pongMessage: Gen[PongMessage] = for { @@ -101,7 +104,8 @@ object ControlMessageGenerator { /** Generates a random [[org.bitcoins.core.p2p.ProtocolVersion]] * - * @see [[https://bitcoin.org/en/developer-reference#protocol-versions]] + * @see + * [[https://bitcoin.org/en/developer-reference#protocol-versions]] */ def protocolVersion: Gen[ProtocolVersion] = for { @@ -110,11 +114,12 @@ object ControlMessageGenerator { /** Generates a [[org.bitcoins.core.p2p.ServiceIdentifier]] * - * @see [[https://bitcoin.org/en/developer-reference#version]] + * @see + * [[https://bitcoin.org/en/developer-reference#version]] */ def serviceIdentifier: Gen[ServiceIdentifier] = for { - //service identifiers can only be NodeNetwork or UnnamedService + // service identifiers can only be NodeNetwork or UnnamedService randomNum <- Gen.choose(0, 1) } yield ServiceIdentifier(randomNum) @@ -122,7 +127,8 @@ object ControlMessageGenerator { /** Creates a [[org.bitcoins.core.p2p.FilterLoadMessage]] * - * @see [[https://bitcoin.org/en/developer-reference#filterload]] + * @see + * [[https://bitcoin.org/en/developer-reference#filterload]] */ def filterLoadMessage: Gen[FilterLoadMessage] = for { @@ -130,14 +136,17 @@ object ControlMessageGenerator { hashFuncs <- Gen.choose(0, 50) tweak <- NumberGenerator.uInt32s flags <- BloomFilterGenerator.bloomFlag - } yield FilterLoadMessage(ByteVector(filter), - UInt32(hashFuncs), - tweak, - flags) + } yield FilterLoadMessage( + ByteVector(filter), + UInt32(hashFuncs), + tweak, + flags + ) /** Creates a [[org.bitcoins.core.p2p.FilterAddMessage]] * - * @see [[https://bitcoin.org/en/developer-reference#filteradd]] + * @see + * [[https://bitcoin.org/en/developer-reference#filteradd]] */ def filterAddMessage: Gen[FilterAddMessage] = for { @@ -147,7 +156,8 @@ object ControlMessageGenerator { /** Creates a [[org.bitcoins.core.p2p.RejectMessage]] * - * @see [[https://bitcoin.org/en/developer-reference#reject]] + * @see + * [[https://bitcoin.org/en/developer-reference#reject]] */ def rejectMessage: Gen[RejectMessage] = for { diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/DataMessageGenerator.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/DataMessageGenerator.scala index d8fd1bd224..3261791f83 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/DataMessageGenerator.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/DataMessageGenerator.scala @@ -12,7 +12,8 @@ import org.scalacheck.Gen /** Responsible for generating random data message * - * @see [[https://bitcoin.org/en/developer-reference#data-messages]] + * @see + * [[https://bitcoin.org/en/developer-reference#data-messages]] */ trait DataMessageGenerator { @@ -49,7 +50,8 @@ trait DataMessageGenerator { /** Generates a random [[org.bitcoins.core.p2p.GetHeadersMessage]] * - * @see [[https://bitcoin.org/en/developer-reference#getheaders]] + * @see + * [[https://bitcoin.org/en/developer-reference#getheaders]] */ def getHeaderMessages: Gen[GetHeadersMessage] = for { @@ -71,7 +73,7 @@ trait DataMessageGenerator { def headersMessage: Gen[HeadersMessage] = for { randomNum <- Gen.choose(1, 10) - //we have a maximum of 2000 block headers in a HeadersMessage + // we have a maximum of 2000 block headers in a HeadersMessage blockHeaders <- Gen .listOfN(randomNum, BlockchainElementsGenerator.blockHeader) @@ -80,7 +82,8 @@ trait DataMessageGenerator { /** Generates a random [[org.bitcoins.core.p2p.TypeIdentifier]] * - * @see [[https://bitcoin.org/en/developer-reference#data-messages]] + * @see + * [[https://bitcoin.org/en/developer-reference#data-messages]] */ def typeIdentifier: Gen[TypeIdentifier] = for { @@ -88,7 +91,8 @@ trait DataMessageGenerator { } yield TypeIdentifier(UInt32(num)) /** Generates a random [[org.bitcoins.core.p2p.Inventory]] - * @see [[https://bitcoin.org/en/developer-reference#term-inventory]] + * @see + * [[https://bitcoin.org/en/developer-reference#term-inventory]] */ def inventory: Gen[Inventory] = for { @@ -97,7 +101,8 @@ trait DataMessageGenerator { } yield Inventory(identifier, hash) /** Generates a random [[org.bitcoins.core.p2p.InventoryMessage]] - * @see [[https://bitcoin.org/en/developer-reference#inv]] + * @see + * [[https://bitcoin.org/en/developer-reference#inv]] */ def inventoryMessages: Gen[InventoryMessage] = for { @@ -112,7 +117,8 @@ trait DataMessageGenerator { } /** Generate a random [[org.bitcoins.core.p2p.GetDataMessage]] - * @see [[https://bitcoin.org/en/developer-reference#getdata]] + * @see + * [[https://bitcoin.org/en/developer-reference#getdata]] */ def getDataMessages: Gen[GetDataMessage] = for { @@ -120,7 +126,8 @@ trait DataMessageGenerator { } yield GetDataMessage(invMsgs.inventoryCount, invMsgs.inventories) /** Generates a random [[org.bitcoins.core.p2p.MerkleBlockMessage]] - * @see [[https://bitcoin.org/en/developer-reference#merkleblock]] + * @see + * [[https://bitcoin.org/en/developer-reference#merkleblock]] */ def merkleBlockMessage: Gen[MerkleBlockMessage] = for { @@ -128,7 +135,8 @@ trait DataMessageGenerator { } yield MerkleBlockMessage(merkleBlock) /** Generates a [[org.bitcoins.core.p2p.TransactionMessage]] - * @see [[https://bitcoin.org/en/developer-reference#tx]] + * @see + * [[https://bitcoin.org/en/developer-reference#tx]] */ def transactionMessage: Gen[TransactionMessage] = for { diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/P2PGenerator.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/P2PGenerator.scala index 1f93afa69a..657b41aae9 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/P2PGenerator.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/gen/p2p/P2PGenerator.scala @@ -8,8 +8,10 @@ object P2PGenerator { /** Generates a valid P2P network message */ def message: Gen[NetworkPayload] = - Gen.oneOf(ControlMessageGenerator.controlMessage, - DataMessageGenerator.dataMessage) + Gen.oneOf( + ControlMessageGenerator.controlMessage, + DataMessageGenerator.dataMessage + ) def inetAddress: Gen[InetAddress] = { def ipRangeNum = Gen.choose(0, 255) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/node/P2PMessageTestUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/node/P2PMessageTestUtil.scala index 357a68f68b..830fc937a5 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/node/P2PMessageTestUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/node/P2PMessageTestUtil.scala @@ -7,8 +7,8 @@ import org.bitcoins.core.protocol.transaction.Transaction abstract class P2PMessageTestUtil { - //txid on testnet 44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff - //this tx has multiple inputs and outputs + // txid on testnet 44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff + // this tx has multiple inputs and outputs def rawTransaction = "01000000" + "02df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd040011b0000006a473044022040f91c48f4011bf2e2edb6621bfa8fb802241de939cb86f1872c99c580ef0fe402204fc27388bc525e1b655b5f5b35f9d601d28602432dd5672f29e0a47f5b8bbb26012102c114f376c98d12a0540c3a81ab99bb1c5234245c05e8239d09f48229f9ebf011ffffffff" + @@ -24,15 +24,16 @@ abstract class P2PMessageTestUtil { "7c1101000000000000000000d805833655010000000000000000000000000000000000000000ffff0a940106479d010000000000000000000000000000000000ffff739259bb479d0000000000000000182f626974636f696e732d7370762d6e6f64652f302e302e310000000000" def versionMessage = VersionMessage(rawVersionMessage) - /** This is a raw network message indicating the version a node is using on the p2p network - * This has BOTH the header and the payload + /** This is a raw network message indicating the version a node is using on + * the p2p network This has BOTH the header and the payload * @return */ def rawNetworkMessage = "0b11090776657273696f6e0000000000660000002f6743da721101000100000000000000e0165b5700000000010000000000000000000000000000000000ffffad1f27a8479d010000000000000000000000000000000000ffff00000000479d68dc32a9948d149b102f5361746f7368693a302e31312e322f7f440d0001" def networkMessage = NetworkMessage(rawNetworkMessage) - /** This is a get headers message taken from wireshark off of a node that sent the message + /** This is a get headers message taken from wireshark off of a node that sent + * the message * @return */ def rawGetHeadersMsg = @@ -42,19 +43,26 @@ abstract class P2PMessageTestUtil { val emptyBloomFilter: BloomFilter = BloomFilter(numElements = 1, falsePositiveRate = 1, flags = BloomUpdateAll) - /** These are the first 5 block headers on testnet, this does NOT include the genesis block header */ + /** These are the first 5 block headers on testnet, this does NOT include the + * genesis block header + */ lazy val firstFiveTestNetBlockHeaders: List[BlockHeader] = { List( BlockHeader( - "0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b672"), + "0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b672" + ), BlockHeader( - "0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d23534"), + "0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d23534" + ), BlockHeader( - "0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b6"), + "0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b6" + ), BlockHeader( - "0100000010befdc16d281e40ecec65b7c9976ddc8fd9bc9752da5827276e898b000000004c976d5776dda2da30d96ee810cd97d23ba852414990d64c4c720f977e651f2daae7494dffff001d02a97640"), + "0100000010befdc16d281e40ecec65b7c9976ddc8fd9bc9752da5827276e898b000000004c976d5776dda2da30d96ee810cd97d23ba852414990d64c4c720f977e651f2daae7494dffff001d02a97640" + ), BlockHeader( - "01000000dde5b648f594fdd2ec1c4083762dd13b197bb1381e74b1fff90a5d8b00000000b3c6c6c1118c3b6abaa17c5aa74ee279089ad34dc3cec3640522737541cb016818e8494dffff001d02da84c0") + "01000000dde5b648f594fdd2ec1c4083762dd13b197bb1381e74b1fff90a5d8b00000000b3c6c6c1118c3b6abaa17c5aa74ee279089ad34dc3cec3640522737541cb016818e8494dffff001d02da84c0" + ) ) } } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BaseAsyncTest.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BaseAsyncTest.scala index c853cda853..251ea5eb46 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BaseAsyncTest.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BaseAsyncTest.scala @@ -36,14 +36,15 @@ trait BaseAsyncTest /** This def ensures that shrinks are disabled for all calls to forAll. * - * If you want to enable shrinking for a specific test, introduce an - * implicit val into that scope with type Shrink[T] where T is the type - * of the generator you want to enable shrinking on. + * If you want to enable shrinking for a specific test, introduce an implicit + * val into that scope with type Shrink[T] where T is the type of the + * generator you want to enable shrinking on. */ implicit def noShrink[T]: Shrink[T] = Shrink.shrinkAny[T] /** The configuration for property based tests in our testing suite - * @see http://www.scalatest.org/user_guide/writing_scalacheck_style_properties + * @see + * http://www.scalatest.org/user_guide/writing_scalacheck_style_properties */ implicit override val generatorDrivenConfig: PropertyCheckConfiguration = { generatorDriveConfigOldCode @@ -58,16 +59,16 @@ trait BaseAsyncTest ) } - /** Property based tests that have been around a long time - * have a less of a chance failing, so execute them less + /** Property based tests that have been around a long time have a less of a + * chance failing, so execute them less * @return */ def generatorDriveConfigOldCode: PropertyCheckConfiguration = { customGenDrivenConfig(BitcoinSUnitTest.OLD_CODE_EXECUTIONS) } - /** Property based tests that are new have a higher chance of failing - * so execute them more + /** Property based tests that are new have a higher chance of failing so + * execute them more * @return */ def generatorDrivenConfigNewCode: PropertyCheckConfiguration = { @@ -75,15 +76,17 @@ trait BaseAsyncTest } def sequenceTestRuns( - testRunFs: Vector[Future[Assertion]]): Future[Assertion] = { + testRunFs: Vector[Future[Assertion]] + ): Future[Assertion] = { val testRunsF: Future[Vector[Assertion]] = Future.sequence(testRunFs) testRunsF.map(_.reduce((_, testRun) => testRun)) } - def forAllAsync[A](gen: Gen[A])( - func: A => Future[Assertion]): Future[Assertion] = { + def forAllAsync[A]( + gen: Gen[A] + )(func: A => Future[Assertion]): Future[Assertion] = { val testRunFs = new java.util.concurrent.CopyOnWriteArrayList[Future[Assertion]] @@ -96,7 +99,8 @@ trait BaseAsyncTest } def forAllAsync[A, B](genA: Gen[A], genB: Gen[B])( - func: (A, B) => Future[Assertion]): Future[Assertion] = { + func: (A, B) => Future[Assertion] + ): Future[Assertion] = { val testRunFs = new java.util.concurrent.CopyOnWriteArrayList[Future[Assertion]] @@ -109,7 +113,8 @@ trait BaseAsyncTest } def forAllAsync[A, B, C](genA: Gen[A], genB: Gen[B], genC: Gen[C])( - func: (A, B, C) => Future[Assertion]): Future[Assertion] = { + func: (A, B, C) => Future[Assertion] + ): Future[Assertion] = { val testRunFs = new java.util.concurrent.CopyOnWriteArrayList[Future[Assertion]] @@ -125,8 +130,8 @@ trait BaseAsyncTest genA: Gen[A], genB: Gen[B], genC: Gen[C], - genD: Gen[D])( - func: (A, B, C, D) => Future[Assertion]): Future[Assertion] = { + genD: Gen[D] + )(func: (A, B, C, D) => Future[Assertion]): Future[Assertion] = { val testRunFs = new java.util.concurrent.CopyOnWriteArrayList[Future[Assertion]] @@ -143,8 +148,8 @@ trait BaseAsyncTest genB: Gen[B], genC: Gen[C], genD: Gen[D], - genE: Gen[E])( - func: (A, B, C, D, E) => Future[Assertion]): Future[Assertion] = { + genE: Gen[E] + )(func: (A, B, C, D, E) => Future[Assertion]): Future[Assertion] = { val testRunFs = new java.util.concurrent.CopyOnWriteArrayList[Future[Assertion]] @@ -163,8 +168,8 @@ trait BaseAsyncTest genC: Gen[C], genD: Gen[D], genE: Gen[E], - genF: Gen[F])( - func: (A, B, C, D, E, F) => Future[Assertion]): Future[Assertion] = { + genF: Gen[F] + )(func: (A, B, C, D, E, F) => Future[Assertion]): Future[Assertion] = { val testRunFs = new java.util.concurrent.CopyOnWriteArrayList[Future[Assertion]] @@ -177,11 +182,12 @@ trait BaseAsyncTest forAllHelper(testRunFs) } - /** Runs all property based tests in parallel. This is a convenient optimization - * for synchronous property based tests + /** Runs all property based tests in parallel. This is a convenient + * optimization for synchronous property based tests */ - def forAllParallel[A](gen: Gen[A])( - func: A => Assertion): Future[Assertion] = { + def forAllParallel[A]( + gen: Gen[A] + )(func: A => Assertion): Future[Assertion] = { forAllAsync(gen) { a: A => FutureUtil.makeAsync { () => func(a) @@ -189,11 +195,12 @@ trait BaseAsyncTest } } - /** Runs all property based tests in parallel. This is a convenient optimization - * for synchronous property based tests + /** Runs all property based tests in parallel. This is a convenient + * optimization for synchronous property based tests */ def forAllParallel[A, B, C](genA: Gen[A], genB: Gen[B])( - func: (A, B) => Assertion): Future[Assertion] = { + func: (A, B) => Assertion + ): Future[Assertion] = { forAllAsync(genA, genB) { case (inputA, inputB) => FutureUtil.makeAsync { () => func(inputA, inputB) @@ -201,11 +208,12 @@ trait BaseAsyncTest } } - /** Runs all property based tests in parallel. This is a convenient optimization - * for synchronous property based tests + /** Runs all property based tests in parallel. This is a convenient + * optimization for synchronous property based tests */ def forAllParallel[A, B, C](genA: Gen[A], genB: Gen[B], genC: Gen[C])( - func: (A, B, C) => Assertion): Future[Assertion] = { + func: (A, B, C) => Assertion + ): Future[Assertion] = { forAllAsync(genA, genB, genC) { case (inputA, inputB, inputC) => FutureUtil.makeAsync { () => func(inputA, inputB, inputC) @@ -213,14 +221,15 @@ trait BaseAsyncTest } } - /** Runs all property based tests in parallel. This is a convenient optimization - * for synchronous property based tests + /** Runs all property based tests in parallel. This is a convenient + * optimization for synchronous property based tests */ def forAllParallel[A, B, C, D, E]( genA: Gen[A], genB: Gen[B], genC: Gen[C], - genD: Gen[D])(func: (A, B, C, D) => Assertion): Future[Assertion] = { + genD: Gen[D] + )(func: (A, B, C, D) => Assertion): Future[Assertion] = { forAllAsync(genA, genB, genC, genD) { case (inputA, inputB, inputC, inputD) => FutureUtil.makeAsync { () => @@ -229,15 +238,16 @@ trait BaseAsyncTest } } - /** Runs all property based tests in parallel. This is a convenient optimization - * for synchronous property based tests + /** Runs all property based tests in parallel. This is a convenient + * optimization for synchronous property based tests */ def forAllParallel[A, B, C, D, E]( genA: Gen[A], genB: Gen[B], genC: Gen[C], genD: Gen[D], - genE: Gen[E])(func: (A, B, C, D, E) => Assertion): Future[Assertion] = { + genE: Gen[E] + )(func: (A, B, C, D, E) => Assertion): Future[Assertion] = { forAllAsync(genA, genB, genC, genD, genE) { case (inputA, inputB, inputC, inputD, inputE) => FutureUtil.makeAsync { () => @@ -246,8 +256,8 @@ trait BaseAsyncTest } } - /** Runs all property based tests in parallel. This is a convenient optimization - * for synchronous property based tests + /** Runs all property based tests in parallel. This is a convenient + * optimization for synchronous property based tests */ def forAllParallel[A, B, C, D, E, F]( genA: Gen[A], @@ -255,8 +265,8 @@ trait BaseAsyncTest genC: Gen[C], genD: Gen[D], genE: Gen[E], - genF: Gen[F])( - func: (A, B, C, D, E, F) => Assertion): Future[Assertion] = { + genF: Gen[F] + )(func: (A, B, C, D, E, F) => Assertion): Future[Assertion] = { forAllAsync(genA, genB, genC, genD, genE, genF) { case (inputA, inputB, inputC, inputD, inputE, inputF) => FutureUtil.makeAsync { () => @@ -267,8 +277,8 @@ trait BaseAsyncTest /** Makes sure we have aggregated all of our test runs */ @nowarn private def forAllHelper( - testRunsF: java.util.concurrent.CopyOnWriteArrayList[ - Future[Assertion]]): Future[Assertion] = { + testRunsF: java.util.concurrent.CopyOnWriteArrayList[Future[Assertion]] + ): Future[Assertion] = { def helper(): Boolean = { testRunsF.size() == generatorDrivenConfig.minSize.value } @@ -281,9 +291,8 @@ trait BaseAsyncTest } } -/** A bitcoin-s test trait that does NOT use akka, it - * uses the default scala execution context to run - * the tests on +/** A bitcoin-s test trait that does NOT use akka, it uses the default scala + * execution context to run the tests on */ trait BitcoinSJvmTest extends AsyncFlatSpec with BaseAsyncTest { diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BitcoinSUnitTest.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BitcoinSUnitTest.scala index 2473fcfa7b..78395c3cfa 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BitcoinSUnitTest.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BitcoinSUnitTest.scala @@ -21,14 +21,15 @@ abstract class BitcoinSUnitTest /** This def ensures that shrinks are disabled for all calls to forAll. * - * If you want to enable shrinking for a specific test, introduce an - * implicit val into that scope with type Shrink[T] where T is the type - * of the generator you want to enable shrinking on. + * If you want to enable shrinking for a specific test, introduce an implicit + * val into that scope with type Shrink[T] where T is the type of the + * generator you want to enable shrinking on. */ implicit def noShrink[T]: Shrink[T] = Shrink.shrinkAny[T] /** The configuration for property based tests in our testing suite - * @see http://www.scalatest.org/user_guide/writing_scalacheck_style_properties + * @see + * http://www.scalatest.org/user_guide/writing_scalacheck_style_properties */ implicit override val generatorDrivenConfig: PropertyCheckConfiguration = { generatorDriveConfigOldCode @@ -43,16 +44,16 @@ abstract class BitcoinSUnitTest ) } - /** Property based tests that have been around a long time - * have a less of a chance failing, so execute them less + /** Property based tests that have been around a long time have a less of a + * chance failing, so execute them less * @return */ def generatorDriveConfigOldCode: PropertyCheckConfiguration = { customGenDrivenConfig(BitcoinSUnitTest.OLD_CODE_EXECUTIONS) } - /** Property based tests that are new have a higher chance of failing - * so execute them more + /** Property based tests that are new have a higher chance of failing so + * execute them more * @return */ def generatorDrivenConfigNewCode: PropertyCheckConfiguration = { @@ -63,13 +64,11 @@ abstract class BitcoinSUnitTest object BitcoinSUnitTest { - /** The number of times new code - * should be executed in a property based test + /** The number of times new code should be executed in a property based test */ val NEW_CODE_EXECUTIONS = 100 - /** The number of times old code should be executed - * in a property based test + /** The number of times old code should be executed in a property based test */ val OLD_CODE_EXECUTIONS = 20 diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BytesUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BytesUtil.scala index feb368d8f6..f6c1373c4c 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BytesUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/BytesUtil.scala @@ -44,12 +44,13 @@ object BytesUtil { case Some((sig, index)) => P2WSHWitnessV0( EmptyScriptPubKey, - p2wsh.stack.updated(index, - flipBit(ECDigitalSignature(sig)).bytes)) + p2wsh.stack.updated(index, flipBit(ECDigitalSignature(sig)).bytes) + ) case None => P2WSHWitnessV0( EmptyScriptPubKey, - p2wsh.stack.updated(0, flipAtIndex(p2wsh.stack.head, 0))) + p2wsh.stack.updated(0, flipAtIndex(p2wsh.stack.head, 0)) + ) } } } @@ -62,7 +63,8 @@ object BytesUtil { def flipBit( cetSigs: CETSignatures, - refundSig: PartialSignature): (CETSignatures, PartialSignature) = { + refundSig: PartialSignature + ): (CETSignatures, PartialSignature) = { val badOutcomeSigs = cetSigs.outcomeSigs.map { case (outcome, sig) => outcome -> flipBit(sig) } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/OracleTestUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/OracleTestUtil.scala index 852842880a..90d11f6c9a 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/OracleTestUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/OracleTestUtil.scala @@ -24,10 +24,12 @@ object OracleTestUtil { val testAddress: Bech32Address = Bech32Address.fromString(testAddressStr) val kVal: ECPrivateKey = ECPrivateKey.fromHex( - "447d4457dfff21354d56cb1b62b2ab6e5964c5ef93e6d74ae3b30dc83b89b6a5") + "447d4457dfff21354d56cb1b62b2ab6e5964c5ef93e6d74ae3b30dc83b89b6a5" + ) val dummyPrivKey: ECPrivateKey = ECPrivateKey.fromHex( - "f04671ab68f3fefbeaa344c49149748f722287a81b19cd956b2332d07b8f6853") + "f04671ab68f3fefbeaa344c49149748f722287a81b19cd956b2332d07b8f6853" + ) val dummyKey: ECPublicKey = dummyPrivKey.publicKey @@ -49,7 +51,8 @@ object OracleTestUtil { attestationOpt = Some(sig.sig), outcomeOpt = Some(outcome), announcementSignature = SchnorrDigitalSignature( - "1efe41fa42ea1dcd103a0251929dd2b192d2daece8a4ce4d81f68a183b750d92d6f02d796965dc79adf4e7786e08f861a1ecc897afbba2dab9cff6eb0a81937e"), + "1efe41fa42ea1dcd103a0251929dd2b192d2daece8a4ce4d81f68a183b750d92d6f02d796965dc79adf4e7786e08f861a1ecc897afbba2dab9cff6eb0a81937e" + ), eventDescriptorTLV = EnumEventDescriptorV0TLV.dummy ) diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/TestUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/TestUtil.scala index 04d7051a4d..d0f45657f2 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/TestUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/TestUtil.scala @@ -51,10 +51,12 @@ object TestUtil { val p2pkhInputScriptAsm: List[ScriptToken] = List( BytesToPushOntoStack(71), ScriptConstant( - "3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01"), + "3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01" + ), BytesToPushOntoStack(33), ScriptConstant( - "02af7dad03e682fcd0427b5c24140c220ac9d8abe286c15f8cf5bf77eed19c3652") + "02af7dad03e682fcd0427b5c24140c220ac9d8abe286c15f8cf5bf77eed19c3652" + ) ) val p2pkhOutputScript = "1976a914e2e7c1ab3f807151e832dd1accb3d4f5d7d19b4b88ac" @@ -68,9 +70,10 @@ object TestUtil { BytesToPushOntoStack(20), ScriptConstant("e2e7c1ab3f807151e832dd1accb3d4f5d7d19b4b"), OP_EQUALVERIFY, - OP_CHECKSIG) + OP_CHECKSIG + ) - //tx id for p2sh inputs/outputs cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 + // tx id for p2sh inputs/outputs cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 val p2shInputScriptNotParsedAsm = "0 304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f001 512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" @@ -82,10 +85,12 @@ object TestUtil { OP_0, BytesToPushOntoStack(71), ScriptConstant( - "304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f001"), + "304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f001" + ), BytesToPushOntoStack(37), ScriptConstant( - "512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae") + "512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" + ) ) val p2shOutputScript = "17a914eda8ae08b5c9f973f49543e90a7c292367b3337c87" @@ -97,17 +102,18 @@ object TestUtil { OP_HASH160, BytesToPushOntoStack(20), ScriptConstant("eda8ae08b5c9f973f49543e90a7c292367b3337c"), - OP_EQUAL) + OP_EQUAL + ) - //https://btc.blockr.io/api/v1/tx/raw/791fe035d312dcf9196b48649a5c9a027198f623c0a5f5bd4cc311b8864dd0cf + // https://btc.blockr.io/api/v1/tx/raw/791fe035d312dcf9196b48649a5c9a027198f623c0a5f5bd4cc311b8864dd0cf val rawP2shInputScriptSigHashSingle = "fdfd0000483045022100dfcfafcea73d83e1c54d444a19fb30d17317f922c19e2ff92dcda65ad09cba24022001e7a805c5672c49b222c5f2f1e67bb01f87215fb69df184e7c16f66c1f87c290347304402204a657ab8358a2edb8fd5ed8a45f846989a43655d2e8f80566b385b8f5a70dab402207362f870ce40f942437d43b6b99343419b14fb18fa69bee801d696a39b3410b8034c695221023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f05611962103d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b802103ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df53ae" def p2shInputScriptSigHashSingle = ScriptSignature(rawP2shInputScriptSigHashSingle) - //p2sh script for a 2 of 2 - //https://tbtc.blockr.io/api/v1/tx/raw/2f18c646a2b2ee8ee1f295bb5a0f5cc51c5e820a123a14b0c0e170f9777518bb + // p2sh script for a 2 of 2 + // https://tbtc.blockr.io/api/v1/tx/raw/2f18c646a2b2ee8ee1f295bb5a0f5cc51c5e820a123a14b0c0e170f9777518bb val rawP2shInputScript2Of2 = "da0047304402207d764cb90c9fd84b74d33a47cf3a0ffead9ded98333776becd6acd32c4426dac02203905a0d064e7f53d07793e86136571b6e4f700c1cfb888174e84d78638335b8101483045022100906aaca39f022acd8b7a38fd2f92aca9e9f35cfeaee69a6f13e1d083ae18222602204c9ed96fc6c4de56fd85c679fc59c16ee1ccc80c42563b86174e1a506fc007c8014752210369d26ebd086523384a0f89f293d4c327a65fa73332d8efd1097cb35231295b832102480863e5c4a4e9763f5380c44fcfe6a3b7787397076cf9ea1049303a9d34f72152ae" @@ -121,29 +127,33 @@ object TestUtil { OP_0, BytesToPushOntoStack(71), ScriptConstant( - "304402207d764cb90c9fd84b74d33a47cf3a0ffead9ded98333776becd6acd32c4426dac02203905a0d064e7f53d07793e86136571b6e4f700c1cfb888174e84d78638335b8101"), + "304402207d764cb90c9fd84b74d33a47cf3a0ffead9ded98333776becd6acd32c4426dac02203905a0d064e7f53d07793e86136571b6e4f700c1cfb888174e84d78638335b8101" + ), BytesToPushOntoStack(72), ScriptConstant( - "3045022100906aaca39f022acd8b7a38fd2f92aca9e9f35cfeaee69a6f13e1d083ae18222602204c9ed96fc6c4de56fd85c679fc59c16ee1ccc80c42563b86174e1a506fc007c801"), + "3045022100906aaca39f022acd8b7a38fd2f92aca9e9f35cfeaee69a6f13e1d083ae18222602204c9ed96fc6c4de56fd85c679fc59c16ee1ccc80c42563b86174e1a506fc007c801" + ), BytesToPushOntoStack(71), OP_2, BytesToPushOntoStack(33), ScriptConstant( - "0369d26ebd086523384a0f89f293d4c327a65fa73332d8efd1097cb35231295b83"), + "0369d26ebd086523384a0f89f293d4c327a65fa73332d8efd1097cb35231295b83" + ), BytesToPushOntoStack(33), ScriptConstant( - "02480863e5c4a4e9763f5380c44fcfe6a3b7787397076cf9ea1049303a9d34f721"), + "02480863e5c4a4e9763f5380c44fcfe6a3b7787397076cf9ea1049303a9d34f721" + ), OP_2, OP_CHECKMULTISIG ) - //https://tbtc.blockr.io/api/v1/tx/raw/8f516300d4525f4a784a8c415d7b89768a9ddbe2cd0737a829c45930ce8e9bd6 + // https://tbtc.blockr.io/api/v1/tx/raw/8f516300d4525f4a784a8c415d7b89768a9ddbe2cd0737a829c45930ce8e9bd6 def rawP2SH2Of2CreditingTx = "0100000001fef43d6ed62f34bd1502ae0569c0c125cb484d183f887a2857ec112e548b5ba8000000006a473044022010a8b76add9224782f2ac741e32b0467c523d27632b594ae679da991975b882d022019138d13753bc7713a72c8a32f9cec8fee8c9475d6b2e386dc31e70936099c93012103f62a2ce04da197ba3efa3bcd9ae0a4021227d75f854c22bdf49c65107c3e1e7fffffffff01c80bcb000000000017a9148bee4cf71fbefe568b173dc69ec951ea3f7a05278700000000" def p2sh2Of2CreditingTx = Transaction(rawP2SH2Of2CreditingTx) - //p2sh input with large amount of signatures - //https://tbtc.blockr.io/api/v1/tx/raw/5d254a872c9197c683ea9111fb5c0e2e0f49280a89961c45b9fea76834d335fe + // p2sh input with large amount of signatures + // https://tbtc.blockr.io/api/v1/tx/raw/5d254a872c9197c683ea9111fb5c0e2e0f49280a89961c45b9fea76834d335fe val rawP2shInputScriptLargeSignature = "fd5e0200483045022100a077d4fe9a81411ecb796c254d8b4e0bc73ff86a42288bc3b3ecfa1ef26c00dd02202389bf96cf38c14c3a6ccb8c688339f3fd880b724322862547a8ee3b547a9df90147304402207c0692464998e7f3869f8501cdd25bbcd9d32b6fd34ae8aeae643b422a8dfd42022057eb16f8ca1f34e88babc9f8beb4c2521eb5c4dea41f8902a70d045f1c132a4401473044022024233923253c73569f4b34723a5495698bc124b099c5542a5997d13fba7d18a802203c317bddc070276c6f6c79cb3415413e608af30e4759e31b0d53eab3ca0acd4e014830450221009b9f0d8b945717d2fca3685093d547a3928d122b8894903ed51e2248303213bc022008b376422c9f2cd713b9d10b5b106d1c56c5893dcc01ae300253ed2234bdb63f014730440220257b57cb09386d82c4328461f8fe200c2f381d6b635e2a2f4ea40c8d945e9ec102201ec67d58d51a309af4d8896e9147a42944e9f9833a456f733ea5fa6954ed2fed014cf155210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae" @@ -159,30 +169,30 @@ object TestUtil { case _: ScriptSignature => throw new RuntimeException } - //txid on testnet 44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff - //this tx has multiple inputs and outputs + // txid on testnet 44e504f5b7649d215be05ad9f09026dee95201244a3b218013c504a6a49a26ff + // this tx has multiple inputs and outputs val rawTransaction = "01000000" + "02df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd040011b0000006a473044022040f91c48f4011bf2e2edb6621bfa8fb802241de939cb86f1872c99c580ef0fe402204fc27388bc525e1b655b5f5b35f9d601d28602432dd5672f29e0a47f5b8bbb26012102c114f376c98d12a0540c3a81ab99bb1c5234245c05e8239d09f48229f9ebf011ffffffff" + "df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd04001340000006b483045022100cf317c320d078c5b884c44e7488825dab5bcdf3f88c66314ac925770cd8773a7022033fde60d33cc2842ea73fce5d9cf4f8da6fadf414a75b7085efdcd300407f438012102605c23537b27b80157c770cd23e066cd11db3800d3066a38b9b592fc08ae9c70ffffffff" + "02c02b00000000000017a914b0b06365c482eb4eabe6e0630029fb8328ea098487e81c0000000000001976a914938da2b50fd6d8acdfa20e30df0e7d8092f0bc7588ac00000000" def transaction = Transaction(rawTransaction) - //txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 + // txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6 val rawTxInput = "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000" + "6f0047304402207df6dd8dad22d49c3c83d8031733c32a53719278eb7985d3b35b375d776f84f102207054f9209a1e87d55feafc90aa04c33008e5bae9191da22aeaa16efde96f41f00125512102b022902a0fdd71e831c37e4136c2754a59887be0618fb75336d7ab67e2982ff551ae" + "ffffffff" def txInput: TransactionInput = RawTransactionInputParser.read(rawTxInput) - //simple raw transaction with only one input and two outputs - //txid 92efdd5abb43efd4fe4f89bd080bcddd287a630e8cb6920388dd7880acf4c964 + // simple raw transaction with only one input and two outputs + // txid 92efdd5abb43efd4fe4f89bd080bcddd287a630e8cb6920388dd7880acf4c964 val simpleRawTransaction = "0100000001ccf318f0cbac588a680bbad075aebdda1f211c94ba28125b0f627f9248310db3000000006b4830450221008337ce3ce0c6ac0ab72509f889c1d52701817a2362d6357457b63e3bdedc0c0602202908963b9cf1a095ab3b34b95ce2bc0d67fb0f19be1cc5f7b3de0b3a325629bf01210241d746ca08da0a668735c3e01c1fa02045f2f399c5937079b6434b5a31dfe353ffffffff0210335d05000000001976a914b1d7591b69e9def0feb13254bace942923c7922d88ac48030000000000001976a9145e690c865c2f6f7a9710a474154ab1423abb5b9288ac00000000" def simpleTransaction = Transaction(simpleRawTransaction) - //parent to the 'simpleRawTransaction' val in this file. It is referenced by the input, - //which needs to have access to this tx to view the scriptPubKey - //txid b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + // parent to the 'simpleRawTransaction' val in this file. It is referenced by the input, + // which needs to have access to this tx to view the scriptPubKey + // txid b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc val parentSimpleRawTransaction = "0100000001cda741646fada7272b900719f7ac9d68d633d0e8aa9501eed3c90afbd323bd65" + "010000006a4730440220048e15422cf62349dc586ffb8c749d40280781edd5064ff27a5910ff5cf225a802206a82685dbc2cf195d" + @@ -191,12 +201,12 @@ object TestUtil { "017a914af575bd77c5ce7eba3bd9ce6f89774713ae62c798700000000" def parentSimpleTransaction = Transaction(parentSimpleRawTransaction) - //scriptPubKey taken from https://bitcoin.org/en/developer-reference#raw-transaction-format + // scriptPubKey taken from https://bitcoin.org/en/developer-reference#raw-transaction-format def rawScriptPubKey = rawP2PKHScriptPubKey def scriptPubKey = RawScriptPubKeyParser.read(rawScriptPubKey) - //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc - //ouptut is index 0 + // from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc + // ouptut is index 0 val rawP2PKHScriptPubKey = "1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac" def p2pkhScriptPubKey = ScriptPubKey(rawP2PKHScriptPubKey) @@ -204,7 +214,7 @@ object TestUtil { val rawP2SHScriptPubKey = "a9145780b80be32e117f675d6e0ada13ba799bf248e987" def p2shScriptPubKey = ScriptPubKey(rawP2SHScriptPubKey) - //https://tbtc.blockr.io/api/v1/tx/raw/bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 + // https://tbtc.blockr.io/api/v1/tx/raw/bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74 val rawScriptSig = "8b483045022100ad8e961fe3c22b2647d92b078f4c0cf81b3106ea5bf8b900ab8646aa4430216f022071d4edc2b5588be20ac4c2d07edd8ed069e10b2402d3dce2d3b835ccd075f283014104fa79182bbc26c708b5d9f36b8635947d4a834ea356cf612ede08395c295f962e0b1dc2557aba34188640e51a58ed547f2c89c8265cd0c04ff890d8435648746e" def scriptSig = ScriptSignature(rawScriptSig) @@ -224,7 +234,8 @@ object TestUtil { case p: PreExecutionScriptProgram => p case _ => throw new RuntimeException( - "this must be a script program that is pre execution") + "this must be a script program that is pre execution" + ) } def testProgramExecutionInProgress = @@ -254,8 +265,10 @@ object TestUtil { ScriptConstant("173014020002107777777777777777777777777777777701"), BytesToPushOntoStack(33), ScriptConstant( - "02af7dad03e682fcd0427b5c24140c220ac9d8abe286c15f8cf5bf77eed19c3652") - )) + "02af7dad03e682fcd0427b5c24140c220ac9d8abe286c15f8cf5bf77eed19c3652" + ) + ) + ) def multiSigScriptPubKeyHex = "695221025878e270211662a27181cf4d6ad4d2cf0e69a98a3815c086f587c7e9388d87182103fc85980e3fac1f3d8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906210215b5bd050869166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f53ae" diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/TransactionTestUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/TransactionTestUtil.scala index 32789d6b29..07ca3692f0 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/TransactionTestUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/util/TransactionTestUtil.scala @@ -29,32 +29,35 @@ trait TransactionTestUtil { "5221025878e270211662a27181cf4d6ad4d2cf0e69a98a3815c086f587c7e9388d87182103fc85980e3fac1f3d8a5c3223c3ef5bffc1bd42d2cc42add8c3899cc66e7f1906210215b5bd050869166a70a7341b4f216e268b7c6c7504576dcea2cce7d11cc9a35f53ae" def multiSignatureScriptPubKey = ScriptPubKey(rawMultiSignatureScriptPubKey) - /** First input of this raw tx is a spending a multisignature output - * the first input is signed for this tx + /** First input of this raw tx is a spending a multisignature output the first + * input is signed for this tx */ def rawSignedMultiSignatureTx = "0100000001d324b34c80c2e611b23c92ed1be31729b2856ae439d54b237a296d618425e912010000009300483045022100f5d203c0b36027ce61cd72ecd09b9629de029cd5cb34155c459f55999d7a08df02206db673c84556c202e5a5a354eca2bb6effeffff2fa040d34ecdbe642dc2219c001483045022100f0e0c53f1ebddb97407e801d90e5131f40dcab071168322454237b49f3bf74ca022069e2545cf9e2e7dc2c708be403f356c3d436fd498b68ef5f0c9138299547f14701ffffffff0140420f00000000001976a914edc96705498831b16782d439fa93164bc5c8db6f88ac00000000" - /** First input of this raw tx is a spending a multisignature output - * the first input is signed for this tx + /** First input of this raw tx is a spending a multisignature output the first + * input is signed for this tx */ def signedMultiSignatureTx = Transaction(rawSignedMultiSignatureTx) def bech32mAddr: Bech32mAddress = Bech32mAddress.fromString( - "tb1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q98lawz") + "tb1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q98lawz" + ) /** Mimics this test utility found in bitcoin core * https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/test/script_tests.cpp#L57 * @param scriptPubKey - * @return the transaction and the output index of the scriptPubKey + * @return + * the transaction and the output index of the scriptPubKey */ def buildCreditingTransaction( scriptPubKey: ScriptPubKey, - amount: Option[CurrencyUnit] = None): (Transaction, UInt32) = { - //this needs to be all zeros according to these 3 lines in bitcoin core - //https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/test/script_tests.cpp#L64 - //https://github.com/bitcoin/bitcoin/blob/80d1f2e48364f05b2cdf44239b3a1faa0277e58e/src/primitives/transaction.h#L32 - //https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/uint256.h#L40 + amount: Option[CurrencyUnit] = None + ): (Transaction, UInt32) = { + // this needs to be all zeros according to these 3 lines in bitcoin core + // https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/test/script_tests.cpp#L64 + // https://github.com/bitcoin/bitcoin/blob/80d1f2e48364f05b2cdf44239b3a1faa0277e58e/src/primitives/transaction.h#L32 + // https://github.com/bitcoin/bitcoin/blob/605c17844ea32b6d237db6d83871164dc7d59dab/src/uint256.h#L40 val outpoint = EmptyTransactionOutPoint val scriptSignature = ScriptSignature("020000") @@ -63,10 +66,12 @@ trait TransactionTestUtil { val output = TransactionOutput(amount.getOrElse(CurrencyUnits.zero), scriptPubKey) - val tx = BaseTransaction(TransactionConstants.version, - Seq(input), - Seq(output), - TransactionConstants.lockTime) + val tx = BaseTransaction( + TransactionConstants.version, + Seq(input), + Seq(output), + TransactionConstants.lockTime + ) (tx, UInt32.zero) } @@ -74,15 +79,16 @@ trait TransactionTestUtil { * @param creditingTx * @param scriptSignature * @param outputIndex - * @return the built spending transaction and the input index for the script signature + * @return + * the built spending transaction and the input index for the script + * signature */ def buildSpendingTransaction( creditingTx: Transaction, scriptSignature: ScriptSignature, outputIndex: UInt32, - witness: Option[(ScriptWitness, CurrencyUnit)] = None): ( - Transaction, - UInt32) = { + witness: Option[(ScriptWitness, CurrencyUnit)] = None + ): (Transaction, UInt32) = { /* CMutableTransaction txSpend; txSpend.nVersion = 1; @@ -107,17 +113,21 @@ trait TransactionTestUtil { case Some((scriptWitness, amount)) => val txWitness = TransactionWitness(Vector(scriptWitness)) val output = TransactionOutput(amount, EmptyScriptPubKey) - WitnessTransaction(TransactionConstants.version, - Seq(input), - Seq(output), - TransactionConstants.lockTime, - txWitness) + WitnessTransaction( + TransactionConstants.version, + Seq(input), + Seq(output), + TransactionConstants.lockTime, + txWitness + ) case None => val output = TransactionOutput(CurrencyUnits.zero, EmptyScriptPubKey) - BaseTransaction(TransactionConstants.version, - Seq(input), - Seq(output), - TransactionConstants.lockTime) + BaseTransaction( + TransactionConstants.version, + Seq(input), + Seq(output), + TransactionConstants.lockTime + ) } @@ -126,79 +136,77 @@ trait TransactionTestUtil { (tx, UInt32.zero) } - /** Returns a transaction, the input that is spending the output, and the inputIndex inside of the tx + /** Returns a transaction, the input that is spending the output, and the + * inputIndex inside of the tx * @return */ - def transactionWithSpendingInputAndCreditingOutput: ( - Transaction, - TransactionInput, - UInt32, - TransactionOutput) = { + def transactionWithSpendingInputAndCreditingOutput + : (Transaction, TransactionInput, UInt32, TransactionOutput) = { val spendingTx = TestUtil.simpleTransaction val creditingTx = TestUtil.parentSimpleTransaction val creditingOutput = TestUtil.parentSimpleTransaction.outputs( - spendingTx.inputs.head.previousOutput.vout.toInt) - //make sure the outpoint index and the outpoint txid are correct + spendingTx.inputs.head.previousOutput.vout.toInt + ) + // make sure the outpoint index and the outpoint txid are correct require(spendingTx.inputs.head.previousOutput.txId == creditingTx.txId) require(spendingTx.inputs.head.previousOutput.vout == UInt32.zero) (spendingTx, spendingTx.inputs.head, UInt32.zero, creditingOutput) } - def signedMultiSignatureTransaction: ( - Transaction, - Int, - ScriptPubKey, - Seq[ECPublicKeyBytes]) = { + def signedMultiSignatureTransaction + : (Transaction, Int, ScriptPubKey, Seq[ECPublicKeyBytes]) = { val key1 = ECPrivateKeyUtil.fromWIFToPrivateKey( - "cVLwRLTvz3BxDAWkvS3yzT9pUcTCup7kQnfT2smRjvmmm1wAP6QT") + "cVLwRLTvz3BxDAWkvS3yzT9pUcTCup7kQnfT2smRjvmmm1wAP6QT" + ) val key2 = ECPrivateKeyUtil.fromWIFToPrivateKey( - "cTine92s8GLpVqvebi8rYce3FrUYq78ZGQffBYCS1HmDPJdSTxUo") + "cTine92s8GLpVqvebi8rYce3FrUYq78ZGQffBYCS1HmDPJdSTxUo" + ) val key3 = ECPrivateKeyUtil.fromWIFToPrivateKey( - "cVHwXSPRZmL9adctwBwmn4oTZdZMbaCsR5XF6VznqMgcvt1FDDxg") - (signedMultiSignatureTx, - 0, - multiSignatureScriptPubKey, - Seq(key1.publicKeyBytes, key2.publicKeyBytes, key3.publicKeyBytes)) + "cVHwXSPRZmL9adctwBwmn4oTZdZMbaCsR5XF6VznqMgcvt1FDDxg" + ) + ( + signedMultiSignatureTx, + 0, + multiSignatureScriptPubKey, + Seq(key1.publicKeyBytes, key2.publicKeyBytes, key3.publicKeyBytes) + ) } /** Returns a p2sh transaction with its corresponding crediting output */ - def p2shTransactionWithSpendingInputAndCreditingOutput: ( - Transaction, - TransactionInput, - UInt32, - TransactionOutput) = { + def p2shTransactionWithSpendingInputAndCreditingOutput + : (Transaction, TransactionInput, UInt32, TransactionOutput) = { val creditingTx = TestUtil.p2sh2Of2CreditingTx val spendingTx = TestUtil.p2sh2Of2Tx val inputIndex = UInt32.zero val input = spendingTx.inputs(inputIndex.toInt) - (spendingTx, - input, - inputIndex, - creditingTx.outputs(input.previousOutput.vout.toInt)) + ( + spendingTx, + input, + inputIndex, + creditingTx.outputs(input.previousOutput.vout.toInt) + ) } - //https://tbtc.blockr.io/api/v1/tx/raw/d77d905fc29f86bc3db39fdb68cfcab4e35f677d4f2ec33ed749912e0fa5f385 + // https://tbtc.blockr.io/api/v1/tx/raw/d77d905fc29f86bc3db39fdb68cfcab4e35f677d4f2ec33ed749912e0fa5f385 def rawP2sh2Of3Transaction = "010000000197e355df4b040cdca3b5623864dfcd9b94cce06417a620e2826e81d6335186c300000000fc004730440220724714702c6c172dfb72dbc1536e3a7604b9fb5f9dcdf05d76c284010f97f75602200c0c749f2efc71234a752dddee42f38967a2c5eb725be3752c4d8c3a2e2403d60147304402200173f0628f05258829a71d62bfe3baaf48d9fa9f1b4c39355be74acc2db0cee6022067357b735da08fdc63546c81437b182e84ee505d7748cbcd32f8cb9098fb0df6014c69522102ab07ab88e8211f8d48820b78ca1276960e1d09ecdc5382afc59f17c660e01d7d210346d594bfc39dc5bc4a2afb62a8717bb049d1543289d78ceec533359e77d845092103c1d5b135b3b082dc20eab6ae7d39d80bb26b5fb33b8f1b4da72f995bca9fe05353aeffffffff02bbda02000000000017a91432f3a016b96be26f9cd088675012c26fca675cfc87a08601000000000017a9149fe9d38bb4054f1827285097f3ce7293030365ee8700000000" def p2sh2Of3Transaction = Transaction(rawP2sh2Of3Transaction) - //https://tbtc.blockr.io/api/v1/tx/raw/c3865133d6816e82e220a61764e0cc949bcddf643862b5a3dc0c044bdf55e397 + // https://tbtc.blockr.io/api/v1/tx/raw/c3865133d6816e82e220a61764e0cc949bcddf643862b5a3dc0c044bdf55e397 def rawP2sh2Of3CreditingTransaction = "01000000016f817a337d3b7c09a7d3484eaad5467730cb48404492968047a0877232a081d000000000fdfd0000473044022053b21ad6a9c63c36792fa9ccabcecaca90015ef5cf93515010fb2f55597b4498022045889d57c7eb01113b50a403287baa1202f7e6cf65ff74c04d1b2bac18f6622201483045022100cdbe4cf74116ef080b0251dc79c65fc94cb601466dcca46852aaf648af7c701302206330a9f97c952cf033faca3dd623aa8150e4f325e228244c737950d38abd7bde014c69522103ed9accffc87e17042feb7dcffb8af8231739aa6ee87a4fc09b5523b5997a295f210310d24963b6777568731efe17a4d06cfeb207b55d869ab641636468ec5e551889210393d6f0fad0c89c190b5a6ce77241e4ff416bc562003c9308394021707f0fd9bd53aeffffffff022e8204000000000017a914aa75a01abb09b58eedd4a97612056c94a3ceafcf87a0860100000000001976a914c810ad20630f02790741f5458f666798b86470c688ac00000000" def p2sh2Of3CreditingTransaction = Transaction(rawP2sh2Of3CreditingTransaction) - /** Returns a p2sh transaction that has 2 of 3 signatures with the creiditing output + /** Returns a p2sh transaction that has 2 of 3 signatures with the creiditing + * output * @return */ - def p2sh2Of3TransactionWithSpendingInputAndCreditingOutput: ( - Transaction, - TransactionInput, - UInt32, - TransactionOutput) = { + def p2sh2Of3TransactionWithSpendingInputAndCreditingOutput + : (Transaction, TransactionInput, UInt32, TransactionOutput) = { val inputIndex = UInt32.zero val input = p2sh2Of3Transaction.inputs(inputIndex.toInt) val output = @@ -207,74 +215,90 @@ trait TransactionTestUtil { } /** Builds a transaction with a non strict der encoded signature - * @return the transaction and the inputIndex of the non strict der encoded signature + * @return + * the transaction and the inputIndex of the non strict der encoded + * signature */ def transactionWithNonStrictDerSignature: (Transaction, UInt32) = { val (creditingTx, outputIndex) = buildCreditingTransaction( - TestUtil.scriptPubKey) + TestUtil.scriptPubKey + ) val (spendingTx, inputIndex) = buildSpendingTransaction( creditingTx, TestUtil.scriptSigNotStrictDerEncoded, - outputIndex) + outputIndex + ) (spendingTx, inputIndex) } /** Returns a valid transaction that spends a p2pkh output at the inputIndex * @return */ - def p2pkhTransactionWithCreditingScriptPubKey: ( - Transaction, - UInt32, - ScriptPubKey) = { + def p2pkhTransactionWithCreditingScriptPubKey + : (Transaction, UInt32, ScriptPubKey) = { val outputIndex = TestUtil.simpleTransaction.inputs.head.previousOutput.vout - (TestUtil.simpleTransaction, - UInt32.zero, - TestUtil.parentSimpleTransaction.outputs(outputIndex.toInt).scriptPubKey) + ( + TestUtil.simpleTransaction, + UInt32.zero, + TestUtil.parentSimpleTransaction.outputs(outputIndex.toInt).scriptPubKey + ) } - /** This transaction has one input which is set to EmptyTransactionInput - * The purpose of this transaction is a base transaction that can be used to manipulate - * the scriptSignature to be whatever we need it to be + /** This transaction has one input which is set to EmptyTransactionInput The + * purpose of this transaction is a base transaction that can be used to + * manipulate the scriptSignature to be whatever we need it to be * @return */ def testTransaction: Transaction = - BaseTransaction(EmptyTransaction.version, - Seq(EmptyTransactionInput), - Nil, - EmptyTransaction.lockTime) + BaseTransaction( + EmptyTransaction.version, + Seq(EmptyTransactionInput), + Nil, + EmptyTransaction.lockTime + ) /** Builds a dummy transaction that sends money to the given output */ def buildTransactionTo(output: TransactionOutput): Transaction = { - BaseTransaction(version = Int32.one, - inputs = Vector(EmptyTransactionInput), - outputs = Vector(output), - lockTime = TransactionConstants.lockTime) + BaseTransaction( + version = Int32.one, + inputs = Vector(EmptyTransactionInput), + outputs = Vector(output), + lockTime = TransactionConstants.lockTime + ) } def buildTransactionTo( output: TransactionOutput, - outPoint: TransactionOutPoint): Transaction = { - val input = TransactionInput(outPoint, - EmptyScriptSignature, - TransactionConstants.sequence) + outPoint: TransactionOutPoint + ): Transaction = { + val input = TransactionInput( + outPoint, + EmptyScriptSignature, + TransactionConstants.sequence + ) val inputs = Vector(input) - BaseTransaction(version = Int32.one, - inputs = inputs, - outputs = Vector(output), - lockTime = TransactionConstants.lockTime) + BaseTransaction( + version = Int32.one, + inputs = inputs, + outputs = Vector(output), + lockTime = TransactionConstants.lockTime + ) } def dummyTx( prevTxId: DoubleSha256Digest = DoubleSha256Digest.empty, scriptSig: ScriptSignature = EmptyScriptSignature, - spk: ScriptPubKey = EmptyScriptPubKey): Transaction = { + spk: ScriptPubKey = EmptyScriptPubKey + ): Transaction = { BaseTransaction( version = Int32.zero, inputs = Vector( - TransactionInput(outPoint = TransactionOutPoint(txId = prevTxId, - vout = UInt32.zero), - scriptSignature = scriptSig, - sequenceNumber = UInt32.zero)), + TransactionInput( + outPoint = TransactionOutPoint(txId = prevTxId, vout = UInt32.zero), + scriptSignature = scriptSig, + sequenceNumber = UInt32.zero + ) + ), outputs = Vector(TransactionOutput(CurrencyUnits.oneBTC, spk)), lockTime = UInt32.zero ) @@ -283,7 +307,8 @@ trait TransactionTestUtil { def dummyPSBT( prevTxId: DoubleSha256Digest = DoubleSha256Digest.empty, scriptSig: ScriptSignature = EmptyScriptSignature, - spk: ScriptPubKey = EmptyScriptPubKey): PSBT = { + spk: ScriptPubKey = EmptyScriptPubKey + ): PSBT = { PSBT.fromUnsignedTx(dummyTx(prevTxId, scriptSig, spk)) } diff --git a/testkit-core/src/main/scala/org/bitcoins/testkitcore/wallet/WalletTestUtil.scala b/testkit-core/src/main/scala/org/bitcoins/testkitcore/wallet/WalletTestUtil.scala index 500653ecc6..577d46e560 100644 --- a/testkit-core/src/main/scala/org/bitcoins/testkitcore/wallet/WalletTestUtil.scala +++ b/testkit-core/src/main/scala/org/bitcoins/testkitcore/wallet/WalletTestUtil.scala @@ -25,43 +25,52 @@ object WalletTestUtil { val hdCoinType: HDCoinType = HDCoinType.Testnet lazy val sampleTransaction: Transaction = Transaction( - "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000") + "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000" + ) - /** Useful if you want wallet test runs - * To use the same key values each time + /** Useful if you want wallet test runs To use the same key values each time */ lazy val sampleMnemonic = MnemonicCode.fromWords( - Vector("portion", - "uniform", - "owner", - "crime", - "duty", - "floor", - "sketch", - "stumble", - "outer", - "south", - "relax", - "car")) + Vector( + "portion", + "uniform", + "owner", + "crime", + "duty", + "floor", + "sketch", + "stumble", + "outer", + "south", + "relax", + "car" + ) + ) lazy val sampleSegwitPath = - SegWitHDPath(hdCoinType, - accountIndex = 0, - HDChainType.External, - addressIndex = 0) + SegWitHDPath( + hdCoinType, + accountIndex = 0, + HDChainType.External, + addressIndex = 0 + ) /** Sample legacy HD path */ - lazy val sampleLegacyPath = LegacyHDPath(hdCoinType, - accountIndex = 0, - HDChainType.Change, - addressIndex = 0) + lazy val sampleLegacyPath = LegacyHDPath( + hdCoinType, + accountIndex = 0, + HDChainType.Change, + addressIndex = 0 + ) lazy val sampleNestedSegwitPath: NestedSegWitHDPath = - NestedSegWitHDPath(hdCoinType, - accountIndex = 0, - HDChainType.External, - addressIndex = 0) + NestedSegWitHDPath( + hdCoinType, + accountIndex = 0, + HDChainType.External, + addressIndex = 0 + ) val defaultHdAccount: HDAccount = HDAccount(HDCoin(HDPurposes.SegWit, hdCoinType), 0) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSTestAppConfig.scala b/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSTestAppConfig.scala index f3ee330d43..39e295a179 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSTestAppConfig.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSTestAppConfig.scala @@ -40,8 +40,9 @@ object BitcoinSTestAppConfig { } } - def getNeutrinoTestConfig(config: Config*)(implicit - system: ActorSystem): BitcoinSAppConfig = { + def getNeutrinoTestConfig( + config: Config* + )(implicit system: ActorSystem): BitcoinSAppConfig = { val overrideConf = ConfigFactory.parseString { s""" |bitcoin-s { @@ -64,14 +65,16 @@ object BitcoinSTestAppConfig { /** @param pgUrl * @param config - * @param forceNamedWallet forces a wallet to have a name, if false there is a 50% chance the wallet will have a name + * @param forceNamedWallet + * forces a wallet to have a name, if false there is a 50% chance the + * wallet will have a name * @return */ def getNeutrinoWithEmbeddedDbTestConfig( pgUrl: () => Option[String], config: Vector[Config], - forceNamedWallet: Boolean = false)(implicit - system: ActorSystem): BitcoinSAppConfig = { + forceNamedWallet: Boolean = false + )(implicit system: ActorSystem): BitcoinSAppConfig = { val overrideConf = ConfigFactory .parseString { s""" @@ -91,20 +94,25 @@ object BitcoinSTestAppConfig { BitcoinSAppConfig( tmpDir(), - (overrideConf +: configWithEmbeddedDb(project = None, - pgUrl) +: config).toVector) + (overrideConf +: configWithEmbeddedDb( + project = None, + pgUrl + ) +: config).toVector + ) } /** @param pgUrl * @param config - * @param forceNamedWallet forces a wallet to have a name, if false there is a 50% chance the wallet will have a name + * @param forceNamedWallet + * forces a wallet to have a name, if false there is a 50% chance the + * wallet will have a name * @return */ def getMultiPeerNeutrinoWithEmbeddedDbTestConfig( pgUrl: () => Option[String], config: Vector[Config], - forceNamedWallet: Boolean = false)(implicit - system: ActorSystem): BitcoinSAppConfig = { + forceNamedWallet: Boolean = false + )(implicit system: ActorSystem): BitcoinSAppConfig = { val overrideConf = ConfigFactory .parseString { s""" @@ -125,12 +133,16 @@ object BitcoinSTestAppConfig { BitcoinSAppConfig( tmpDir(), - (overrideConf +: configWithEmbeddedDb(project = None, - pgUrl) +: config).toVector) + (overrideConf +: configWithEmbeddedDb( + project = None, + pgUrl + ) +: config).toVector + ) } - def getDLCOracleAppConfig(config: Config*)(implicit - ec: ExecutionContext): DLCOracleAppConfig = { + def getDLCOracleAppConfig( + config: Config* + )(implicit ec: ExecutionContext): DLCOracleAppConfig = { val overrideConf = KeyManagerTestUtil.aesPasswordOpt match { case Some(value) => ConfigFactory.parseString { @@ -147,7 +159,8 @@ object BitcoinSTestAppConfig { def getDLCOracleWithEmbeddedDbTestConfig( pgUrl: () => Option[String], - config: Config*)(implicit ec: ExecutionContext): DLCOracleAppConfig = { + config: Config* + )(implicit ec: ExecutionContext): DLCOracleAppConfig = { val overrideConf = KeyManagerTestUtil.aesPasswordOpt match { case Some(value) => ConfigFactory.parseString { @@ -161,8 +174,11 @@ object BitcoinSTestAppConfig { DLCOracleAppConfig( tmpDir(), - (overrideConf +: configWithEmbeddedDb(project = None, - pgUrl) +: config).toVector) + (overrideConf +: configWithEmbeddedDb( + project = None, + pgUrl + ) +: config).toVector + ) } sealed trait ProjectType @@ -179,21 +195,24 @@ object BitcoinSTestAppConfig { val all = List(Wallet, Node, Chain, Oracle, DLC, Test) } - /** Generates a Typesafe config with DBs set to memory - * databases for the given project (or all, if no - * project is given). This configuration can then be + /** Generates a Typesafe config with DBs set to memory databases for the given + * project (or all, if no project is given). This configuration can then be * given as a override to other configs. */ def configWithEmbeddedDb( project: Option[ProjectType], - pgUrl: () => Option[String]): Config = { + pgUrl: () => Option[String] + ): Config = { def pgConfigForProject(project: ProjectType): String = { val url = pgUrl().getOrElse( - throw new RuntimeException(s"Cannot get db url for $project")) + throw new RuntimeException(s"Cannot get db url for $project") + ) val parts = url.split(":") - require(parts.size >= 3 && parts(0) == "jdbc", - s"`$url` must be a valid JDBC URL") + require( + parts.size >= 3 && parts(0) == "jdbc", + s"`$url` must be a valid JDBC URL" + ) val str = parts(3) val endOfPortStr = str.indexOf('/') val (port, _) = str.splitAt(endOfPortStr) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/async/TestAsyncUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/async/TestAsyncUtil.scala index 23d9841f5b..94be0569b8 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/async/TestAsyncUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/async/TestAsyncUtil.scala @@ -14,14 +14,17 @@ abstract class TestAsyncUtil extends AsyncUtil with Serializable { counter: Int, maxTries: Int, stackTrace: Array[StackTraceElement], - mode: RetryMode)(implicit ec: ExecutionContext): Future[Unit] = { + mode: RetryMode + )(implicit ec: ExecutionContext): Future[Unit] = { val retryF = super - .retryUntilSatisfiedWithCounter(conditionF, - duration, - counter, - maxTries, - stackTrace, - mode) + .retryUntilSatisfiedWithCounter( + conditionF, + duration, + counter, + maxTries, + stackTrace, + mode + ) TestAsyncUtil.transformRetryToTestFailure(retryF) } @@ -29,14 +32,16 @@ abstract class TestAsyncUtil extends AsyncUtil with Serializable { object TestAsyncUtil extends TestAsyncUtil { - /** As opposed to the AsyncUtil in the rpc project, in the testkit, we can assume that - * TestAsyncUtil methods are being called from tests and as such, we want to trim the stack - * trace to exclude stack elements that occur before the beginning of a test. - * Additionally, we want to transform RpcRetryExceptions to TestFailedExceptions which - * conveniently mention the line that called the TestAsyncUtil method. + /** As opposed to the AsyncUtil in the rpc project, in the testkit, we can + * assume that TestAsyncUtil methods are being called from tests and as such, + * we want to trim the stack trace to exclude stack elements that occur + * before the beginning of a test. Additionally, we want to transform + * RpcRetryExceptions to TestFailedExceptions which conveniently mention the + * line that called the TestAsyncUtil method. */ - def transformRetryToTestFailure[T](fut: Future[T])(implicit - ec: ExecutionContext): Future[T] = { + def transformRetryToTestFailure[T]( + fut: Future[T] + )(implicit ec: ExecutionContext): Future[T] = { def transformRetry(err: Throwable): Throwable = { if (err.isInstanceOf[AsyncUtil.RpcRetryException]) { val retryErr = err.asInstanceOf[AsyncUtil.RpcRetryException] @@ -48,11 +53,13 @@ object TestAsyncUtil extends TestAsyncUtil { val path = stackElement.getClassName val line = stackElement.getLineNumber val pos = org.scalactic.source.Position(file, path, line) - val newErr = new TestFailedException({ _: StackDepthException => - Some(retryErr.message) - }, - None, - pos) + val newErr = new TestFailedException( + { _: StackDepthException => + Some(retryErr.message) + }, + None, + pos + ) newErr.setStackTrace(relevantStackTrace) newErr } else { @@ -60,9 +67,11 @@ object TestAsyncUtil extends TestAsyncUtil { } } - fut.transform({ elem: T => - elem - }, - transformRetry) + fut.transform( + { elem: T => + elem + }, + transformRetry + ) } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/BlockHeaderHelper.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/BlockHeaderHelper.scala index 84c115d9c3..9576bd49ea 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/BlockHeaderHelper.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/BlockHeaderHelper.scala @@ -13,14 +13,13 @@ import org.bitcoins.crypto.{ import scala.annotation.tailrec -/** Useful helper methods for getting - * block header related data for - * unit tests. +/** Useful helper methods for getting block header related data for unit tests. */ abstract class BlockHeaderHelper { /** The previous block to this was [[header2]] - * @see [[https://blockstream.info/block/0000000000000000002339403dedc19ae93f6f3912d364b42f568afa1ba7cfec height #566,093]] + * @see + * [[https://blockstream.info/block/0000000000000000002339403dedc19ae93f6f3912d364b42f568afa1ba7cfec height #566,093]] */ val header1: BlockHeader = { val hex = @@ -29,14 +28,17 @@ abstract class BlockHeaderHelper { } val header1Db: BlockHeaderDb = { - BlockHeaderDbHelper.fromBlockHeader(566093, - Pow.getBlockProof(header1), - header1) + BlockHeaderDbHelper.fromBlockHeader( + 566093, + Pow.getBlockProof(header1), + header1 + ) } /** The next block is [[header1]] after this block * 000000000000000000250c4b6909c0befc321610d4cd0229ad08ad45a3335eb4 - * @see [[https://blockstream.info/block/000000000000000000250c4b6909c0befc321610d4cd0229ad08ad45a3335eb4 #566,092]] + * @see + * [[https://blockstream.info/block/000000000000000000250c4b6909c0befc321610d4cd0229ad08ad45a3335eb4 #566,092]] */ val header2: BlockHeader = { val hex = @@ -50,15 +52,19 @@ abstract class BlockHeaderHelper { } lazy val twoValidHeaders: Vector[BlockHeader] = { - //https://blockstream.info/block/0000000000000000002339403dedc19ae93f6f3912d364b42f568afa1ba7cfec?expand + // https://blockstream.info/block/0000000000000000002339403dedc19ae93f6f3912d364b42f568afa1ba7cfec?expand val headers = Vector(header1, header2) headers } - /** Gives us a block header that has a bad prev hash (can't connect to anything */ + /** Gives us a block header that has a bad prev hash (can't connect to + * anything + */ lazy val badPrevHash: BlockHeader = { - BlockHeaderHelper.withPrevhash(bh = header1, - newPrevHash = DoubleSha256DigestBE.empty) + BlockHeaderHelper.withPrevhash( + bh = header1, + newPrevHash = DoubleSha256DigestBE.empty + ) } lazy val badNonce: BlockHeader = { @@ -72,40 +78,48 @@ abstract class BlockHeaderHelper { /** Modifies the given block header with the newPrevHash */ def withPrevhash( bh: BlockHeader, - newPrevHash: DoubleSha256DigestBE): BlockHeader = { - BlockHeader(version = bh.version, - previousBlockHash = newPrevHash.flip, - merkleRootHash = bh.merkleRootHash, - time = bh.time, - nBits = bh.nBits, - nonce = bh.nonce) + newPrevHash: DoubleSha256DigestBE + ): BlockHeader = { + BlockHeader( + version = bh.version, + previousBlockHash = newPrevHash.flip, + merkleRootHash = bh.merkleRootHash, + time = bh.time, + nBits = bh.nBits, + nonce = bh.nonce + ) } /** Modifies the given block header with the new nonce */ def withNonce(bh: BlockHeader, newNonce: UInt32): BlockHeader = { - BlockHeader(version = bh.version, - previousBlockHash = bh.previousBlockHash, - merkleRootHash = bh.merkleRootHash, - time = bh.time, - nBits = bh.nBits, - nonce = newNonce) + BlockHeader( + version = bh.version, + previousBlockHash = bh.previousBlockHash, + merkleRootHash = bh.merkleRootHash, + time = bh.time, + nBits = bh.nBits, + nonce = newNonce + ) } /** Modifies the given block header with the new nBits */ def withNBits(bh: BlockHeader, newNBits: UInt32): BlockHeader = { - BlockHeader(version = bh.version, - previousBlockHash = bh.previousBlockHash, - merkleRootHash = bh.merkleRootHash, - time = bh.time, - nBits = newNBits, - nonce = bh.nonce) + BlockHeader( + version = bh.version, + previousBlockHash = bh.previousBlockHash, + merkleRootHash = bh.merkleRootHash, + time = bh.time, + nBits = newNBits, + nonce = bh.nonce + ) } - /** Builds a block header on top the given prev header - * The only consensus requirement that this method adheres to - * with the returned [[org.bitcoins.chain.models.BlockHeaderDb]] is that - * 1. We reference the [[org.bitcoins.chain.models.BlockHeaderDb.blockHeader.hash]] correct - * 2. We increment the height of [[prevHeader]] by one + /** Builds a block header on top the given prev header The only consensus + * requirement that this method adheres to with the returned + * [[org.bitcoins.chain.models.BlockHeaderDb]] is that + * 1. We reference the + * [[org.bitcoins.chain.models.BlockHeaderDb.blockHeader.hash]] correct + * 2. We increment the height of [[prevHeader]] by one * @param prevHeader * @return */ @@ -116,25 +130,27 @@ abstract class BlockHeaderHelper { BlockHeader( version = Int32(5), previousBlockHash = prevHash, - //get random 32 bytes + // get random 32 bytes merkleRootHash = DoubleSha256Digest.fromBytes(ECPrivateKey.freshPrivateKey.bytes), time = prevHeader.time + UInt32.one, nBits = prevHeader.nBits, - //generate random uint32 for nonce + // generate random uint32 for nonce nonce = UInt32(Math.abs(scala.util.Random.nextInt() % UInt32.max.toLong)) ) } - //check if header meets pow requirement, if it doesn't generate another + // check if header meets pow requirement, if it doesn't generate another if (TipValidation.isBadNonce(blockHeader)) { buildNextHeader(prevHeader) } else { val chainWork = prevHeader.chainWork + Pow.getBlockProof(blockHeader) - BlockHeaderDbHelper.fromBlockHeader(prevHeader.height + 1, - chainWork, - blockHeader) + BlockHeaderDbHelper.fromBlockHeader( + prevHeader.height + 1, + chainWork, + blockHeader + ) } } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainDbUnitTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainDbUnitTest.scala index ad59f7013f..320d58637e 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainDbUnitTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainDbUnitTest.scala @@ -9,8 +9,10 @@ trait ChainDbUnitTest extends ChainUnitTest with EmbeddedPg { implicit override lazy val cachedChainConf: ChainAppConfig = { val memoryDb = - BitcoinSTestAppConfig.configWithEmbeddedDb(Some(ProjectType.Chain), - () => pgUrl()) + BitcoinSTestAppConfig.configWithEmbeddedDb( + Some(ProjectType.Chain), + () => pgUrl() + ) val chainConfig: ChainAppConfig = BitcoinSTestAppConfig.getNeutrinoTestConfig().chainConf chainConfig.withOverrides(memoryDb) @@ -18,8 +20,10 @@ trait ChainDbUnitTest extends ChainUnitTest with EmbeddedPg { override lazy val mainnetAppConfig: ChainAppConfig = { val memoryDb = - BitcoinSTestAppConfig.configWithEmbeddedDb(Some(ProjectType.Chain), - () => pgUrl()) + BitcoinSTestAppConfig.configWithEmbeddedDb( + Some(ProjectType.Chain), + () => pgUrl() + ) val mainnetConf = ConfigFactory.parseString("bitcoin-s.network = mainnet") val chainConfig: ChainAppConfig = BitcoinSTestAppConfig.getNeutrinoTestConfig(mainnetConf).chainConf diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainUnitTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainUnitTest.scala index c046c8c5e7..bd44a3b1d2 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainUnitTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/ChainUnitTest.scala @@ -47,8 +47,7 @@ trait ChainUnitTest with ChainFixtureHelper with CachedChainAppConfig { - /** Behaves exactly like the default conf, execpt - * network is set to mainnet + /** Behaves exactly like the default conf, execpt network is set to mainnet */ lazy val mainnetAppConfig: ChainAppConfig = { val mainnetConf = ConfigFactory.parseString("bitcoin-s.network = mainnet") @@ -75,34 +74,39 @@ trait ChainUnitTest val fixtureTag: ChainFixtureTag = ChainFixtureTag.from(stringTag) - makeDependentFixture(build = () => createFixture(fixtureTag), - destroy = destroyFixture)(test) + makeDependentFixture( + build = () => createFixture(fixtureTag), + destroy = destroyFixture + )(test) } /** This is a wrapper for a tagged test statement that adds a def inFixtured - * to replace the use of in, which only accepts a FixtureParam => Future[Assertion], - * whereas inFixtured accepts a PartialFunction and fails the test if it is not - * defined on the input. + * to replace the use of in, which only accepts a FixtureParam => + * Future[Assertion], whereas inFixtured accepts a PartialFunction and fails + * the test if it is not defined on the input. * * This is nothing more than syntactic sugar. * * This functionality is added using language.implicitConversions below */ final class SugaryItVerbStringTaggedAs( - itVerbStringTaggedAs: ItVerbStringTaggedAs) { + itVerbStringTaggedAs: ItVerbStringTaggedAs + ) { def inFixtured( - partialTestFun: PartialFunction[ - FixtureParam, - Future[compatible.Assertion]])(implicit - pos: org.scalactic.source.Position): Unit = { + partialTestFun: PartialFunction[FixtureParam, + Future[ + compatible.Assertion + ]] + )(implicit pos: org.scalactic.source.Position): Unit = { val testFun: FixtureParam => Future[compatible.Assertion] = { fixture: FixtureParam => partialTestFun.applyOrElse[FixtureParam, Future[Assertion]]( fixture, { _: FixtureParam => Future(fail("Incorrect tag/fixture for this test")) - }) + } + ) } itVerbStringTaggedAs.in(testFun)(pos) @@ -110,9 +114,9 @@ trait ChainUnitTest } /** This is a wrapper for a tagged test statement that adds a def inFixtured - * to replace the use of in, which only accepts a FixtureParam => Future[Assertion], - * whereas inFixtured accepts a PartialFunction and fails the test if it is not - * defined on the input. + * to replace the use of in, which only accepts a FixtureParam => + * Future[Assertion], whereas inFixtured accepts a PartialFunction and fails + * the test if it is not defined on the input. * * This is nothing more than syntactic sugar. * @@ -121,17 +125,19 @@ trait ChainUnitTest final class SugaryItVerbString(itVerbString: ItVerbString) { def inFixtured( - partialTestFun: PartialFunction[ - FixtureParam, - Future[compatible.Assertion]])(implicit - pos: org.scalactic.source.Position): Unit = { + partialTestFun: PartialFunction[FixtureParam, + Future[ + compatible.Assertion + ]] + )(implicit pos: org.scalactic.source.Position): Unit = { val testFun: FixtureParam => Future[compatible.Assertion] = { fixture: FixtureParam => partialTestFun.applyOrElse[FixtureParam, Future[Assertion]]( fixture, { _: FixtureParam => Future(fail("Incorrect tag/fixture for this test")) - }) + } + ) } itVerbString.in(testFun)(pos) @@ -141,77 +147,100 @@ trait ChainUnitTest import language.implicitConversions implicit def itVerbStringTaggedAsToSugaryItVerbStringTaggedAs( - itVerbStringTaggedAs: ItVerbStringTaggedAs): SugaryItVerbStringTaggedAs = + itVerbStringTaggedAs: ItVerbStringTaggedAs + ): SugaryItVerbStringTaggedAs = new SugaryItVerbStringTaggedAs(itVerbStringTaggedAs) implicit def itVerbStringToSugaryItVerbString( - itVerbString: ItVerbString): SugaryItVerbString = + itVerbString: ItVerbString + ): SugaryItVerbString = new SugaryItVerbString(itVerbString) - /** Fixture that creates a block header table - * with one row inserted into it, the [[org.bitcoins.core.protocol.blockchain.RegTestNetChainParams]] + /** Fixture that creates a block header table with one row inserted into it, + * the [[org.bitcoins.core.protocol.blockchain.RegTestNetChainParams]] * genesis block */ def withBlockHeaderDAO(test: OneArgAsyncTest): FutureOutcome = { - makeFixture(build = () => ChainUnitTest.createBlockHeaderDAO(), - destroy = () => ChainUnitTest.destroyChainApi())(test) + makeFixture( + build = () => ChainUnitTest.createBlockHeaderDAO(), + destroy = () => ChainUnitTest.destroyChainApi() + )(test) } /** Creates a compact filter DAO with zero rows in it */ def withCompactFilterHeaderDAO(test: OneArgAsyncTest): FutureOutcome = { - makeFixture(build = () => ChainUnitTest.createFilterHeaderDAO(), - destroy = () => ChainUnitTest.destroyChainApi())(test) + makeFixture( + build = () => ChainUnitTest.createFilterHeaderDAO(), + destroy = () => ChainUnitTest.destroyChainApi() + )(test) } /** Creates a compact filter DAO with zero rows in it */ def withCompactFilterDAO(test: OneArgAsyncTest): FutureOutcome = { - makeFixture(build = () => ChainUnitTest.createFilterDAO(), - destroy = () => ChainUnitTest.destroyChainApi())(test) + makeFixture( + build = () => ChainUnitTest.createFilterDAO(), + destroy = () => ChainUnitTest.destroyChainApi() + )(test) } def withPopulatedBlockHeaderDAO(test: OneArgAsyncTest): FutureOutcome = { - makeFixture(build = () => ChainUnitTest.createPopulatedBlockHeaderDAO(), - destroy = () => ChainUnitTest.destroyChainApi())(test) + makeFixture( + build = () => ChainUnitTest.createPopulatedBlockHeaderDAO(), + destroy = () => ChainUnitTest.destroyChainApi() + )(test) } def withChainStateDescriptorDAO(test: OneArgAsyncTest): FutureOutcome = { - makeFixture(build = () => ChainUnitTest.createChainStateDescriptorDAO(), - destroy = () => ChainUnitTest.destroyChainApi())(test) + makeFixture( + build = () => ChainUnitTest.createChainStateDescriptorDAO(), + destroy = () => ChainUnitTest.destroyChainApi() + )(test) } def withChainHandler(test: OneArgAsyncTest): FutureOutcome = { - makeFixture(() => ChainUnitTest.createChainHandler(), - () => ChainUnitTest.destroyChainApi())(test) + makeFixture( + () => ChainUnitTest.createChainHandler(), + () => ChainUnitTest.destroyChainApi() + )(test) } def withChainHandlerCached(test: OneArgAsyncTest): FutureOutcome = { - makeFixture(() => ChainUnitTest.createChainHandlerCached(), - () => ChainUnitTest.destroyChainApi())(test) + makeFixture( + () => ChainUnitTest.createChainHandlerCached(), + () => ChainUnitTest.destroyChainApi() + )(test) } def withChainHandlerGenesisFilter(test: OneArgAsyncTest): FutureOutcome = { - makeFixture(() => createChainHandlerWithGenesisFilter(), - () => ChainUnitTest.destroyChainApi())(test) + makeFixture( + () => createChainHandlerWithGenesisFilter(), + () => ChainUnitTest.destroyChainApi() + )(test) } def withChainHandlerCachedGenesisFilter( - test: OneArgAsyncTest): FutureOutcome = { - makeFixture(build = () => createChainHandlerCachedWithGenesisFilter(), - destroy = () => ChainUnitTest.destroyChainApi())(test) + test: OneArgAsyncTest + ): FutureOutcome = { + makeFixture( + build = () => createChainHandlerCachedWithGenesisFilter(), + destroy = () => ChainUnitTest.destroyChainApi() + )(test) } - /** Creates and populates BlockHeaderTable with block headers 562375 to 571375 */ + /** Creates and populates BlockHeaderTable with block headers 562375 to 571375 + */ def createPopulatedChainHandler(): Future[ChainHandler] = { for { blockHeaderDAO <- ChainUnitTest.createPopulatedBlockHeaderDAO() filterHeaderDAO <- ChainUnitTest.createPopulatedFilterHeaderDAO() filterDAO <- ChainUnitTest.createPopulatedFilterDAO() stateDAO = ChainStateDescriptorDAO() - chainHandler = ChainHandler.fromDatabase(blockHeaderDAO = blockHeaderDAO, - filterHeaderDAO = - filterHeaderDAO, - filterDAO = filterDAO, - stateDAO = stateDAO) + chainHandler = ChainHandler.fromDatabase( + blockHeaderDAO = blockHeaderDAO, + filterHeaderDAO = filterHeaderDAO, + filterDAO = filterDAO, + stateDAO = stateDAO + ) } yield chainHandler } @@ -220,31 +249,36 @@ trait ChainUnitTest chainHandler <- createChainHandler() filterHeaderChainApi <- chainHandler.processFilterHeader( ChainTestUtil.genesisFilterHeaderDb.filterHeader, - ChainTestUtil.genesisHeaderDb.hashBE) + ChainTestUtil.genesisHeaderDb.hashBE + ) filterChainApi <- filterHeaderChainApi.processFilter(ChainTestUtil.genesisFilterMessage) } yield filterChainApi.asInstanceOf[ChainHandler] } - def createChainHandlerCachedWithGenesisFilter(): Future[ - ChainHandlerCached] = { + def createChainHandlerCachedWithGenesisFilter() + : Future[ChainHandlerCached] = { for { chainHandler <- createChainHandlerCached() filterHeaderChainApi <- chainHandler.processFilterHeader( ChainTestUtil.genesisFilterHeaderDb.filterHeader, - ChainTestUtil.genesisHeaderDb.hashBE) + ChainTestUtil.genesisHeaderDb.hashBE + ) filterChainApi <- filterHeaderChainApi.processFilter(ChainTestUtil.genesisFilterMessage) } yield filterChainApi.asInstanceOf[ChainHandlerCached] } def withPopulatedChainHandler(test: OneArgAsyncTest): FutureOutcome = { - makeFixture(() => createPopulatedChainHandler(), - () => ChainUnitTest.destroyAllTables())(test) + makeFixture( + () => createPopulatedChainHandler(), + () => ChainUnitTest.destroyAllTables() + )(test) } def createChainHandlerWithBitcoindZmq(bitcoind: BitcoindRpcClient)(implicit - chainAppConfig: ChainAppConfig): Future[(ChainHandler, ZMQSubscriber)] = { + chainAppConfig: ChainAppConfig + ): Future[(ChainHandler, ZMQSubscriber)] = { val zmqRawBlockUriOpt: Option[InetSocketAddress] = bitcoind.instance.zmqConfig.rawBlock val handleRawBlock: Block => Unit = { block: Block => @@ -260,30 +294,35 @@ trait ChainUnitTest val socket = zmqRawBlockUriOpt.get val zmqSubscriber = - new ZMQSubscriber(socket = socket, - hashTxListener = None, - hashBlockListener = None, - rawTxListener = None, - rawBlockListener = Some(handleRawBlock)) + new ZMQSubscriber( + socket = socket, + hashTxListener = None, + hashBlockListener = None, + rawTxListener = None, + rawBlockListener = Some(handleRawBlock) + ) zmqSubscriber.start() val handlerWithGenesisHeaderF = - ChainUnitTest.setupHeaderTableWithGenesisHeader()(executionContext, - chainAppConfig) + ChainUnitTest.setupHeaderTableWithGenesisHeader()( + executionContext, + chainAppConfig + ) val chainHandlerF = handlerWithGenesisHeaderF.map(_._1) - //generate a block and make sure we see it so we know the subscription is complete + // generate a block and make sure we see it so we know the subscription is complete val subscribedF = for { chainHandler <- chainHandlerF addr <- bitcoind.getNewAddress hash +: _ <- bitcoind.generateToAddress(1, addr) - //wait until we see the hash, to make sure the subscription is started + // wait until we see the hash, to make sure the subscription is started _ <- AsyncUtil.retryUntilSatisfiedF( () => { chainHandler.getHeader(hash).map(_.isDefined) }, - 1.second) + 1.second + ) } yield (chainHandler, zmqSubscriber) subscribedF } @@ -292,32 +331,40 @@ trait ChainUnitTest BitcoinSFixture.composeBuildersAndWrap( () => BitcoinSFixture.createBitcoind(), createChainHandlerWithBitcoindZmq, - BitcoindChainHandlerViaZmq.apply)(executionContext)() + BitcoindChainHandlerViaZmq.apply + )(executionContext)() } def destroyBitcoindChainHandlerViaZmq( - bitcoindChainHandler: BitcoindChainHandlerViaZmq): Future[Unit] = { + bitcoindChainHandler: BitcoindChainHandlerViaZmq + ): Future[Unit] = { - //piggy back off of rpc destructor + // piggy back off of rpc destructor val rpc = chain.fixture.BitcoindBaseVersionChainHandlerViaRpc( bitcoindChainHandler.bitcoindRpc, - bitcoindChainHandler.chainHandler) + bitcoindChainHandler.chainHandler + ) ChainUnitTest.destroyBitcoindChainApiViaRpc(rpc).map { _ => bitcoindChainHandler.zmqSubscriber.stop() } } - /** Creates a [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] that is linked to our [[org.bitcoins.chain.blockchain.ChainHandler ChainHandler]] - * via a [[org.bitcoins.zmq.ZMQSubscriber zmq]]. This means messages are passed between bitcoin and our chain handler - * with a zmq pub/sub message passing - * @param test the test to be executed with bitcoind and chain handler via zmq + /** Creates a + * [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] + * that is linked to our + * [[org.bitcoins.chain.blockchain.ChainHandler ChainHandler]] via a + * [[org.bitcoins.zmq.ZMQSubscriber zmq]]. This means messages are passed + * between bitcoin and our chain handler with a zmq pub/sub message passing + * @param test + * the test to be executed with bitcoind and chain handler via zmq * @param system * @return */ def withBitcoindChainHandlerViaZmq(test: OneArgAsyncTest)(implicit system: ActorSystem, - chainAppConfig: ChainAppConfig): FutureOutcome = { + chainAppConfig: ChainAppConfig + ): FutureOutcome = { val builder: () => Future[BitcoindChainHandlerViaZmq] = BitcoinSFixture.composeBuildersAndWrap( builder = () => BitcoinSFixture.createBitcoind(), @@ -330,8 +377,9 @@ trait ChainUnitTest makeDependentFixture(builder, destroyBitcoindChainHandlerViaZmq)(test) } - def withBitcoindChainHandlerViaRpc(test: OneArgAsyncTest)(implicit - system: ActorSystem): FutureOutcome = { + def withBitcoindChainHandlerViaRpc( + test: OneArgAsyncTest + )(implicit system: ActorSystem): FutureOutcome = { val builder: () => Future[BitcoindBaseVersionChainHandlerViaRpc] = { () => BitcoinSFixture .createBitcoind() @@ -339,13 +387,15 @@ trait ChainUnitTest } makeDependentFixture(builder, ChainUnitTest.destroyBitcoindChainApiViaRpc)( - test) + test + ) } final def processHeaders( processorF: Future[ChainApi], headers: Vector[BlockHeader], - height: Int): Future[Assertion] = { + height: Int + ): Future[Assertion] = { def processedHeadersF = for { @@ -354,30 +404,34 @@ trait ChainUnitTest FutureUtil.foldLeftAsync(chainApi, headers.grouped(2000).toVector)( (chainApi, headers) => chainApi.processHeaders(headers)) } yield { - FutureUtil.foldLeftAsync((Option.empty[BlockHeaderDb], - height, - Vector.empty[Future[Assertion]]), - headers) { - case ((prevHeaderDbOpt, height, assertions), header) => - for { - headerOpt <- chainApiWithHeaders.getHeader(header.hashBE) - } yield { - val chainWork = prevHeaderDbOpt match { - case None => Pow.getBlockProof(header) - case Some(prevHeader) => - prevHeader.chainWork + Pow.getBlockProof(header) - } - - val expectedBlockHeaderDb = - BlockHeaderDbHelper.fromBlockHeader(height, chainWork, header) - - val newHeight = height + 1 - - val newAssertions = assertions :+ Future( - assert(headerOpt.contains(expectedBlockHeaderDb))) - - (Some(expectedBlockHeaderDb), newHeight, newAssertions) + FutureUtil.foldLeftAsync( + ( + Option.empty[BlockHeaderDb], + height, + Vector.empty[Future[Assertion]] + ), + headers + ) { case ((prevHeaderDbOpt, height, assertions), header) => + for { + headerOpt <- chainApiWithHeaders.getHeader(header.hashBE) + } yield { + val chainWork = prevHeaderDbOpt match { + case None => Pow.getBlockProof(header) + case Some(prevHeader) => + prevHeader.chainWork + Pow.getBlockProof(header) } + + val expectedBlockHeaderDb = + BlockHeaderDbHelper.fromBlockHeader(height, chainWork, header) + + val newHeight = height + 1 + + val newAssertions = assertions :+ Future( + assert(headerOpt.contains(expectedBlockHeaderDb)) + ) + + (Some(expectedBlockHeaderDb), newHeight, newAssertions) + } } } @@ -393,7 +447,8 @@ trait ChainUnitTest /** Builds two competing headers that are built from the same parent */ private def buildCompetingHeaders( - parent: BlockHeaderDb): (BlockHeader, BlockHeader) = { + parent: BlockHeaderDb + ): (BlockHeader, BlockHeader) = { val newHeaderCandidate1 = BlockHeaderHelper.buildNextHeader(parent) @@ -406,9 +461,12 @@ trait ChainUnitTest } } - /** Builds two competing headers off of the [[ChainHandler.getBestBlockHash best chain tip]] */ + /** Builds two competing headers off of the + * [[ChainHandler.getBestBlockHash best chain tip]] + */ def buildChainHandlerCompetingHeaders( - chainHandler: ChainHandler): Future[ReorgFixtureChainApi] = { + chainHandler: ChainHandler + ): Future[ReorgFixtureChainApi] = { for { oldBestTip <- chainHandler.getBestBlockHeader() (newHeaderB, newHeaderC) = buildCompetingHeaders(oldBestTip) @@ -417,29 +475,35 @@ trait ChainUnitTest newHeaderDbB <- newChainApi.getHeader(newHeaderB.hashBE) newHeaderDbC <- newChainApi2.getHeader(newHeaderC.hashBE) } yield { - ReorgFixtureChainApi(newChainApi2, - newHeaderDbB.get, - newHeaderDbC.get, - oldBestTip) + ReorgFixtureChainApi( + newChainApi2, + newHeaderDbB.get, + newHeaderDbC.get, + oldBestTip + ) } } /** Builds two competing headers off of [[BlockHeaderDAO.chainTips]]. */ def buildBlockHeaderDAOCompetingHeaders( - blockHeaderDAO: BlockHeaderDAO): Future[ReorgFixtureBlockHeaderDAO] = { - val handler = ChainHandler.fromDatabase(blockHeaderDAO, - CompactFilterHeaderDAO(), - CompactFilterDAO(), - ChainStateDescriptorDAO()) + blockHeaderDAO: BlockHeaderDAO + ): Future[ReorgFixtureBlockHeaderDAO] = { + val handler = ChainHandler.fromDatabase( + blockHeaderDAO, + CompactFilterHeaderDAO(), + CompactFilterDAO(), + ChainStateDescriptorDAO() + ) val chainFixtureF = buildChainHandlerCompetingHeaders(handler) for { chainFixture <- chainFixtureF } yield { - ReorgFixtureBlockHeaderDAO(blockHeaderDAO = blockHeaderDAO, - headerDb1 = chainFixture.headerDb1, - headerDb2 = chainFixture.headerDb2, - oldBestBlockHeader = - chainFixture.oldBestBlockHeader) + ReorgFixtureBlockHeaderDAO( + blockHeaderDAO = blockHeaderDAO, + headerDb1 = chainFixture.headerDb1, + headerDb2 = chainFixture.headerDb2, + oldBestBlockHeader = chainFixture.oldBestBlockHeader + ) } } } @@ -453,7 +517,8 @@ object ChainUnitTest extends ChainVerificationLogger { def createChainHandler()(implicit ec: ExecutionContext, - appConfig: ChainAppConfig): Future[ChainHandler] = { + appConfig: ChainAppConfig + ): Future[ChainHandler] = { val handlerWithGenesisHeaderF = ChainUnitTest.setupHeaderTableWithGenesisHeader() for { @@ -464,7 +529,8 @@ object ChainUnitTest extends ChainVerificationLogger { def createChainHandlerCached()(implicit ec: ExecutionContext, - appConfig: ChainAppConfig): Future[ChainHandlerCached] = { + appConfig: ChainAppConfig + ): Future[ChainHandlerCached] = { val handlerWithGenesisHeaderF = ChainUnitTest.setupHeaderTableWithGenesisHeader() @@ -474,7 +540,8 @@ object ChainUnitTest extends ChainVerificationLogger { def createBlockHeaderDAO()(implicit ec: ExecutionContext, - appConfig: ChainAppConfig): Future[BlockHeaderDAO] = { + appConfig: ChainAppConfig + ): Future[BlockHeaderDAO] = { val handlerWithGenesisHeaderF = ChainUnitTest.setupHeaderTableWithGenesisHeader() @@ -484,41 +551,48 @@ object ChainUnitTest extends ChainVerificationLogger { def createChainStateDescriptorDAO()(implicit ec: ExecutionContext, - appConfig: ChainAppConfig): Future[ChainStateDescriptorDAO] = { + appConfig: ChainAppConfig + ): Future[ChainStateDescriptorDAO] = { appConfig.migrate() Future.successful(ChainStateDescriptorDAO()) } def createFilterHeaderDAO()(implicit appConfig: ChainAppConfig, - ec: ExecutionContext): Future[CompactFilterHeaderDAO] = { + ec: ExecutionContext + ): Future[CompactFilterHeaderDAO] = { appConfig.migrate() Future.successful(CompactFilterHeaderDAO()) } def createPopulatedFilterHeaderDAO()(implicit appConfig: ChainAppConfig, - ec: ExecutionContext): Future[CompactFilterHeaderDAO] = { + ec: ExecutionContext + ): Future[CompactFilterHeaderDAO] = { createFilterHeaderDAO() } def createFilterDAO()(implicit appConfig: ChainAppConfig, - ec: ExecutionContext): Future[CompactFilterDAO] = { + ec: ExecutionContext + ): Future[CompactFilterDAO] = { appConfig.migrate() Future.successful(CompactFilterDAO()) } def createPopulatedFilterDAO()(implicit appConfig: ChainAppConfig, - ec: ExecutionContext): Future[CompactFilterDAO] = { + ec: ExecutionContext + ): Future[CompactFilterDAO] = { createFilterDAO() } - /** Creates and populates BlockHeaderTable with block headers 562375 to 571375 */ + /** Creates and populates BlockHeaderTable with block headers 562375 to 571375 + */ def createPopulatedBlockHeaderDAO()(implicit appConfig: ChainAppConfig, - ec: ExecutionContext): Future[BlockHeaderDAO] = { + ec: ExecutionContext + ): Future[BlockHeaderDAO] = { // The height of the first block in the json file val OFFSET: Int = FIRST_BLOCK_HEIGHT @@ -543,9 +617,11 @@ object ChainUnitTest extends ChainVerificationLogger { prevHeader.chainWork + Pow.getBlockProof(header) } - val newHeader = BlockHeaderDbHelper.fromBlockHeader(height + OFFSET, - chainWork, - header) + val newHeader = BlockHeaderDbHelper.fromBlockHeader( + height + OFFSET, + chainWork, + header + ) prevHeaderOpt = Some(newHeader) newHeader } @@ -554,8 +630,8 @@ object ChainUnitTest extends ChainVerificationLogger { def splitIntoBatches( batchSize: Int, dbHeaders: Vector[BlockHeaderDb], - batchesSoFar: Vector[Vector[BlockHeaderDb]]): Vector[ - Vector[BlockHeaderDb]] = { + batchesSoFar: Vector[Vector[BlockHeaderDb]] + ): Vector[Vector[BlockHeaderDb]] = { if (dbHeaders.isEmpty) { batchesSoFar } else if (dbHeaders.length < batchSize) { @@ -568,20 +644,22 @@ object ChainUnitTest extends ChainVerificationLogger { } } - val batchedDbHeaders = splitIntoBatches(batchSize = 500, - dbHeaders = dbHeaders, - batchesSoFar = Vector.empty) + val batchedDbHeaders = splitIntoBatches( + batchSize = 500, + dbHeaders = dbHeaders, + batchesSoFar = Vector.empty + ) for { _ <- ChainUnitTest.setupAllTables() chainHandler <- ChainUnitTest.makeChainHandler() _ <- batchedDbHeaders.foldLeft( - Future.successful[Vector[BlockHeaderDb]](Vector.empty)) { - case (fut, batch) => - for { - _ <- fut - headers <- chainHandler.blockHeaderDAO.createAll(batch) - } yield headers + Future.successful[Vector[BlockHeaderDb]](Vector.empty) + ) { case (fut, batch) => + for { + _ <- fut + headers <- chainHandler.blockHeaderDAO.createAll(batch) + } yield headers } } yield { chainHandler.blockHeaderDAO @@ -591,8 +669,8 @@ object ChainUnitTest extends ChainVerificationLogger { def createChainApiWithBitcoindRpc(bitcoind: BitcoindRpcClient)(implicit ec: ExecutionContext, - chainAppConfig: ChainAppConfig): Future[ - BitcoindBaseVersionChainHandlerViaRpc] = { + chainAppConfig: ChainAppConfig + ): Future[BitcoindBaseVersionChainHandlerViaRpc] = { val handlerWithGenesisHeaderF = ChainUnitTest.setupHeaderTableWithGenesisHeader() @@ -604,9 +682,11 @@ object ChainUnitTest extends ChainVerificationLogger { } def destroyBitcoindChainApiViaRpc( - bitcoindChainHandler: BitcoindBaseVersionChainHandlerViaRpc)(implicit + bitcoindChainHandler: BitcoindBaseVersionChainHandlerViaRpc + )(implicit system: ActorSystem, - chainAppConfig: ChainAppConfig): Future[Unit] = { + chainAppConfig: ChainAppConfig + ): Future[Unit] = { import system.dispatcher val stopBitcoindF = BitcoindRpcTestUtil.stopServer(bitcoindChainHandler.bitcoindRpc) @@ -618,14 +698,16 @@ object ChainUnitTest extends ChainVerificationLogger { } yield () } - def destroyBitcoind(bitcoind: BitcoindRpcClient)(implicit - system: ActorSystem): Future[Unit] = { + def destroyBitcoind( + bitcoind: BitcoindRpcClient + )(implicit system: ActorSystem): Future[Unit] = { BitcoindRpcTestUtil.stopServer(bitcoind) } def setupAllTables()(implicit appConfig: ChainAppConfig, - ec: ExecutionContext): Future[Unit] = + ec: ExecutionContext + ): Future[Unit] = Future { appConfig.migrate() () @@ -633,7 +715,8 @@ object ChainUnitTest extends ChainVerificationLogger { def destroyAllTables()(implicit appConfig: ChainAppConfig, - ec: ExecutionContext): Future[Unit] = + ec: ExecutionContext + ): Future[Unit] = for { _ <- appConfig.dropTable("flyway_schema_history") _ <- appConfig.dropAll() @@ -641,8 +724,8 @@ object ChainUnitTest extends ChainVerificationLogger { def setupHeaderTableWithGenesisHeader()(implicit ec: ExecutionContext, - appConfig: ChainAppConfig): Future[ - (ChainHandlerCached, BlockHeaderDb)] = { + appConfig: ChainAppConfig + ): Future[(ChainHandlerCached, BlockHeaderDb)] = { val tableSetupF = setupAllTables() val genesisHeaderF = tableSetupF.flatMap { _ => @@ -650,7 +733,8 @@ object ChainUnitTest extends ChainVerificationLogger { for { chainHandler <- chainHandlerF genHeader <- chainHandler.blockHeaderDAO.upsert( - ChainTestUtil.genesisHeaderDb) + ChainTestUtil.genesisHeaderDb + ) } yield genHeader } @@ -662,24 +746,28 @@ object ChainUnitTest extends ChainVerificationLogger { def makeChainHandler()(implicit appConfig: ChainAppConfig, - ec: ExecutionContext): Future[ChainHandlerCached] = { + ec: ExecutionContext + ): Future[ChainHandlerCached] = { lazy val blockHeaderDAO = BlockHeaderDAO() lazy val filterHeaderDAO = CompactFilterHeaderDAO() lazy val filterDAO = CompactFilterDAO() lazy val stateDAO = ChainStateDescriptorDAO() - ChainHandlerCached.fromDatabase(blockHeaderDAO = blockHeaderDAO, - filterHeaderDAO = filterHeaderDAO, - filterDAO = filterDAO, - stateDAO = stateDAO) + ChainHandlerCached.fromDatabase( + blockHeaderDAO = blockHeaderDAO, + filterHeaderDAO = filterHeaderDAO, + filterDAO = filterDAO, + stateDAO = stateDAO + ) } /** Syncs the given chain handler to the given bitcoind */ def syncFromBitcoind(bitcoind: BitcoindRpcClient, chainHandler: ChainHandler)( - implicit ec: ExecutionContext): Future[ChainApi] = { - //sync headers - //first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions + implicit ec: ExecutionContext + ): Future[ChainApi] = { + // sync headers + // first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions val getBestBlockHashFunc = { () => bitcoind.getBestBlockHash() } @@ -691,12 +779,13 @@ object ChainUnitTest extends ChainVerificationLogger { ChainSync.sync(chainHandler, getBlockHeaderFunc, getBestBlockHashFunc) } - /** Destroys the chain api, but leaves the bitcoind instance running - * so we can cache it + /** Destroys the chain api, but leaves the bitcoind instance running so we can + * cache it */ def destroyChainApi()(implicit system: ActorSystem, - chainAppConfig: ChainAppConfig): Future[Unit] = { + chainAppConfig: ChainAppConfig + ): Future[Unit] = { import system.dispatcher for { _ <- ChainUnitTest.destroyAllTables() @@ -707,7 +796,8 @@ object ChainUnitTest extends ChainVerificationLogger { def buildNHeaders(chainHandler: ChainHandler, target: Int)(implicit ec: ExecutionContext, - mat: Materializer): Future[Unit] = { + mat: Materializer + ): Future[Unit] = { val bestHeaderF = chainHandler.getBestBlockHeader() val builtHeaderDbsF: Future[Vector[BlockHeaderDb]] = bestHeaderF .flatMap { bestHeader => diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/MockChainQueryApi.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/MockChainQueryApi.scala index 9d367318b8..7a86587466 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/MockChainQueryApi.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/MockChainQueryApi.scala @@ -16,11 +16,13 @@ object MockChainQueryApi extends ChainQueryApi { // This is a random block on testnet val testBlockHash: DoubleSha256DigestBE = DoubleSha256DigestBE.fromHex( - "00000000496dcc754fabd97f3e2df0a7337eab417d75537fecf97a7ebb0e7c75") + "00000000496dcc754fabd97f3e2df0a7337eab417d75537fecf97a7ebb0e7c75" + ) /** Gets the height of the given block */ override def getBlockHeight( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = { + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = { if (blockHash == testBlockHash) { Future.successful(Some(1)) } else if ( @@ -36,7 +38,8 @@ object MockChainQueryApi extends ChainQueryApi { /** Gets number of confirmations for the given block hash */ override def getNumberOfConfirmations( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = { + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = { if (blockHash == testBlockHash) { Future.successful(Some(6)) } else FutureUtil.none @@ -51,7 +54,8 @@ object MockChainQueryApi extends ChainQueryApi { override def getFiltersBetweenHeights( startHeight: Int, - endHeight: Int): Future[Vector[FilterResponse]] = + endHeight: Int + ): Future[Vector[FilterResponse]] = Future.successful { import scodec.bits._ @@ -85,10 +89,13 @@ object MockChainQueryApi extends ChainQueryApi { hex"c14d41b2d5aefaf539e989f7fa097eac657c70b975c56e26b73fb9401ce3" ++ hex"81502f0883d52c6a3bcc956e0ea1787f0717d0205fecfe55b01edb1ac0" Vector( - FilterResponse(compactFilter = BlockFilter - .fromBytes(filterBytes, testBlockHash.flip), - blockHash = testBlockHash, - blockHeight = 1)) + FilterResponse( + compactFilter = BlockFilter + .fromBytes(filterBytes, testBlockHash.flip), + blockHash = testBlockHash, + blockHeight = 1 + ) + ) } override def epochSecondToBlockHeight(time: Long): Future[Int] = diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/SyncUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/SyncUtil.scala index ed61cd4ef7..c16e2eeddb 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/SyncUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/SyncUtil.scala @@ -22,51 +22,65 @@ import org.bitcoins.wallet.sync.WalletSync import scala.concurrent.{ExecutionContext, Future} -/** Useful utilities to use in the chain project for syncing things against bitcoind */ +/** Useful utilities to use in the chain project for syncing things against + * bitcoind + */ abstract class SyncUtil extends BitcoinSLogger { - /** Creates a function that will retrun bitcoin's best block hash when called */ + /** Creates a function that will retrun bitcoin's best block hash when called + */ def getBestBlockHashFunc( - bitcoind: BitcoindRpcClient): () => Future[DoubleSha256DigestBE] = { () => + bitcoind: BitcoindRpcClient + ): () => Future[DoubleSha256DigestBE] = { () => bitcoind.getBestBlockHash() } - /** Creates a function that you can pass a hash to and it returns the block header */ + /** Creates a function that you can pass a hash to and it returns the block + * header + */ def getBlockHeaderFunc(bitcoind: BitcoindRpcClient)(implicit - ec: ExecutionContext): DoubleSha256DigestBE => Future[BlockHeader] = { + ec: ExecutionContext + ): DoubleSha256DigestBE => Future[BlockHeader] = { hash: DoubleSha256DigestBE => bitcoind.getBlockHeader(hash).map(_.blockHeader) } - /** Creates a function that you can pass a block header to and it's return's it's [[GolombFilter]] */ + /** Creates a function that you can pass a block header to and it's return's + * it's [[GolombFilter]] + */ def getFilterFunc(bitcoind: BlockchainRpc, filterType: FilterType)(implicit - ec: ExecutionContext): BlockHeader => Future[FilterWithHeaderHash] = { - case header: BlockHeader => - val prevFilterResultF = - bitcoind.getBlockFilter(header.hashBE, filterType) - prevFilterResultF.map { case GetBlockFilterResult(filter, header) => - FilterWithHeaderHash(filter, header) - } + ec: ExecutionContext + ): BlockHeader => Future[FilterWithHeaderHash] = { case header: BlockHeader => + val prevFilterResultF = + bitcoind.getBlockFilter(header.hashBE, filterType) + prevFilterResultF.map { case GetBlockFilterResult(filter, header) => + FilterWithHeaderHash(filter, header) + } } def getBlockFunc( - bitcoind: BitcoindRpcClient): DoubleSha256DigestBE => Future[Block] = { + bitcoind: BitcoindRpcClient + ): DoubleSha256DigestBE => Future[Block] = { bitcoind.getBlockRaw(_: DoubleSha256DigestBE) } - def getNodeApi(bitcoindRpcClient: BitcoindRpcClient)(implicit - ec: ExecutionContext): NodeApi = { + def getNodeApi( + bitcoindRpcClient: BitcoindRpcClient + )(implicit ec: ExecutionContext): NodeApi = { new NodeApi { override def broadcastTransactions( - transactions: Vector[Transaction]): Future[Unit] = { + transactions: Vector[Transaction] + ): Future[Unit] = { bitcoindRpcClient.broadcastTransactions(transactions) } - /** Request the underlying node to download the given blocks from its peers and feed the blocks to [[org.bitcoins.node.NodeCallbacks]]. + /** Request the underlying node to download the given blocks from its + * peers and feed the blocks to [[org.bitcoins.node.NodeCallbacks]]. */ override def downloadBlocks( - blockHashes: Vector[DoubleSha256DigestBE]): Future[Unit] = { + blockHashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] = { logger.info(s"Fetching ${blockHashes.length} hashes from bitcoind") val f: Vector[DoubleSha256DigestBE] => Future[Vector[Unit]] = { case hashes => @@ -79,14 +93,17 @@ abstract class SyncUtil extends BitcoinSLogger { } val batchSize = 25 - val batchedExecutedF = FutureUtil.batchExecute(elements = blockHashes, - f = f, - init = Vector.empty, - batchSize = batchSize) + val batchedExecutedF = FutureUtil.batchExecute( + elements = blockHashes, + f = f, + init = Vector.empty, + batchSize = batchSize + ) batchedExecutedF.map { _ => logger.info( - s"Done fetching ${blockHashes.length} hashes from bitcoind") + s"Done fetching ${blockHashes.length} hashes from bitcoind" + ) () } } @@ -98,14 +115,18 @@ abstract class SyncUtil extends BitcoinSLogger { def getNodeApiWalletCallback( bitcoindRpcClient: BitcoindRpcClient, - walletF: Future[Wallet])(implicit system: ActorSystem): NodeApi = { - BitcoindRpcBackendUtil.buildBitcoindNodeApi(bitcoindRpcClient, - walletF, - None) + walletF: Future[Wallet] + )(implicit system: ActorSystem): NodeApi = { + BitcoindRpcBackendUtil.buildBitcoindNodeApi( + bitcoindRpcClient, + walletF, + None + ) } - def getNodeChainQueryApi(bitcoind: BitcoindRpcClient)(implicit - ec: ExecutionContext): NodeChainQueryApi = { + def getNodeChainQueryApi( + bitcoind: BitcoindRpcClient + )(implicit ec: ExecutionContext): NodeChainQueryApi = { val chainQuery = bitcoind val nodeApi = SyncUtil.getNodeApi(bitcoind) node.NodeChainQueryApi(nodeApi, chainQuery) @@ -113,8 +134,8 @@ abstract class SyncUtil extends BitcoinSLogger { def getNodeChainQueryApiWalletCallback( bitcoind: BitcoindRpcClient, - walletF: Future[Wallet])(implicit - system: ActorSystem): NodeChainQueryApi = { + walletF: Future[Wallet] + )(implicit system: ActorSystem): NodeChainQueryApi = { val chainQuery = bitcoind val nodeApi = SyncUtil.getNodeApiWalletCallback(bitcoind, walletF) @@ -125,7 +146,8 @@ abstract class SyncUtil extends BitcoinSLogger { * [[Wallet.processBlock()]] */ def syncWalletFullBlocks(wallet: WalletApi, bitcoind: BitcoindRpcClient)( - implicit ec: ExecutionContext): Future[WalletApi] = { + implicit ec: ExecutionContext + ): Future[WalletApi] = { val genesisBlockHashF = bitcoind.getBlockHash(0) for { genesisBlockHash <- genesisBlockHashF @@ -139,14 +161,16 @@ abstract class SyncUtil extends BitcoinSLogger { } yield syncedWalletApi } - /** Syncs the given chain handler to the given bitcoind node. This also syncs block filters - * since we know a bitcoind v19 node has block filter capability + /** Syncs the given chain handler to the given bitcoind node. This also syncs + * block filters since we know a bitcoind v19 node has block filter + * capability */ def syncBitcoindWithChainHandler( - bitcoindWithChainHandler: BitcoindBaseVersionChainHandlerViaRpc)(implicit + bitcoindWithChainHandler: BitcoindBaseVersionChainHandlerViaRpc + )(implicit ec: ExecutionContext, - chainAppConfig: ChainAppConfig): Future[ - BitcoindBaseVersionChainHandlerViaRpc] = { + chainAppConfig: ChainAppConfig + ): Future[BitcoindBaseVersionChainHandlerViaRpc] = { val bitcoindV19 = bitcoindWithChainHandler.bitcoindRpc val chainApiF = syncBitcoindWithChainHandler(bitcoindWithChainHandler) .map(_.chainHandler) @@ -166,7 +190,8 @@ abstract class SyncUtil extends BitcoinSLogger { ) } yield BitcoindBaseVersionChainHandlerViaRpc( bitcoindRpc = bitcoindWithChainHandler.bitcoindRpc, - chainHandler = filterSyncChainApi.asInstanceOf[ChainHandler]) + chainHandler = filterSyncChainApi.asInstanceOf[ChainHandler] + ) } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/BitcoindChainHandlerViaRpc.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/BitcoindChainHandlerViaRpc.scala index 90fb903f10..106b39c498 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/BitcoindChainHandlerViaRpc.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/BitcoindChainHandlerViaRpc.scala @@ -8,11 +8,11 @@ sealed trait BitcoindChainHandlerViaRpc { def chainHandler: ChainHandler } -/** Represents a bitcoind instance paired with a chain handler via rpc - * This is useful for when the bitcoind version doesn't matter, you - * just need a generic [[BitcoindRpcClient]] +/** Represents a bitcoind instance paired with a chain handler via rpc This is + * useful for when the bitcoind version doesn't matter, you just need a generic + * [[BitcoindRpcClient]] */ case class BitcoindBaseVersionChainHandlerViaRpc( bitcoindRpc: BitcoindRpcClient, - chainHandler: ChainHandler) - extends BitcoindChainHandlerViaRpc + chainHandler: ChainHandler +) extends BitcoindChainHandlerViaRpc diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/BitcoindChainHandlerViaZmq.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/BitcoindChainHandlerViaZmq.scala index afec4a79ab..fa8cd78571 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/BitcoindChainHandlerViaZmq.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/BitcoindChainHandlerViaZmq.scala @@ -9,13 +9,15 @@ import org.bitcoins.zmq.ZMQSubscriber case class BitcoindChainHandlerViaZmq( bitcoindRpc: BitcoindRpcClient, chainHandler: ChainHandler, - zmqSubscriber: ZMQSubscriber) + zmqSubscriber: ZMQSubscriber +) object BitcoindChainHandlerViaZmq { def apply( bitcoindRpc: BitcoindRpcClient, - pair: (ChainHandler, ZMQSubscriber)): BitcoindChainHandlerViaZmq = { + pair: (ChainHandler, ZMQSubscriber) + ): BitcoindChainHandlerViaZmq = { val (chainHandler, zmqSubscriber) = pair fixture.BitcoindChainHandlerViaZmq(bitcoindRpc, chainHandler, zmqSubscriber) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixture.scala index 0a5b081e8a..d3ccf3c188 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixture.scala @@ -4,10 +4,10 @@ import org.bitcoins.chain.blockchain.{ChainHandler, ChainHandlerCached} import org.bitcoins.chain.models.BlockHeaderDAO /** This ADT represents all Chain test fixtures. If you set this type to be your - * FixtureParam and override withFixture to be withChainFixutre, then simply tag - * tests to specify which fixture that test should receive and then use inFixutred - * which takes a PartialFunction[ChainFixture, Future[Assertion] ] (i.e. just - * specify the relevant case for your expected fixture) + * FixtureParam and override withFixture to be withChainFixutre, then simply + * tag tests to specify which fixture that test should receive and then use + * inFixutred which takes a PartialFunction[ChainFixture, Future[Assertion] ] + * (i.e. just specify the relevant case for your expected fixture) */ sealed trait ChainFixture @@ -21,21 +21,23 @@ object ChainFixture { case class GenisisChainHandler(chainHandler: ChainHandler) extends ChainFixture - /** Genesis chain handler, but has both genesis [[org.bitcoins.core.api.chain.db.CompactFilterHeaderDb]] and - * [[org.bitcoins.core.api.chain.db.CompactFilterDb]] inserted into their respective tables + /** Genesis chain handler, but has both genesis + * [[org.bitcoins.core.api.chain.db.CompactFilterHeaderDb]] and + * [[org.bitcoins.core.api.chain.db.CompactFilterDb]] inserted into their + * respective tables */ case class GenesisChainHandlerWithGenesisFilters(chainHandler: ChainHandler) extends ChainFixture /** Genesis chain handler with the genesis block header cached in memory */ case class GenesisChainHandlerCachedWithGenesisFilters( - chainHandler: ChainHandlerCached) - extends ChainFixture + chainHandler: ChainHandlerCached + ) extends ChainFixture case class PopulatedChainHandler(chainHandler: ChainHandler) extends ChainFixture case class BitcoindZmqChainHandlerWithBlock( - bitcoindChainHandler: BitcoindChainHandlerViaZmq) - extends ChainFixture + bitcoindChainHandler: BitcoindChainHandlerViaZmq + ) extends ChainFixture } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixtureHelper.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixtureHelper.scala index b568fdaf75..682adb65ae 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixtureHelper.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixtureHelper.scala @@ -30,7 +30,8 @@ trait ChainFixtureHelper { this: ChainUnitTest => ChainUnitTest.createChainHandler().map(GenisisChainHandler.apply) case ChainFixtureTag.PopulatedChainHandler => createPopulatedChainHandler().map( - ChainFixture.PopulatedChainHandler.apply) + ChainFixture.PopulatedChainHandler.apply + ) case ChainFixtureTag.GenesisChainHandlerWithFilter => createChainHandlerWithGenesisFilter() .map(ChainFixture.GenesisChainHandlerWithGenesisFilters(_)) @@ -39,7 +40,8 @@ trait ChainFixtureHelper { this: ChainUnitTest => .map(ChainFixture.GenesisChainHandlerCachedWithGenesisFilters(_)) case ChainFixtureTag.BitcoindZmqChainHandlerWithBlock => createBitcoindChainHandlerViaZmq().map( - BitcoindZmqChainHandlerWithBlock.apply) + BitcoindZmqChainHandlerWithBlock.apply + ) } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixtureTag.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixtureTag.scala index 00b6367d7b..fe40320946 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixtureTag.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainFixtureTag.scala @@ -2,8 +2,8 @@ package org.bitcoins.testkit.chain.fixture import org.scalatest.Tag -/** If a test file uses ChainFixture as its FixtureParam, then - * using these tags will determine which fixture the test will get. +/** If a test file uses ChainFixture as its FixtureParam, then using these tags + * will determine which fixture the test will get. * * Simply add taggedAs FixtureTag._ to your test before calling inFixtured. */ @@ -20,8 +20,9 @@ object ChainFixtureTag { case object GenisisChainHandler extends ChainFixtureTag("GenisisChainHandler") - /** Creates the genesis block header and genesis [[org.bitcoins.core.api.chain.db.CompactFilterHeaderDb]] - * and [[org.bitcoins.core.api.chain.db.CompactFilterDb]] + /** Creates the genesis block header and genesis + * [[org.bitcoins.core.api.chain.db.CompactFilterHeaderDb]] and + * [[org.bitcoins.core.api.chain.db.CompactFilterDb]] */ case object GenesisChainHandlerWithFilter extends ChainFixtureTag("GenesisChainHandlerWithFilter") diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainWithBitcoindUnitTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainWithBitcoindUnitTest.scala index 86d6ec9950..0ea7d74863 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainWithBitcoindUnitTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/fixture/ChainWithBitcoindUnitTest.scala @@ -30,7 +30,8 @@ trait ChainWithBitcoindNewestCachedUnitTest def withBitcoindNewestChainHandlerViaRpc( test: OneArgAsyncTest, - bitcoindRpcClient: BitcoindRpcClient): FutureOutcome = { + bitcoindRpcClient: BitcoindRpcClient + ): FutureOutcome = { val builder: () => Future[BitcoindBaseVersionChainHandlerViaRpc] = { () => ChainUnitTest.createChainApiWithBitcoindRpc(bitcoindRpcClient) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/chain/models/ReorgFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/chain/models/ReorgFixture.scala index 5aff704585..a8822258e6 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/chain/models/ReorgFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/chain/models/ReorgFixture.scala @@ -5,12 +5,8 @@ import org.bitcoins.core.api.chain.ChainApi import org.bitcoins.core.api.chain.db.BlockHeaderDb import org.bitcoins.core.protocol.blockchain.BlockHeader -/** A trait that contains a reorg scenario that looks like this - * headerDb1 - * / - * oldBestBlockHeader - * \ - * headerDb2 +/** A trait that contains a reorg scenario that looks like this headerDb1 / + * oldBestBlockHeader \ headerDb2 */ sealed trait ReorgFixture { def headerDb1: BlockHeaderDb @@ -25,12 +21,12 @@ case class ReorgFixtureChainApi( chainApi: ChainApi, headerDb1: BlockHeaderDb, headerDb2: BlockHeaderDb, - oldBestBlockHeader: BlockHeaderDb) - extends ReorgFixture + oldBestBlockHeader: BlockHeaderDb +) extends ReorgFixture case class ReorgFixtureBlockHeaderDAO( blockHeaderDAO: BlockHeaderDAO, headerDb1: BlockHeaderDb, headerDb2: BlockHeaderDb, - oldBestBlockHeader: BlockHeaderDb) - extends ReorgFixture + oldBestBlockHeader: BlockHeaderDb +) extends ReorgFixture diff --git a/testkit/src/main/scala/org/bitcoins/testkit/clightning/CLightningRpcTestClient.scala b/testkit/src/main/scala/org/bitcoins/testkit/clightning/CLightningRpcTestClient.scala index cfed83214b..4d50e47b57 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/clightning/CLightningRpcTestClient.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/clightning/CLightningRpcTestClient.scala @@ -19,21 +19,23 @@ import scala.concurrent.duration.DurationInt /** Helper class to start a clightning client with the given binary */ case class CLightningRpcTestClient( override val binary: Path, - bitcoindOpt: Option[BitcoindRpcClient])(implicit system: ActorSystem) + bitcoindOpt: Option[BitcoindRpcClient] +)(implicit system: ActorSystem) extends RpcBinaryUtil[CLightningRpcClient] { - require(Files.exists(binary), - s"Path did not exist! got=${binary.toAbsolutePath.toString}") + require( + Files.exists(binary), + s"Path did not exist! got=${binary.toAbsolutePath.toString}" + ) import system.dispatcher - /** Cached client. This is defined if start() has been called - * else None + /** Cached client. This is defined if start() has been called else None */ private var clientOpt: Option[CLightningRpcClient] = None private lazy val bitcoindRpcClientF: Future[BitcoindRpcClient] = { bitcoindOpt match { case Some(bitcoindRpcClient) => Future.successful(bitcoindRpcClient) - case None => CLightningRpcTestUtil.startedBitcoindRpcClient() + case None => CLightningRpcTestUtil.startedBitcoindRpcClient() } } @@ -59,7 +61,8 @@ case class CLightningRpcTestClient( _ <- TestAsyncUtil.awaitCondition( () => clightning.instance.rpcFile.exists(), interval = 1.second, - maxTries = 10) + maxTries = 10 + ) _ <- TestAsyncUtil.nonBlockingSleep(7.seconds) } yield { clientOpt = Some(clightning) @@ -73,7 +76,8 @@ case class CLightningRpcTestClient( case Some(cli) => cli.stop() case None => Future.failed( - new RuntimeException(s"CLightningRpcClient was not defined!")) + new RuntimeException(s"CLightningRpcClient was not defined!") + ) } } } @@ -89,8 +93,10 @@ object CLightningRpcTestClient extends SbtBinaryFactory { clightningVersionOpt: Option[String] = None )(implicit system: ActorSystem): Option[CLightningRpcTestClient] = { val fileOpt = - getBinary(clightningVersionOpt = clightningVersionOpt, - binaryDirectory = sbtBinaryDirectory) + getBinary( + clightningVersionOpt = clightningVersionOpt, + binaryDirectory = sbtBinaryDirectory + ) for { file <- fileOpt @@ -99,25 +105,28 @@ object CLightningRpcTestClient extends SbtBinaryFactory { def fromSbtDownload( bitcoindRpcClientOpt: Option[BitcoindRpcClient], - clightningVersionOpt: Option[String] = None)(implicit - system: ActorSystem): CLightningRpcTestClient = { + clightningVersionOpt: Option[String] = None + )(implicit system: ActorSystem): CLightningRpcTestClient = { val clightningOpt = fromSbtDownloadOpt( bitcoindRpcClientOpt = bitcoindRpcClientOpt, - clightningVersionOpt = clightningVersionOpt) + clightningVersionOpt = clightningVersionOpt + ) clightningOpt match { case Some(client) => client case None => sys.error( s"Could not find clightning that was downloaded by sbt " + s"with version=$clightningVersionOpt " + - s"path=${sbtBinaryDirectory.toAbsolutePath.toString}") + s"path=${sbtBinaryDirectory.toAbsolutePath.toString}" + ) } } /** Path to executable downloaded for clightning, if it exists */ def getBinary( clightningVersionOpt: Option[String], - binaryDirectory: Path): Option[File] = { + binaryDirectory: Path + ): Option[File] = { val versionStr = clightningVersionOpt.getOrElse(CLightningRpcClient.version) val path = binaryDirectory diff --git a/testkit/src/main/scala/org/bitcoins/testkit/clightning/CLightningRpcTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/clightning/CLightningRpcTestUtil.scala index 5eccb1ab46..2e711950a2 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/clightning/CLightningRpcTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/clightning/CLightningRpcTestUtil.scala @@ -35,8 +35,8 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { /** Makes a best effort to get a 0.21 bitcoind instance */ def startedBitcoindRpcClient( - instanceOpt: Option[BitcoindInstanceLocal] = None)(implicit - actorSystem: ActorSystem): Future[BitcoindRpcClient] = { + instanceOpt: Option[BitcoindInstanceLocal] = None + )(implicit actorSystem: ActorSystem): Future[BitcoindRpcClient] = { BitcoindRpcTestUtil.startedBitcoindRpcClient(instanceOpt, Vector.newBuilder) } @@ -44,34 +44,38 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { def bitcoindInstance( port: Int = RpcUtil.randomPort, rpcPort: Int = RpcUtil.randomPort, - bitcoindV: BitcoindVersion = BitcoindVersion.newest)(implicit - system: ActorSystem): BitcoindInstanceLocal = { - BitcoindRpcTestUtil.getInstance(bitcoindVersion = bitcoindV, - port = port, - rpcPort = rpcPort) + bitcoindV: BitcoindVersion = BitcoindVersion.newest + )(implicit system: ActorSystem): BitcoindInstanceLocal = { + BitcoindRpcTestUtil.getInstance( + bitcoindVersion = bitcoindV, + port = port, + rpcPort = rpcPort + ) } def commonConfig( datadir: Path, bitcoindInstance: BitcoindInstance, - port: Int = RpcUtil.randomPort): String = { + port: Int = RpcUtil.randomPort + ): String = { val bitcoinCliPath: Path = bitcoindInstance match { case local: BitcoindInstanceLocal => local.binary.toPath.getParent.resolve("bitcoin-cli") case _: BitcoindInstanceRemote => throw new RuntimeException( - "Local bitcoind instance required for clightning") + "Local bitcoind instance required for clightning" + ) } s""" |network=regtest |addr=127.0.0.1:$port |bitcoin-cli=${bitcoinCliPath.toAbsolutePath} |bitcoin-rpcuser=${bitcoindInstance.authCredentials - .asInstanceOf[BitcoindAuthCredentials.PasswordBased] - .username} + .asInstanceOf[BitcoindAuthCredentials.PasswordBased] + .username} |bitcoin-rpcpassword=${bitcoindInstance.authCredentials - .asInstanceOf[BitcoindAuthCredentials.PasswordBased] - .password} + .asInstanceOf[BitcoindAuthCredentials.PasswordBased] + .password} |bitcoin-rpcconnect=127.0.0.1 |bitcoin-rpcport=${bitcoindInstance.rpcUri.getPort} |log-file=${datadir.resolve("clightning.log")} @@ -80,12 +84,13 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { def cLightningDataDir( bitcoindRpcClient: BitcoindRpcClient, - isCanonical: Boolean): File = { + isCanonical: Boolean + ): File = { val bitcoindInstance = bitcoindRpcClient.instance if (isCanonical) { canonicalDatadir } else { - //creates a random clightning datadir, but still assumes that a bitcoind instance is running right now + // creates a random clightning datadir, but still assumes that a bitcoind instance is running right now val datadir = randomCLightningDatadir() datadir.mkdirs() logger.trace(s"Creating temp clightning dir ${datadir.getAbsolutePath}") @@ -100,41 +105,48 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { } } - def cLightingInstance(bitcoindRpc: BitcoindRpcClient)(implicit - system: ActorSystem): CLightningInstanceLocal = { + def cLightingInstance( + bitcoindRpc: BitcoindRpcClient + )(implicit system: ActorSystem): CLightningInstanceLocal = { val datadir = cLightningDataDir(bitcoindRpc, isCanonical = false) cLightingInstance(datadir) } - def cLightingInstance(datadir: File)(implicit - system: ActorSystem): CLightningInstanceLocal = { + def cLightingInstance( + datadir: File + )(implicit system: ActorSystem): CLightningInstanceLocal = { CLightningInstanceLocal.fromDataDir(datadir) } - /** Returns a `Future` that is completed when both clightning and bitcoind have the same block height - * Fails the future if they are not synchronized within the given timeout. + /** Returns a `Future` that is completed when both clightning and bitcoind + * have the same block height Fails the future if they are not synchronized + * within the given timeout. */ def awaitInSync(clightning: CLightningRpcClient, bitcoind: BitcoindRpcClient)( - implicit system: ActorSystem): Future[Unit] = { + implicit system: ActorSystem + ): Future[Unit] = { import system.dispatcher TestAsyncUtil.retryUntilSatisfiedF( conditionF = () => clientInSync(clightning, bitcoind), - interval = 1.seconds) + interval = 1.seconds + ) } private def clientInSync( client: CLightningRpcClient, - bitcoind: BitcoindRpcClient)(implicit - ec: ExecutionContext): Future[Boolean] = + bitcoind: BitcoindRpcClient + )(implicit ec: ExecutionContext): Future[Boolean] = for { blockCount <- bitcoind.getBlockCount() info <- client.getInfo } yield info.blockheight == blockCount - /** Shuts down an clightning daemon and the bitcoind daemon it is associated with + /** Shuts down an clightning daemon and the bitcoind daemon it is associated + * with */ - def shutdown(CLightningRpcClient: CLightningRpcClient)(implicit - system: ActorSystem): Future[Unit] = { + def shutdown( + CLightningRpcClient: CLightningRpcClient + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher val shutdownF = for { bitcoindRpc <- startedBitcoindRpcClient() @@ -142,11 +154,13 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { _ <- CLightningRpcClient.stop() } yield { logger.debug( - "Successfully shutdown clightning and it's corresponding bitcoind") + "Successfully shutdown clightning and it's corresponding bitcoind" + ) } shutdownF.failed.foreach { err: Throwable => logger.info( - s"Killed a bitcoind instance, but could not find an clightning process to kill") + s"Killed a bitcoind instance, but could not find an clightning process to kill" + ) throw err } shutdownF @@ -154,8 +168,8 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { def connectLNNodes( client: CLightningRpcClient, - otherClient: CLightningRpcClient)(implicit - ec: ExecutionContext): Future[Unit] = { + otherClient: CLightningRpcClient + )(implicit ec: ExecutionContext): Future[Unit] = { val infoF = otherClient.getInfo val nodeIdF = client.getInfo.map(_.id) val connectionF = infoF.flatMap { info => @@ -172,9 +186,10 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { } logger.debug(s"Awaiting connection between clients") - val connected = TestAsyncUtil.retryUntilSatisfiedF(conditionF = - () => isConnected, - interval = 1.second) + val connected = TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => isConnected, + interval = 1.second + ) connected.map(_ => logger.debug(s"Successfully connected two clients")) @@ -184,8 +199,8 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { def fundLNNodes( bitcoind: BitcoindRpcClient, client: CLightningRpcClient, - otherClient: CLightningRpcClient)(implicit - ec: ExecutionContext): Future[Unit] = { + otherClient: CLightningRpcClient + )(implicit ec: ExecutionContext): Future[Unit] = { for { addrA <- client.getNewAddress addrB <- otherClient.getNewAddress @@ -196,10 +211,12 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { } /** Creates two clightning nodes that are connected together and returns their - * respective [[com.bitcoins.clightning.rpc.CLightningRpcClient CLightningRpcClient]]s + * respective + * [[com.bitcoins.clightning.rpc.CLightningRpcClient CLightningRpcClient]]s */ def createNodePair(bitcoind: BitcoindRpcClient)(implicit - system: ActorSystem): Future[(CLightningRpcClient, CLightningRpcClient)] = { + system: ActorSystem + ): Future[(CLightningRpcClient, CLightningRpcClient)] = { import system.dispatcher val clientA = CLightningRpcTestClient.fromSbtDownload(Some(bitcoind)) val clientB = CLightningRpcTestClient.fromSbtDownload(Some(bitcoind)) @@ -248,8 +265,8 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { n1: CLightningRpcClient, n2: CLightningRpcClient, amt: CurrencyUnit = DEFAULT_CHANNEL_AMT, - pushAmt: CurrencyUnit = DEFAULT_CHANNEL_AMT / Satoshis(2))(implicit - ec: ExecutionContext): Future[FundChannelResult] = { + pushAmt: CurrencyUnit = DEFAULT_CHANNEL_AMT / Satoshis(2) + )(implicit ec: ExecutionContext): Future[FundChannelResult] = { val n1NodeIdF = n1.nodeId val n2NodeIdF = n2.nodeId @@ -261,12 +278,15 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { val fundedChannelIdF = nodeIdsF.flatMap { case (nodeId1, nodeId2) => logger.debug( - s"Opening a channel from $nodeId1 -> $nodeId2 with amount $amt") - n1.openChannel(nodeId = nodeId2, - fundingAmount = amt, - pushAmt = pushAmt, - feeRate = SatoshisPerVirtualByte.fromLong(10), - privateChannel = false) + s"Opening a channel from $nodeId1 -> $nodeId2 with amount $amt" + ) + n1.openChannel( + nodeId = nodeId2, + fundingAmount = amt, + pushAmt = pushAmt, + feeRate = SatoshisPerVirtualByte.fromLong(10), + privateChannel = false + ) } val genF = for { @@ -290,7 +310,8 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { openedF.flatMap { _ => nodeIdsF.map { case (nodeId1, nodeId2) => logger.debug( - s"Channel successfully opened $nodeId1 -> $nodeId2 with amount $amt") + s"Channel successfully opened $nodeId1 -> $nodeId2 with amount $amt" + ) } } @@ -299,13 +320,16 @@ trait CLightningRpcTestUtil extends BitcoinSLogger { private def awaitUntilChannelActive( client: CLightningRpcClient, - destination: NodeId)(implicit ec: ExecutionContext): Future[Unit] = { + destination: NodeId + )(implicit ec: ExecutionContext): Future[Unit] = { def isActive: Future[Boolean] = { client.listChannels().map(_.exists(_.destination == destination)) } - TestAsyncUtil.retryUntilSatisfiedF(conditionF = () => isActive, - interval = 1.seconds) + TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => isActive, + interval = 1.seconds + ) } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/db/DbTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/db/DbTestUtil.scala index fa4f0a0e6a..3e55a648ea 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/db/DbTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/db/DbTestUtil.scala @@ -12,8 +12,9 @@ import scala.concurrent.{ExecutionContext, Future} object DbTestUtil { - def createTestDbManagement(testAppConfig: TestAppConfig)(implicit - system: ActorSystem): TestDbManagement = { + def createTestDbManagement( + testAppConfig: TestAppConfig + )(implicit system: ActorSystem): TestDbManagement = { new TestDbManagement with JdbcProfileComponent[TestAppConfig] { override val ec: ExecutionContext = system.dispatcher @@ -42,8 +43,8 @@ trait TestDbManagement extends DbManagement { } case class TestAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( - implicit override val ec: ExecutionContext) - extends DbAppConfig + implicit override val ec: ExecutionContext +) extends DbAppConfig with TestDbManagement with JdbcProfileComponent[TestAppConfig] { @@ -52,7 +53,8 @@ case class TestAppConfig(baseDatadir: Path, configOverrides: Vector[Config])( override protected[bitcoins] type ConfigType = TestAppConfig override protected[bitcoins] def newConfigOfType( - configs: Vector[Config]): TestAppConfig = + configs: Vector[Config] + ): TestAppConfig = TestAppConfig(baseDatadir, configs) override def appConfig: TestAppConfig = this @@ -77,8 +79,8 @@ case class TestDb(pk: String, data: ByteVector) case class TestDAO()(implicit override val ec: ExecutionContext, - override val appConfig: TestAppConfig) - extends CRUD[TestDb, String] + override val appConfig: TestAppConfig +) extends CRUD[TestDb, String] with SlickUtil[TestDb, String] { import profile.api._ @@ -93,7 +95,8 @@ case class TestDAO()(implicit createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - ts: Vector[String]): Query[TestTable, TestDb, Seq] = { + ts: Vector[String] + ): Query[TestTable, TestDb, Seq] = { table.filter(_.pk.inSet(ts)) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/db/TestAppConfigFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/db/TestAppConfigFixture.scala index 5fd4e44b58..2f93e79224 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/db/TestAppConfigFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/db/TestAppConfigFixture.scala @@ -27,7 +27,8 @@ trait TestAppConfigFixture def getFreshTestConfig(): Future[TestAppConfig] = { val configOverride = BitcoinSTestAppConfig.configWithEmbeddedDb( Some(ProjectType.Test), - pgUrl = () => pgUrl()) + pgUrl = () => pgUrl() + ) val config = TestAppConfig(BitcoinSTestAppConfig.tmpDir(), Vector(configOverride)) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/db/TestDAOFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/db/TestDAOFixture.scala index 4029d804c4..a14be604e3 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/db/TestDAOFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/db/TestDAOFixture.scala @@ -20,8 +20,10 @@ sealed trait TestDAOFixture implicit private val testConfig: TestAppConfig = { val configOverrides = - BitcoinSTestAppConfig.configWithEmbeddedDb(Some(ProjectType.Test), - () => pgUrl()) + BitcoinSTestAppConfig.configWithEmbeddedDb( + Some(ProjectType.Test), + () => pgUrl() + ) TestAppConfig(BitcoinSTestAppConfig.tmpDir(), Vector(configOverrides)) } @@ -50,10 +52,12 @@ sealed trait TestDAOFixture val testDb: TestDb = TestDb("abc", hex"0054") - val testDbs: Vector[TestDb] = Vector(TestDb("abc", hex"0050"), - TestDb("abc1", hex"0051"), - TestDb("abc2", hex"0052"), - TestDb("abc3", hex"0053")) + val testDbs: Vector[TestDb] = Vector( + TestDb("abc", hex"0050"), + TestDb("abc1", hex"0051"), + TestDb("abc2", hex"0052"), + TestDb("abc3", hex"0053") + ) val updatedDb: TestDb = testDb.copy(data = hex"0000") diff --git a/testkit/src/main/scala/org/bitcoins/testkit/dlc/BitcoinSDLCNodeTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/dlc/BitcoinSDLCNodeTest.scala index f49935506a..08263d0ead 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/dlc/BitcoinSDLCNodeTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/dlc/BitcoinSDLCNodeTest.scala @@ -16,16 +16,19 @@ trait BitcoinSDLCNodeTest extends BitcoinSWalletTest with CachedTor { override protected def getFreshConfig: BitcoinSAppConfig = { val dlcListenWithSegwitWallet = ConfigFactory .parseString( - s"""bitcoin-s.dlcnode.listen = "127.0.0.1:${RpcUtil.randomPort}" """) + s"""bitcoin-s.dlcnode.listen = "127.0.0.1:${RpcUtil.randomPort}" """ + ) .withFallback(BaseWalletTest.segwitWalletConf) - BaseWalletTest.getFreshConfig(() => pgUrl(), - Vector(dlcListenWithSegwitWallet)) + BaseWalletTest.getFreshConfig( + () => pgUrl(), + Vector(dlcListenWithSegwitWallet) + ) } /** Creates two DLC nodes with wallets that are funded with some bitcoin, - * these wallets are NOT peered with a bitcoind so the funds in - * the wallets are not tied to an underlying blockchain. + * these wallets are NOT peered with a bitcoind so the funds in the wallets + * are not tied to an underlying blockchain. */ def witTwoFundedDLCNodes(test: OneArgAsyncTest): FutureOutcome = { makeDependentFixture( @@ -40,10 +43,12 @@ trait BitcoinSDLCNodeTest extends BitcoinSWalletTest with CachedTor { walletA <- FundWalletUtil.createFundedDLCWallet(nodeApi, chainQueryApi)( configA, - system) + system + ) walletB <- FundWalletUtil.createFundedDLCWallet( nodeApi, - chainQueryApi)(configB, system) + chainQueryApi + )(configB, system) nodeA = configA.dlcNodeConf.createDLCNode(walletA.wallet) nodeB = configB.dlcNodeConf.createDLCNode(walletB.wallet) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/eclair/rpc/EclairRpcTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/eclair/rpc/EclairRpcTestUtil.scala index 47c93d6209..c91030b4bb 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/eclair/rpc/EclairRpcTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/eclair/rpc/EclairRpcTestUtil.scala @@ -43,10 +43,10 @@ import scala.reflect.ClassTag import scala.util.{Failure, Success} /** @define nodeLinkDoc - * Creates four Eclair nodes that are connected in the following manner: - * {{{ + * Creates four Eclair nodes that are connected in the following manner: + * {{{ * node1 <-> node2 <-> node3 <-> node4 - * }}} + * }}} * * Each double sided arrow represents a P2P connection as well as a funded * channel @@ -61,12 +61,14 @@ trait EclairRpcTestUtil extends BitcoinSLogger { /** Makes a best effort to get a 0.16 bitcoind instance */ def startedBitcoindRpcClient( - instanceOpt: Option[BitcoindInstanceLocal] = None)(implicit - actorSystem: ActorSystem): Future[BitcoindRpcClient] = { - //need to do something with the Vector.newBuilder presumably? + instanceOpt: Option[BitcoindInstanceLocal] = None + )(implicit actorSystem: ActorSystem): Future[BitcoindRpcClient] = { + // need to do something with the Vector.newBuilder presumably? val instance = instanceOpt.getOrElse(bitcoindInstance()) - BitcoindRpcTestUtil.startedBitcoindRpcClient(Some(instance), - Vector.newBuilder) + BitcoindRpcTestUtil.startedBitcoindRpcClient( + Some(instance), + Vector.newBuilder + ) } /** Creates a bitcoind instance with the given parameters */ @@ -74,19 +76,22 @@ trait EclairRpcTestUtil extends BitcoinSLogger { port: Int = RpcUtil.randomPort, rpcPort: Int = RpcUtil.randomPort, zmqConfig: ZmqConfig = RpcUtil.zmqConfig, - bitcoindV: BitcoindVersion = EclairRpcClient.bitcoindV)(implicit - system: ActorSystem): BitcoindInstanceLocal = { - BitcoindRpcTestUtil.getInstance(bitcoindVersion = bitcoindV, - port = port, - rpcPort = rpcPort, - zmqConfig = zmqConfig) + bitcoindV: BitcoindVersion = EclairRpcClient.bitcoindV + )(implicit system: ActorSystem): BitcoindInstanceLocal = { + BitcoindRpcTestUtil.getInstance( + bitcoindVersion = bitcoindV, + port = port, + rpcPort = rpcPort, + zmqConfig = zmqConfig + ) } - //cribbed from https://github.com/Christewart/eclair/blob/bad02e2c0e8bd039336998d318a861736edfa0ad/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala#L140-L153 + // cribbed from https://github.com/Christewart/eclair/blob/bad02e2c0e8bd039336998d318a861736edfa0ad/eclair-core/src/test/scala/fr/acinq/eclair/integration/IntegrationSpec.scala#L140-L153 private[rpc] def commonConfig( bitcoindInstance: BitcoindInstance, port: Int = RpcUtil.randomPort, - apiPort: Int = RpcUtil.randomPort): Config = { + apiPort: Int = RpcUtil.randomPort + ): Config = { val configMap = { val hashBlock = bitcoindInstance.zmqConfig.hashBlock.get val rawTx = bitcoindInstance.zmqConfig.rawTx.get @@ -129,13 +134,14 @@ trait EclairRpcTestUtil extends BitcoinSLogger { def eclairDataDir( bitcoindRpcClient: BitcoindRpcClient, - isCannonical: Boolean): File = { + isCannonical: Boolean + ): File = { val bitcoindInstance = bitcoindRpcClient.instance if (isCannonical) { - //assumes that the ${HOME}/.eclair/eclair.conf file is created AND a bitcoind instance is running + // assumes that the ${HOME}/.eclair/eclair.conf file is created AND a bitcoind instance is running cannonicalDatadir } else { - //creates a random eclair datadir, but still assumes that a bitcoind instance is running right now + // creates a random eclair datadir, but still assumes that a bitcoind instance is running right now val datadir = randomEclairDatadir() datadir.mkdirs() logger.trace(s"Creating temp eclair dir ${datadir.getAbsolutePath}") @@ -150,16 +156,20 @@ trait EclairRpcTestUtil extends BitcoinSLogger { } } - /** Assumes bitcoind is running already and you have specified correct bindings in eclair.conf */ + /** Assumes bitcoind is running already and you have specified correct + * bindings in eclair.conf + */ def cannonicalEclairInstance( - logbackXml: Option[String] = None): EclairInstanceLocal = { + logbackXml: Option[String] = None + ): EclairInstanceLocal = { val datadir = cannonicalDatadir eclairInstance(datadir, logbackXml) } def eclairInstance( datadir: File, - logbackXml: Option[String]): EclairInstanceLocal = { + logbackXml: Option[String] + ): EclairInstanceLocal = { val instance = EclairInstanceLocal.fromDatadir(datadir, logbackXml, None) instance } @@ -167,14 +177,16 @@ trait EclairRpcTestUtil extends BitcoinSLogger { /** Starts the given bitcoind instance and then starts the eclair instance */ def eclairInstance( bitcoindRpc: BitcoindRpcClient, - logbackXml: Option[String] = None): EclairInstanceLocal = { + logbackXml: Option[String] = None + ): EclairInstanceLocal = { val datadir = eclairDataDir(bitcoindRpc, false) eclairInstance(datadir, logbackXml) } def randomEclairInstance( bitcoindRpc: BitcoindRpcClient, - logbackXml: Option[String] = None): EclairInstanceLocal = { + logbackXml: Option[String] = None + ): EclairInstanceLocal = { val datadir = eclairDataDir(bitcoindRpc, false) eclairInstance(datadir, logbackXml) } @@ -182,12 +194,13 @@ trait EclairRpcTestUtil extends BitcoinSLogger { def randomEclairClient( bitcoindRpcOpt: Option[BitcoindRpcClient] = None, eclairVersionOpt: Option[String] = None, - eclairCommitOpt: Option[String] = None)(implicit - system: ActorSystem): Future[EclairRpcClient] = { + eclairCommitOpt: Option[String] = None + )(implicit system: ActorSystem): Future[EclairRpcClient] = { val eclairRpcTestClient = EclairRpcTestClient.fromSbtDownload( eclairVersionOpt = eclairVersionOpt, eclairCommitOpt = eclairCommitOpt, - bitcoindRpcClientOpt = bitcoindRpcOpt) + bitcoindRpcClientOpt = bitcoindRpcOpt + ) eclairRpcTestClient.start() } @@ -195,36 +208,43 @@ trait EclairRpcTestUtil extends BitcoinSLogger { def cannonicalEclairClient( eclairVersionOpt: Option[String] = None, eclairCommitOpt: Option[String] = None, - binaryDirectory: Path = EclairRpcTestClient.sbtBinaryDirectory)(implicit - system: ActorSystem): EclairRpcClient = { + binaryDirectory: Path = EclairRpcTestClient.sbtBinaryDirectory + )(implicit system: ActorSystem): EclairRpcClient = { val inst = cannonicalEclairInstance() - new EclairRpcClient(inst, - EclairRpcTestClient.getBinary( - eclairVersionOpt = eclairVersionOpt, - eclairCommitOpt = eclairCommitOpt, - binaryDirectory = binaryDirectory)) + new EclairRpcClient( + inst, + EclairRpcTestClient.getBinary( + eclairVersionOpt = eclairVersionOpt, + eclairCommitOpt = eclairCommitOpt, + binaryDirectory = binaryDirectory + ) + ) } - /** Doesn't return until the given channelId - * is in the [[org.bitcoins.core.protocol.ln.channel.ChannelState ChannelState.NORMAL]] - * for this [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] + /** Doesn't return until the given channelId is in the + * [[org.bitcoins.core.protocol.ln.channel.ChannelState ChannelState.NORMAL]] + * for this + * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] * @param client * @param chanId */ def awaitUntilChannelNormal(client: EclairApi, chanId: ChannelId)(implicit - system: ActorSystem): Future[Unit] = { + system: ActorSystem + ): Future[Unit] = { awaitUntilChannelState(client, chanId, ChannelState.NORMAL) } def awaitUntilChannelClosing(client: EclairApi, chanId: ChannelId)(implicit - system: ActorSystem): Future[Unit] = { + system: ActorSystem + ): Future[Unit] = { awaitUntilChannelState(client, chanId, ChannelState.CLOSING) } private def awaitUntilChannelState( client: EclairApi, chanId: ChannelId, - state: ChannelState)(implicit system: ActorSystem): Future[Unit] = { + state: ChannelState + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher logger.debug(s"Awaiting ${chanId} to enter ${state} state") def isState(): Future[Boolean] = { @@ -232,14 +252,17 @@ trait EclairRpcTestUtil extends BitcoinSLogger { chanF.map { chan => if (!(chan.state == state)) { logger.trace( - s"ChanId ${chanId} has not entered ${state} yet. Currently in ${chan.state}") + s"ChanId ${chanId} has not entered ${state} yet. Currently in ${chan.state}" + ) } chan.state == state }(system.dispatcher) } - TestAsyncUtil.retryUntilSatisfiedF(conditionF = () => isState(), - interval = 1.seconds) + TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => isState(), + interval = 1.seconds + ) } def awaitUntilPaymentSucceeded( @@ -247,12 +270,15 @@ trait EclairRpcTestUtil extends BitcoinSLogger { paymentId: PaymentId, duration: FiniteDuration = 1.second, maxTries: Int = 60, - failFast: Boolean = true)(implicit system: ActorSystem): Future[Unit] = { - awaitUntilOutgoingPaymentStatus[OutgoingPaymentStatus.Succeeded](client, - paymentId, - duration, - maxTries, - failFast) + failFast: Boolean = true + )(implicit system: ActorSystem): Future[Unit] = { + awaitUntilOutgoingPaymentStatus[OutgoingPaymentStatus.Succeeded]( + client, + paymentId, + duration, + maxTries, + failFast + ) } def awaitUntilPaymentFailed( @@ -260,12 +286,15 @@ trait EclairRpcTestUtil extends BitcoinSLogger { paymentId: PaymentId, duration: FiniteDuration = 1.second, maxTries: Int = 60, - failFast: Boolean = false)(implicit system: ActorSystem): Future[Unit] = { - awaitUntilOutgoingPaymentStatus[OutgoingPaymentStatus.Failed](client, - paymentId, - duration, - maxTries, - failFast) + failFast: Boolean = false + )(implicit system: ActorSystem): Future[Unit] = { + awaitUntilOutgoingPaymentStatus[OutgoingPaymentStatus.Failed]( + client, + paymentId, + duration, + maxTries, + failFast + ) } private def awaitUntilOutgoingPaymentStatus[T <: OutgoingPaymentStatus]( @@ -273,12 +302,12 @@ trait EclairRpcTestUtil extends BitcoinSLogger { paymentId: PaymentId, interval: FiniteDuration, maxTries: Int, - failFast: Boolean)(implicit - system: ActorSystem, - tag: ClassTag[T]): Future[Unit] = { + failFast: Boolean + )(implicit system: ActorSystem, tag: ClassTag[T]): Future[Unit] = { import system.dispatcher logger.debug( - s"Awaiting payment ${paymentId} to enter ${tag.runtimeClass.getName} state") + s"Awaiting payment ${paymentId} to enter ${tag.runtimeClass.getName} state" + ) def isFailed(status: OutgoingPaymentStatus): Boolean = status match { @@ -293,13 +322,15 @@ trait EclairRpcTestUtil extends BitcoinSLogger { sentInfoF.map { payment => if (failFast && payment.exists(result => isFailed(result.status))) { throw new RuntimeException( - s"Payment ${paymentId} has failed: $payment") + s"Payment ${paymentId} has failed: $payment" + ) } if ( !payment.exists(result => tag.runtimeClass == result.status.getClass) ) { logger.trace( - s"Payment ${paymentId} has not entered ${tag.runtimeClass.getName} yet. Currently in ${payment.map(_.status).mkString(",")}") + s"Payment ${paymentId} has not entered ${tag.runtimeClass.getName} yet. Currently in ${payment.map(_.status).mkString(",")}" + ) false } else { true @@ -307,21 +338,23 @@ trait EclairRpcTestUtil extends BitcoinSLogger { }(system.dispatcher) } - TestAsyncUtil.retryUntilSatisfiedF(conditionF = () => isInState(), - interval = interval, - maxTries = maxTries) + TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => isInState(), + interval = interval, + maxTries = maxTries + ) } def awaitUntilIncomingPaymentStatus[T <: IncomingPaymentStatus]( client: EclairApi, paymentHash: Sha256Digest, interval: FiniteDuration = 1.second, - maxTries: Int = 60)(implicit - system: ActorSystem, - tag: ClassTag[T]): Future[Unit] = { + maxTries: Int = 60 + )(implicit system: ActorSystem, tag: ClassTag[T]): Future[Unit] = { import system.dispatcher logger.debug( - s"Awaiting payment ${paymentHash} to enter ${tag.runtimeClass.getName} state") + s"Awaiting payment ${paymentHash} to enter ${tag.runtimeClass.getName} state" + ) def isInState(): Future[Boolean] = { @@ -329,11 +362,12 @@ trait EclairRpcTestUtil extends BitcoinSLogger { .getReceivedInfo(paymentHash) .map { payment => if ( - !payment.exists(result => - tag.runtimeClass == result.status.getClass) + !payment + .exists(result => tag.runtimeClass == result.status.getClass) ) { logger.trace( - s"Payment ${paymentHash} has not entered ${tag.runtimeClass.getName} yet. Currently in ${payment.map(_.status).mkString(",")}") + s"Payment ${paymentHash} has not entered ${tag.runtimeClass.getName} yet. Currently in ${payment.map(_.status).mkString(",")}" + ) false } else { true @@ -341,15 +375,17 @@ trait EclairRpcTestUtil extends BitcoinSLogger { }(system.dispatcher) } - TestAsyncUtil.retryUntilSatisfiedF(conditionF = () => isInState(), - interval = interval, - maxTries = maxTries) + TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => isInState(), + interval = interval, + maxTries = maxTries + ) } private def createNodeLink( bitcoindRpcClient: Option[BitcoindRpcClient], - channelAmount: MilliSatoshis)(implicit - actorSystem: ActorSystem): Future[EclairNodes4] = { + channelAmount: MilliSatoshis + )(implicit actorSystem: ActorSystem): Future[EclairNodes4] = { implicit val ec: ExecutionContext = actorSystem.dispatcher val internalBitcoindF = { if (bitcoindRpcClient.isDefined) { @@ -369,11 +405,14 @@ trait EclairRpcTestUtil extends BitcoinSLogger { def open( c1: EclairRpcClient, - c2: EclairRpcClient): Future[FundedChannelId] = { - openChannel(n1 = c1, - n2 = c2, - amt = channelAmount.toSatoshis, - pushMSat = MilliSatoshis(channelAmount.toLong / 2)) + c2: EclairRpcClient + ): Future[FundedChannelId] = { + openChannel( + n1 = c1, + n2 = c2, + amt = channelAmount.toSatoshis, + pushMSat = MilliSatoshis(channelAmount.toLong / 2) + ) } val nodeVecF: Future[Vector[EclairRpcClient]] = { @@ -391,9 +430,11 @@ trait EclairRpcTestUtil extends BitcoinSLogger { val openChannelsFNested: Future[List[Future[FundedChannelId]]] = { nodeVecF.map { nodeVec => - List(open(nodeVec.head, nodeVec(1)), - open(nodeVec(1), nodeVec(2)), - open(nodeVec(2), nodeVec(3))) + List( + open(nodeVec.head, nodeVec(1)), + open(nodeVec(1), nodeVec(2)), + open(nodeVec(2), nodeVec(3)) + ) } } @@ -416,8 +457,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger { def openAndConfirmChannel( client1F: Future[EclairRpcClient], client2F: Future[EclairRpcClient], - amount: CurrencyUnit = Satoshis(1000000))(implicit - system: ActorSystem): Future[ChannelId] = { + amount: CurrencyUnit = Satoshis(1000000) + )(implicit system: ActorSystem): Future[ChannelId] = { import system.dispatcher val bitcoindRpcF = client1F.map(EclairRpcTestUtil.getBitcoindRpc(_)) @@ -429,7 +470,7 @@ trait EclairRpcTestUtil extends BitcoinSLogger { } } - //confirm the funding tx + // confirm the funding tx val genF = for { _ <- channelIdF bitcoind <- bitcoindRpcF @@ -439,8 +480,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger { channelIdF.flatMap { cid => genF.flatMap { _ => - //wait until our peer has put the channel in the - //NORMAL state so we can route payments to them + // wait until our peer has put the channel in the + // NORMAL state so we can route payments to them val normalF = client2F.flatMap(c2 => EclairRpcTestUtil.awaitUntilChannelNormal(c2, cid)) @@ -451,9 +492,11 @@ trait EclairRpcTestUtil extends BitcoinSLogger { } /** $nodeLinkDoc - * @note Blocks the current thread - * @return A 4-tuple of the created nodes' respective - * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] + * @note + * Blocks the current thread + * @return + * A 4-tuple of the created nodes' respective + * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] */ def createNodeLink( bitcoindRpcClient: BitcoindRpcClient @@ -462,31 +505,38 @@ trait EclairRpcTestUtil extends BitcoinSLogger { } /** $nodeLinkDoc - * @note Blocks the current thread - * @return A 4-tuple of the created nodes' respective - * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] + * @note + * Blocks the current thread + * @return + * A 4-tuple of the created nodes' respective + * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] */ def createNodeLink( bitcoindRpcClient: BitcoindRpcClient, - channelAmount: MilliSatoshis)(implicit - actorSystem: ActorSystem): Future[EclairNodes4] = { + channelAmount: MilliSatoshis + )(implicit actorSystem: ActorSystem): Future[EclairNodes4] = { createNodeLink(Some(bitcoindRpcClient), channelAmount) } /** $nodeLinkDoc - * @note Blocks the current thread - * @return A 4-tuple of the created nodes' respective - * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] + * @note + * Blocks the current thread + * @return + * A 4-tuple of the created nodes' respective + * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] */ def createNodeLink()(implicit - actorSystem: ActorSystem): Future[EclairNodes4] = { + actorSystem: ActorSystem + ): Future[EclairNodes4] = { createNodeLink(None, DEFAULT_CHANNEL_MSAT_AMT) } /** $nodeLinkDoc - * @note Blocks the current thread - * @return A 4-tuple of the created nodes' respective - * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] + * @note + * Blocks the current thread + * @return + * A 4-tuple of the created nodes' respective + * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]] */ def createNodeLink( channelAmount: MilliSatoshis @@ -495,7 +545,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger { } /** Creates two Eclair nodes that are connected together and returns their - * respective [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]]s + * respective + * [[org.bitcoins.eclair.rpc.client.EclairRpcClient EclairRpcClient]]s */ def createNodePair( bitcoindRpcClientOpt: Option[BitcoindRpcClient], @@ -503,8 +554,10 @@ trait EclairRpcTestUtil extends BitcoinSLogger { eclairCommitOpt1: Option[String] = None, eclairVersionOpt2: Option[String] = None, eclairCommitOpt2: Option[String] = None, - binaryDirectory: Path = EclairRpcTestClient.sbtBinaryDirectory)(implicit - system: ActorSystem): Future[(EclairRpcClient, EclairRpcClient)] = { + binaryDirectory: Path = EclairRpcTestClient.sbtBinaryDirectory + )(implicit + system: ActorSystem + ): Future[(EclairRpcClient, EclairRpcClient)] = { import system.dispatcher val bitcoindRpcClientF: Future[BitcoindRpcClient] = { @@ -522,22 +575,32 @@ trait EclairRpcTestUtil extends BitcoinSLogger { val clientF = e1InstanceF.flatMap { e1 => val e = - new EclairRpcClient(e1, - EclairRpcTestClient.getBinary(eclairVersionOpt1, - eclairCommitOpt1, - binaryDirectory)) + new EclairRpcClient( + e1, + EclairRpcTestClient.getBinary( + eclairVersionOpt1, + eclairCommitOpt1, + binaryDirectory + ) + ) logger.debug( - s"Temp eclair directory created ${e.getDaemon.authCredentials.datadir}") + s"Temp eclair directory created ${e.getDaemon.authCredentials.datadir}" + ) e.start().map(_ => e) } val otherClientF = e2InstanceF.flatMap { e2 => val e = - new EclairRpcClient(e2, - EclairRpcTestClient.getBinary(eclairVersionOpt2, - eclairCommitOpt2, - binaryDirectory)) + new EclairRpcClient( + e2, + EclairRpcTestClient.getBinary( + eclairVersionOpt2, + eclairCommitOpt2, + binaryDirectory + ) + ) logger.debug( - s"Temp eclair directory created ${e.getDaemon.authCredentials.datadir}") + s"Temp eclair directory created ${e.getDaemon.authCredentials.datadir}" + ) e.start().map(_ => e) } @@ -555,7 +618,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger { } def connectLNNodes(client: EclairApi, otherClient: EclairApi)(implicit - system: ActorSystem): Future[Unit] = { + system: ActorSystem + ): Future[Unit] = { implicit val dispatcher = system.dispatcher val infoF = otherClient.getInfo val nodeIdF = infoF.map(_.nodeId) @@ -574,9 +638,10 @@ trait EclairRpcTestUtil extends BitcoinSLogger { } logger.debug(s"Awaiting connection between clients") - val connected = TestAsyncUtil.retryUntilSatisfiedF(conditionF = - () => isConnected(), - interval = 1.second) + val connected = TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => isConnected(), + interval = 1.second + ) connected.map(_ => logger.debug(s"Successfully connected two clients")) @@ -584,13 +649,13 @@ trait EclairRpcTestUtil extends BitcoinSLogger { } - /** Sends `numPayments` between `c1` and `c2`. No aspect of the payment - * (size, description, etc) should be assumed to have a certain value, - * this method is just for populating channel update history with - * something. + /** Sends `numPayments` between `c1` and `c2`. No aspect of the payment (size, + * description, etc) should be assumed to have a certain value, this method + * is just for populating channel update history with something. */ def sendPayments(c1: EclairApi, c2: EclairApi, numPayments: Int = 5)(implicit - ec: ExecutionContext): Future[Vector[PaymentId]] = { + ec: ExecutionContext + ): Future[Vector[PaymentId]] = { val payments = (1 to numPayments) .map(MilliSatoshis(_)) .map(sats => @@ -607,7 +672,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger { nodeId1F.flatMap { nid1 => nodeId2F.map { nid2 => logger.error( - s"Failed to send payments from ${nid1.hex} -> ${nid2.hex}") + s"Failed to send payments from ${nid1.hex} -> ${nid2.hex}" + ) } } } @@ -623,8 +689,9 @@ trait EclairRpcTestUtil extends BitcoinSLogger { n2: EclairRpcClient, amt: CurrencyUnit = DEFAULT_CHANNEL_MSAT_AMT.toSatoshis, pushMSat: MilliSatoshis = MilliSatoshis( - DEFAULT_CHANNEL_MSAT_AMT.toLong / 2))(implicit - system: ActorSystem): Future[FundedChannelId] = { + DEFAULT_CHANNEL_MSAT_AMT.toLong / 2 + ) + )(implicit system: ActorSystem): Future[FundedChannelId] = { val bitcoindRpcClient = getBitcoindRpc(n1) implicit val ec = system.dispatcher @@ -639,13 +706,16 @@ trait EclairRpcTestUtil extends BitcoinSLogger { val fundedChannelIdF: Future[FundedChannelId] = { nodeIdsF.flatMap { case (nodeId1, nodeId2) => logger.debug( - s"Opening a channel from ${nodeId1} -> ${nodeId2} with amount ${amt}") - n1.open(nodeId = nodeId2, - funding = amt, - pushMsat = Some(pushMSat), - feerateSatPerByte = None, - channelFlags = None, - openTimeout = None) + s"Opening a channel from ${nodeId1} -> ${nodeId2} with amount ${amt}" + ) + n1.open( + nodeId = nodeId2, + funding = amt, + pushMsat = Some(pushMSat), + feerateSatPerByte = None, + channelFlags = None, + openTimeout = None + ) } } @@ -667,7 +737,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger { openedF.flatMap { case _ => nodeIdsF.map { case (nodeId1, nodeId2) => logger.debug( - s"Channel successfully opened ${nodeId1} -> ${nodeId2} with amount $amt") + s"Channel successfully opened ${nodeId1} -> ${nodeId2} with amount $amt" + ) } } @@ -675,14 +746,15 @@ trait EclairRpcTestUtil extends BitcoinSLogger { } def awaitChannelOpened(client1: EclairApi, chanId: ChannelId)(implicit - system: ActorSystem): Future[Unit] = { + system: ActorSystem + ): Future[Unit] = { EclairRpcTestUtil.awaitUntilChannelNormal(client1, chanId) } def getBitcoindRpc( eclairRpcClient: EclairRpcClient, - bitcoindVersion: BitcoindVersion = EclairRpcClient.bitcoindV)(implicit - system: ActorSystem): BitcoindRpcClient = { + bitcoindVersion: BitcoindVersion = EclairRpcClient.bitcoindV + )(implicit system: ActorSystem): BitcoindRpcClient = { val bitcoindRpc = { val instance = eclairRpcClient.instance val auth = instance.authCredentials @@ -698,21 +770,24 @@ trait EclairRpcTestUtil extends BitcoinSLogger { bitcoindRpc } - /** Returns a `Future` that is completed when both eclair and bitcoind have the same block height - * Fails the future if they are not sychronized within the given timeout. + /** Returns a `Future` that is completed when both eclair and bitcoind have + * the same block height Fails the future if they are not sychronized within + * the given timeout. */ def awaitEclairInSync(eclair: EclairRpcClient, bitcoind: BitcoindRpcClient)( - implicit system: ActorSystem): Future[Unit] = { + implicit system: ActorSystem + ): Future[Unit] = { import system.dispatcher - TestAsyncUtil.retryUntilSatisfiedF(conditionF = - () => clientInSync(eclair, bitcoind), - interval = 1.seconds) + TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => clientInSync(eclair, bitcoind), + interval = 1.seconds + ) } private def clientInSync( client: EclairRpcClient, - bitcoind: BitcoindRpcClient)(implicit - ec: ExecutionContext): Future[Boolean] = + bitcoind: BitcoindRpcClient + )(implicit ec: ExecutionContext): Future[Boolean] = for { blockCount <- bitcoind.getBlockCount() info <- client.getInfo @@ -720,8 +795,9 @@ trait EclairRpcTestUtil extends BitcoinSLogger { /** Shuts down an eclair daemon and the bitcoind daemon it is associated with */ - def shutdown(eclairRpcClient: EclairRpcClient)(implicit - system: ActorSystem): Future[Unit] = { + def shutdown( + eclairRpcClient: EclairRpcClient + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher val bitcoindRpc = getBitcoindRpc(eclairRpcClient) @@ -736,11 +812,13 @@ trait EclairRpcTestUtil extends BitcoinSLogger { _ <- iskilled } yield { logger.debug( - "Successfully shutdown eclair and it's corresponding bitcoind") + "Successfully shutdown eclair and it's corresponding bitcoind" + ) } shutdownF.failed.foreach { err: Throwable => logger.info( - s"Killed a bitcoind instance, but could not find an eclair process to kill") + s"Killed a bitcoind instance, but could not find an eclair process to kill" + ) throw err } shutdownF @@ -750,7 +828,8 @@ trait EclairRpcTestUtil extends BitcoinSLogger { bitcoind: BitcoindRpcClient, testEclairNode: EclairRpcClient, networkEclairNodes: Vector[EclairRpcClient], - channelIds: Vector[FundedChannelId]) { + channelIds: Vector[FundedChannelId] + ) { def shutdown()(implicit ec: ExecutionContext): Future[Unit] = for { @@ -770,18 +849,21 @@ trait EclairRpcTestUtil extends BitcoinSLogger { networkSize: Int, channelAmount: MilliSatoshis, logbackXml: Option[String], - binaryDirectory: Path = EclairRpcTestClient.sbtBinaryDirectory)(implicit - system: ActorSystem): Future[EclairNetwork] = { + binaryDirectory: Path = EclairRpcTestClient.sbtBinaryDirectory + )(implicit system: ActorSystem): Future[EclairNetwork] = { import system.dispatcher for { bitcoind <- startedBitcoindRpcClient() testEclairInstance = EclairRpcTestUtil.eclairInstance(bitcoind, logbackXml = logbackXml) - testEclairNode = new EclairRpcClient(testEclairInstance, - EclairRpcTestClient.getBinary( - testEclairVersion, - testEclairCommit, - binaryDirectory)) + testEclairNode = new EclairRpcClient( + testEclairInstance, + EclairRpcTestClient.getBinary( + testEclairVersion, + testEclairCommit, + binaryDirectory + ) + ) _ <- testEclairNode.start() _ <- awaitEclairInSync(testEclairNode, bitcoind) networkEclairInstances = @@ -789,35 +871,46 @@ trait EclairRpcTestUtil extends BitcoinSLogger { .to(networkSize) .toVector .map(_ => - EclairRpcTestUtil.eclairInstance(bitcoind, - logbackXml = logbackXml)) + EclairRpcTestUtil + .eclairInstance(bitcoind, logbackXml = logbackXml)) networkEclairNodes = networkEclairInstances.map( - new EclairRpcClient(_, - EclairRpcTestClient.getBinary(senderEclairVersion, - senderEclairCommit, - binaryDirectory))) + new EclairRpcClient( + _, + EclairRpcTestClient.getBinary( + senderEclairVersion, + senderEclairCommit, + binaryDirectory + ) + ) + ) _ <- Future.sequence(networkEclairNodes.map(_.start())) _ <- Future.sequence( - networkEclairNodes.map(awaitEclairInSync(_, bitcoind))) + networkEclairNodes.map(awaitEclairInSync(_, bitcoind)) + ) _ <- Future.sequence( - networkEclairNodes.map(connectLNNodes(_, testEclairNode))) + networkEclairNodes.map(connectLNNodes(_, testEclairNode)) + ) channelIds <- networkEclairNodes.foldLeft( - Future.successful(Vector.empty[FundedChannelId])) { (accF, node) => + Future.successful(Vector.empty[FundedChannelId]) + ) { (accF, node) => for { acc <- accF - channelId <- openChannel(n1 = node, - n2 = testEclairNode, - amt = channelAmount.toSatoshis, - pushMSat = - MilliSatoshis(channelAmount.toLong / 2)) + channelId <- openChannel( + n1 = node, + n2 = testEclairNode, + amt = channelAmount.toSatoshis, + pushMSat = MilliSatoshis(channelAmount.toLong / 2) + ) } yield acc :+ channelId } _ <- Future.sequence(channelIds.map(awaitChannelOpened(testEclairNode, _))) - } yield EclairNetwork(bitcoind, - testEclairNode, - networkEclairNodes, - channelIds) + } yield EclairNetwork( + bitcoind, + testEclairNode, + networkEclairNodes, + channelIds + ) } } @@ -829,7 +922,8 @@ object EclairRpcTestUtil extends EclairRpcTestUtil { override def commonConfig( bitcoindInstance: BitcoindInstance, port: Int, - apiPort: Int): Config = + apiPort: Int + ): Config = super .commonConfig(bitcoindInstance, port, apiPort) .withFallback(ConfigFactory.parseMap(customConfigMap.asJava)) @@ -840,4 +934,5 @@ case class EclairNodes4( c1: EclairRpcClient, c2: EclairRpcClient, c3: EclairRpcClient, - c4: EclairRpcClient) + c4: EclairRpcClient +) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSAppConfigFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSAppConfigFixture.scala index 0e99d93931..732dbc8641 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSAppConfigFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSAppConfigFixture.scala @@ -16,8 +16,8 @@ sealed trait BitcoinSAppConfigFixture extends BitcoinSFixture with EmbeddedPg { } } -/** Makes a bitcoin-s app config with proper bitcoind credentials - * and bitcoin-s.node.mode=bitcoind to use bitcoin as the backend +/** Makes a bitcoin-s app config with proper bitcoind credentials and + * bitcoin-s.node.mode=bitcoind to use bitcoin as the backend * * The [[BitcoinSAppConfig]] is not started */ @@ -54,18 +54,23 @@ trait BitcoinSAppConfigBitcoinFixtureStarted with CachedBitcoindNewest { def withTwoBitcoinSAppConfigNotStarted( - test: OneArgAsyncTest): FutureOutcome = { + test: OneArgAsyncTest + ): FutureOutcome = { val builder: () => Future[(BitcoinSAppConfig, BitcoinSAppConfig)] = () => { for { _ <- cachedBitcoindWithFundsF bitcoinSAppConfig1 = BitcoinSTestAppConfig - .getNeutrinoWithEmbeddedDbTestConfig(pgUrl = () => pgUrl(), - config = Vector.empty, - forceNamedWallet = true) + .getNeutrinoWithEmbeddedDbTestConfig( + pgUrl = () => pgUrl(), + config = Vector.empty, + forceNamedWallet = true + ) bitcoinSAppConfig2 = BitcoinSTestAppConfig - .getNeutrinoWithEmbeddedDbTestConfig(pgUrl = () => pgUrl(), - config = Vector.empty, - forceNamedWallet = true) + .getNeutrinoWithEmbeddedDbTestConfig( + pgUrl = () => pgUrl(), + config = Vector.empty, + forceNamedWallet = true + ) _ <- bitcoinSAppConfig1.start() _ <- bitcoinSAppConfig2.start() } yield (bitcoinSAppConfig1, bitcoinSAppConfig2) @@ -83,8 +88,10 @@ trait BitcoinSAppConfigBitcoinFixtureStarted } yield () } - makeDependentFixture[(BitcoinSAppConfig, BitcoinSAppConfig)](builder, - destroyF)(test) + makeDependentFixture[(BitcoinSAppConfig, BitcoinSAppConfig)]( + builder, + destroyF + )(test) } override def afterAll(): Unit = { diff --git a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSFixture.scala index 06e3bdad4f..d62e513f54 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/BitcoinSFixture.scala @@ -11,8 +11,9 @@ import scala.util.{Failure, Success} trait BitcoinSFixture extends BitcoinSAsyncFixtureTest { - /** Given functions to build and destroy a fixture, returns a OneArgAsyncTest => FutureOutcome - * (this version gives the destroy function access to the fixture) + /** Given functions to build and destroy a fixture, returns a OneArgAsyncTest + * \=> FutureOutcome (this version gives the destroy function access to the + * fixture) * * Example: * {{{ @@ -21,7 +22,8 @@ trait BitcoinSFixture extends BitcoinSAsyncFixtureTest { */ def makeDependentFixture[T]( build: () => Future[T], - destroy: T => Future[Any])(test: OneArgAsyncTest): FutureOutcome = { + destroy: T => Future[Any] + )(test: OneArgAsyncTest): FutureOutcome = { val fixtureF: Future[T] = build() val outcomeF: Future[Outcome] = fixtureF @@ -38,12 +40,12 @@ trait BitcoinSFixture extends BitcoinSAsyncFixtureTest { case Failure(exn) => fixtureF.transformWith { case Success(t) => - //means fixture setup successfully, something in test case code failed - //so we should destroy the fixture + // means fixture setup successfully, something in test case code failed + // so we should destroy the fixture destroy(t).flatMap(_ => Future.failed(exn)) case Failure(fixtureExn) => - //means setting up the fixture, NOT the test case, failed - //since the fixture failed, we cannot destroy the fixture + // means setting up the fixture, NOT the test case, failed + // since the fixture failed, we cannot destroy the fixture logger.error(s"Failed to setup test fixture", fixtureExn) Future.failed(fixtureExn) } @@ -51,8 +53,9 @@ trait BitcoinSFixture extends BitcoinSAsyncFixtureTest { new FutureOutcome(destructedF) } - /** Given functions to build and destroy a fixture, returns a OneArgAsyncTest => FutureOutcome - * (this version does not give the destroy function access to the fixture, see makeDependentFixture) + /** Given functions to build and destroy a fixture, returns a OneArgAsyncTest + * \=> FutureOutcome (this version does not give the destroy function access + * to the fixture, see makeDependentFixture) * * Example: * {{{ @@ -60,7 +63,8 @@ trait BitcoinSFixture extends BitcoinSAsyncFixtureTest { * }}} */ def makeFixture[T](build: () => Future[T], destroy: () => Future[Any])( - test: OneArgAsyncTest): FutureOutcome = { + test: OneArgAsyncTest + ): FutureOutcome = { val outcomeF = build().flatMap { fixture => test(fixture.asInstanceOf[FixtureParam]).toFuture } @@ -85,8 +89,9 @@ trait BitcoinSFixture extends BitcoinSAsyncFixtureTest { object BitcoinSFixture { - def createBitcoindWithFunds(versionOpt: Option[BitcoindVersion] = None)( - implicit system: ActorSystem): Future[BitcoindRpcClient] = { + def createBitcoindWithFunds( + versionOpt: Option[BitcoindVersion] = None + )(implicit system: ActorSystem): Future[BitcoindRpcClient] = { import system.dispatcher for { bitcoind <- createBitcoind(versionOpt = versionOpt) @@ -96,8 +101,8 @@ object BitcoinSFixture { } def createBitcoindBlockFilterRpcWithFunds( - versionOpt: Option[BitcoindVersion] = None)(implicit - system: ActorSystem): Future[BitcoindRpcClient] = { + versionOpt: Option[BitcoindVersion] = None + )(implicit system: ActorSystem): Future[BitcoindRpcClient] = { import system.dispatcher for { bitcoind <- createBitcoindWithFunds(versionOpt) @@ -105,16 +110,21 @@ object BitcoinSFixture { } /** Creates a new bitcoind instance - * @param versionOpt the version of bitcoind ot use - * @param enableNeutrinoOpt whether neutrino should be enabled or not, if param not given it is default enabled + * @param versionOpt + * the version of bitcoind ot use + * @param enableNeutrinoOpt + * whether neutrino should be enabled or not, if param not given it is + * default enabled */ def createBitcoind( versionOpt: Option[BitcoindVersion] = None, - enableNeutrino: Boolean = true)(implicit - system: ActorSystem): Future[BitcoindRpcClient] = { + enableNeutrino: Boolean = true + )(implicit system: ActorSystem): Future[BitcoindRpcClient] = { import system.dispatcher - val instance = BitcoindRpcTestUtil.instance(versionOpt = versionOpt, - enableNeutrino = enableNeutrino) + val instance = BitcoindRpcTestUtil.instance( + versionOpt = versionOpt, + enableNeutrino = enableNeutrino + ) val bitcoind = versionOpt match { case Some(v) => BitcoindRpcClient.fromVersion(v, instance) case None => new BitcoindRpcClient(instance) @@ -122,8 +132,8 @@ object BitcoinSFixture { BitcoindRpcTestUtil.startServers(Vector(bitcoind)).map(_ => bitcoind) } - /** Given two fixture building methods (one dependent on the other), returns a single - * fixture building method where the fixture is the pair of the two. + /** Given two fixture building methods (one dependent on the other), returns a + * single fixture building method where the fixture is the pair of the two. * * Example: * {{{ @@ -132,8 +142,8 @@ object BitcoinSFixture { */ def composeBuilders[T, U]( builder: () => Future[T], - dependentBuilder: T => Future[U])(implicit - ec: ExecutionContext): () => Future[(T, U)] = + dependentBuilder: T => Future[U] + )(implicit ec: ExecutionContext): () => Future[(T, U)] = () => { builder().flatMap { first => dependentBuilder(first).map { second => @@ -142,8 +152,9 @@ object BitcoinSFixture { } } - /** Given two fixture building methods (one dependent on the other) and a wrapper - * for their pair type, returns a single fixture building method where the fixture is wrapper. + /** Given two fixture building methods (one dependent on the other) and a + * wrapper for their pair type, returns a single fixture building method + * where the fixture is wrapper. * * Example: * {{{ @@ -156,7 +167,8 @@ object BitcoinSFixture { def composeBuildersAndWrap[T, U, C]( builder: () => Future[T], dependentBuilder: T => Future[U], - wrap: (T, U) => C)(implicit ec: ExecutionContext): () => Future[C] = + wrap: (T, U) => C + )(implicit ec: ExecutionContext): () => Future[C] = () => { composeBuilders(builder, dependentBuilder)(ec)().map { case (first, second) => @@ -164,12 +176,12 @@ object BitcoinSFixture { } } - /** Given two fixture building methods (one dependent on the other) and - * a function that processes the result of the builders returning a Future, + /** Given two fixture building methods (one dependent on the other) and a + * function that processes the result of the builders returning a Future, * returns a single fixture building method where the fixture is wrapper. * - * This method is identical to `composeBuildersAndWrap`, except that - * the wrapping function returns a `Future[C]` instead of a `C` + * This method is identical to `composeBuildersAndWrap`, except that the + * wrapping function returns a `Future[C]` instead of a `C` */ def composeBuildersAndWrapFuture[T, U, C]( builder: () => Future[T], diff --git a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/CLightningFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/CLightningFixture.scala index 990d68d20c..404da0b485 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/CLightningFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/CLightningFixture.scala @@ -12,7 +12,8 @@ import org.scalatest.FutureOutcome import scala.concurrent.duration.DurationInt -/** A trait that is useful if you need clightning fixtures for your test suite */ +/** A trait that is useful if you need clightning fixtures for your test suite + */ trait CLightningFixture extends BitcoinSFixture with CachedBitcoindNewest { override type FixtureParam = CLightningRpcClient @@ -37,7 +38,9 @@ trait CLightningFixture extends BitcoinSFixture with CachedBitcoindNewest { } } -/** A trait that is useful if you need dual clightning fixtures for your test suite */ +/** A trait that is useful if you need dual clightning fixtures for your test + * suite + */ trait DualCLightningFixture extends BitcoinSFixture with CachedBitcoindNewest { override type FixtureParam = diff --git a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/DLCDAOFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/DLCDAOFixture.scala index f764d41dcb..aa29edff9a 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/DLCDAOFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/DLCDAOFixture.scala @@ -22,7 +22,8 @@ case class DLCDAOs( dlcRefundSigDAO: DLCRefundSigsDAO, dlcRemoteTxDAO: DLCRemoteTxDAO, incomingDLCOfferDAO: IncomingDLCOfferDAO, - contactDAO: DLCContactDAO) { + contactDAO: DLCContactDAO +) { val list = Vector( announcementDAO, @@ -89,8 +90,10 @@ trait DLCDAOFixture extends BitcoinSFixture with EmbeddedPg { } def withFixture(test: OneArgAsyncTest): FutureOutcome = - makeFixture(build = () => Future(dlcConfig.migrate()).map(_ => daos), - destroy = () => dropAll())(test) + makeFixture( + build = () => Future(dlcConfig.migrate()).map(_ => daos), + destroy = () => dropAll() + )(test) private def dropAll(): Future[Unit] = { val res = for { diff --git a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/DLCOracleDAOFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/DLCOracleDAOFixture.scala index cabdc7df0c..628c5b0512 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/DLCOracleDAOFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/DLCOracleDAOFixture.scala @@ -11,7 +11,8 @@ import scala.concurrent.Future case class DLCOracleDAOs( rValueDAO: RValueDAO, eventDAO: EventDAO, - outcomeDAO: EventOutcomeDAO) + outcomeDAO: EventOutcomeDAO +) trait DLCOracleDAOFixture extends BitcoinSFixture with EmbeddedPg { diff --git a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/LndFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/LndFixture.scala index 81c0c7e311..789b2321b9 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/LndFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/LndFixture.scala @@ -95,9 +95,11 @@ trait RemoteLndFixture extends BitcoinSFixture with CachedBitcoindNewest { } // create a remote instance and client - remoteInstance = LndInstanceRemote(lnd.instance.rpcUri, - lnd.instance.macaroon, - cert) + remoteInstance = LndInstanceRemote( + lnd.instance.rpcUri, + lnd.instance.macaroon, + cert + ) remoteLnd = LndRpcClient(remoteInstance) } yield remoteLnd }, diff --git a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/NodeDAOFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/NodeDAOFixture.scala index e83d89fe17..f2241aca2e 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/NodeDAOFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/NodeDAOFixture.scala @@ -12,15 +12,18 @@ import scala.concurrent.Future case class NodeDAOs( txDAO: BroadcastAbleTransactionDAO, peerDAO: PeerDAO, - nodeAppConfig: NodeAppConfig) + nodeAppConfig: NodeAppConfig +) /** Provides a fixture where all DAOs used by the node projects are provided */ trait NodeDAOFixture extends NodeUnitTest { /** Wallet config with data directory set to user temp directory */ override protected def getFreshConfig: BitcoinSAppConfig = - BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(() => pgUrl(), - Vector.empty) + BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig( + () => pgUrl(), + Vector.empty + ) final override type FixtureParam = NodeDAOs diff --git a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/WalletDAOFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/WalletDAOFixture.scala index 91182a792b..d3d4386712 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/fixtures/WalletDAOFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/fixtures/WalletDAOFixture.scala @@ -17,17 +17,20 @@ case class WalletDAOs( incomingTxDAO: IncomingTransactionDAO, outgoingTxDAO: OutgoingTransactionDAO, scriptPubKeyDAO: ScriptPubKeyDAO, - stateDescriptorDAO: WalletStateDescriptorDAO) { + stateDescriptorDAO: WalletStateDescriptorDAO +) { - val list = Vector(scriptPubKeyDAO, - accountDAO, - addressDAO, - addressTagDAO, - transactionDAO, - incomingTxDAO, - utxoDAO, - outgoingTxDAO, - stateDescriptorDAO) + val list = Vector( + scriptPubKeyDAO, + accountDAO, + addressDAO, + addressTagDAO, + transactionDAO, + incomingTxDAO, + utxoDAO, + outgoingTxDAO, + stateDescriptorDAO + ) } trait WalletDAOFixture extends BitcoinSFixture with EmbeddedPg { @@ -49,15 +52,17 @@ trait WalletDAOFixture extends BitcoinSFixture with EmbeddedPg { val outgoingTx = OutgoingTransactionDAO() val scriptPubKey = ScriptPubKeyDAO() val stateDescriptorDAO = WalletStateDescriptorDAO() - WalletDAOs(account, - address, - tags, - utxo, - tx, - incomingTx, - outgoingTx, - scriptPubKey, - stateDescriptorDAO) + WalletDAOs( + account, + address, + tags, + utxo, + tx, + incomingTx, + outgoingTx, + scriptPubKey, + stateDescriptorDAO + ) } override def withFixture(test: OneArgAsyncTest): FutureOutcome = { diff --git a/testkit/src/main/scala/org/bitcoins/testkit/keymanager/KeyManagerApiUnitTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/keymanager/KeyManagerApiUnitTest.scala index 3a6f8a462a..eddba3ee2d 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/keymanager/KeyManagerApiUnitTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/keymanager/KeyManagerApiUnitTest.scala @@ -13,8 +13,8 @@ trait KeyManagerApiUnitTest extends BitcoinSUnitTest { aesPasswordOpt: Option[AesPassword] = KeyManagerTestUtil.aesPasswordOpt, kmParams: KeyManagerParams = KeyManagerTestUtil.createKeyManagerParams(), entropy: BitVector = MnemonicCode.getEntropy256Bits, - bip39PasswordOpt: Option[String] = - KeyManagerTestUtil.bip39PasswordOpt): BIP39KeyManager = { + bip39PasswordOpt: Option[String] = KeyManagerTestUtil.bip39PasswordOpt + ): BIP39KeyManager = { val kmResult = BIP39KeyManager.initializeWithEntropy( aesPasswordOpt = aesPasswordOpt, entropy = entropy, diff --git a/testkit/src/main/scala/org/bitcoins/testkit/keymanager/KeyManagerTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/keymanager/KeyManagerTestUtil.scala index e9e54bc882..e83406a4a2 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/keymanager/KeyManagerTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/keymanager/KeyManagerTestUtil.scala @@ -25,9 +25,11 @@ object KeyManagerTestUtil { def createKeyManagerParams(): KeyManagerParams = { val seedPath = KeyManagerTestUtil.tmpSeedPath - KeyManagerParams(seedPath = seedPath, - purpose = Gen.oneOf(HDPurposes.all).sample.get, - network = Gen.oneOf(Networks.knownNetworks).sample.get) + KeyManagerParams( + seedPath = seedPath, + purpose = Gen.oneOf(HDPurposes.all).sample.get, + network = Gen.oneOf(Networks.knownNetworks).sample.get + ) } def bip39PasswordOpt: Option[String] = { diff --git a/testkit/src/main/scala/org/bitcoins/testkit/lnd/LndRpcTestClient.scala b/testkit/src/main/scala/org/bitcoins/testkit/lnd/LndRpcTestClient.scala index 4c7180e5d3..b34fe4f847 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/lnd/LndRpcTestClient.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/lnd/LndRpcTestClient.scala @@ -20,14 +20,16 @@ import scala.util.Properties /** Helper class to start a bitcoind client with the given binary */ case class LndRpcTestClient( override val binary: Path, - bitcoindOpt: Option[BitcoindRpcClient])(implicit system: ActorSystem) + bitcoindOpt: Option[BitcoindRpcClient] +)(implicit system: ActorSystem) extends RpcBinaryUtil[LndRpcClient] { - require(Files.exists(binary), - s"Path did not exist! got=${binary.toAbsolutePath.toString}") + require( + Files.exists(binary), + s"Path did not exist! got=${binary.toAbsolutePath.toString}" + ) import system.dispatcher - /** Cached client. This is defined if start() has been called - * else None + /** Cached client. This is defined if start() has been called else None */ private var clientOpt: Option[LndRpcClient] = None @@ -58,9 +60,11 @@ case class LndRpcTestClient( _ <- lnd.start() // Wait for it to be ready - _ <- TestAsyncUtil.awaitConditionF(() => lnd.isStarted, - interval = 500.milliseconds, - maxTries = 100) + _ <- TestAsyncUtil.awaitConditionF( + () => lnd.isStarted, + interval = 500.milliseconds, + maxTries = 100 + ) } yield { clientOpt = Some(lnd) lnd @@ -95,35 +99,41 @@ object LndRpcTestClient extends SbtBinaryFactory { def fromSbtDownloadOpt( bitcoindRpcClientOpt: Option[BitcoindRpcClient], - lndVersionOpt: Option[String] = None)(implicit - system: ActorSystem): Option[LndRpcTestClient] = { + lndVersionOpt: Option[String] = None + )(implicit system: ActorSystem): Option[LndRpcTestClient] = { val fileOpt = - getBinary(lndVersionOpt = lndVersionOpt, - binaryDirectory = sbtBinaryDirectory) + getBinary( + lndVersionOpt = lndVersionOpt, + binaryDirectory = sbtBinaryDirectory + ) fileOpt.map(f => LndRpcTestClient(binary = f.toPath, bitcoindRpcClientOpt)) } def fromSbtDownload( bitcoindRpcClientOpt: Option[BitcoindRpcClient], - lndVersionOpt: Option[String] = None)(implicit - system: ActorSystem): LndRpcTestClient = { - val lndOpt = fromSbtDownloadOpt(lndVersionOpt = lndVersionOpt, - bitcoindRpcClientOpt = bitcoindRpcClientOpt) + lndVersionOpt: Option[String] = None + )(implicit system: ActorSystem): LndRpcTestClient = { + val lndOpt = fromSbtDownloadOpt( + lndVersionOpt = lndVersionOpt, + bitcoindRpcClientOpt = bitcoindRpcClientOpt + ) lndOpt match { case Some(client) => client case None => sys.error( s"Could not find lnd that was downloaded by sbt " + s"with version=$lndVersionOpt " + - s"path=${sbtBinaryDirectory.toAbsolutePath.toString}") + s"path=${sbtBinaryDirectory.toAbsolutePath.toString}" + ) } } /** Path to executable downloaded for lnd, if it exists */ def getBinary( lndVersionOpt: Option[String], - binaryDirectory: Path): Option[File] = { + binaryDirectory: Path + ): Option[File] = { val versionStr = lndVersionOpt.getOrElse(LndRpcClient.version) val platform = diff --git a/testkit/src/main/scala/org/bitcoins/testkit/lnd/LndRpcTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/lnd/LndRpcTestUtil.scala index 28734886bf..36ab754940 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/lnd/LndRpcTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/lnd/LndRpcTestUtil.scala @@ -42,9 +42,9 @@ trait LndRpcTestUtil extends BitcoinSLogger { /** Makes a best effort to get a 0.21 bitcoind instance */ def startedBitcoindRpcClient( - instanceOpt: Option[BitcoindInstanceLocal] = None)(implicit - actorSystem: ActorSystem): Future[BitcoindRpcClient] = { - //need to do something with the Vector.newBuilder presumably? + instanceOpt: Option[BitcoindInstanceLocal] = None + )(implicit actorSystem: ActorSystem): Future[BitcoindRpcClient] = { + // need to do something with the Vector.newBuilder presumably? BitcoindRpcTestUtil.startedBitcoindRpcClient(instanceOpt, Vector.newBuilder) } @@ -53,18 +53,21 @@ trait LndRpcTestUtil extends BitcoinSLogger { port: Int = RpcUtil.randomPort, rpcPort: Int = RpcUtil.randomPort, zmqConfig: ZmqConfig = RpcUtil.zmqConfig, - bitcoindV: BitcoindVersion = BitcoindVersion.newest)(implicit - system: ActorSystem): BitcoindInstanceLocal = { - BitcoindRpcTestUtil.getInstance(bitcoindVersion = bitcoindV, - port = port, - rpcPort = rpcPort, - zmqConfig = zmqConfig) + bitcoindV: BitcoindVersion = BitcoindVersion.newest + )(implicit system: ActorSystem): BitcoindInstanceLocal = { + BitcoindRpcTestUtil.getInstance( + bitcoindVersion = bitcoindV, + port = port, + rpcPort = rpcPort, + zmqConfig = zmqConfig + ) } def commonConfig( bitcoindInstance: BitcoindInstance, port: Int = RpcUtil.randomPort, - rpcPort: Int = RpcUtil.randomPort): String = { + rpcPort: Int = RpcUtil.randomPort + ): String = { val rawTx = bitcoindInstance.zmqConfig.rawTx.get val rawBlock = bitcoindInstance.zmqConfig.rawBlock.get s""" @@ -88,11 +91,11 @@ trait LndRpcTestUtil extends BitcoinSLogger { |externalip=127.0.0.1 |maxpendingchannels=10 |bitcoind.rpcuser = ${bitcoindInstance.authCredentials - .asInstanceOf[BitcoindAuthCredentials.PasswordBased] - .username} + .asInstanceOf[BitcoindAuthCredentials.PasswordBased] + .username} |bitcoind.rpcpass = ${bitcoindInstance.authCredentials - .asInstanceOf[BitcoindAuthCredentials.PasswordBased] - .password} + .asInstanceOf[BitcoindAuthCredentials.PasswordBased] + .password} |bitcoind.rpchost = 127.0.0.1:${bitcoindInstance.rpcUri.getPort} |bitcoind.zmqpubrawtx = tcp://127.0.0.1:${rawTx.getPort} |bitcoind.zmqpubrawblock = tcp://127.0.0.1:${rawBlock.getPort} @@ -101,13 +104,14 @@ trait LndRpcTestUtil extends BitcoinSLogger { def lndDataDir( bitcoindRpcClient: BitcoindRpcClient, - isCannonical: Boolean): File = { + isCannonical: Boolean + ): File = { val bitcoindInstance = bitcoindRpcClient.instance if (isCannonical) { - //assumes that the ${HOME}/.lnd/lnd.conf file is created AND a bitcoind instance is running + // assumes that the ${HOME}/.lnd/lnd.conf file is created AND a bitcoind instance is running cannonicalDatadir } else { - //creates a random lnd datadir, but still assumes that a bitcoind instance is running right now + // creates a random lnd datadir, but still assumes that a bitcoind instance is running right now val datadir = randomLndDatadir() datadir.mkdirs() logger.trace(s"Creating temp lnd dir ${datadir.getAbsolutePath}") @@ -122,30 +126,36 @@ trait LndRpcTestUtil extends BitcoinSLogger { } } - def lndInstance(bitcoindRpc: BitcoindRpcClient)(implicit - system: ActorSystem): LndInstanceLocal = { + def lndInstance( + bitcoindRpc: BitcoindRpcClient + )(implicit system: ActorSystem): LndInstanceLocal = { val datadir = lndDataDir(bitcoindRpc, isCannonical = false) lndInstance(datadir) } - def lndInstance(datadir: File)(implicit - system: ActorSystem): LndInstanceLocal = { + def lndInstance( + datadir: File + )(implicit system: ActorSystem): LndInstanceLocal = { LndInstanceLocal.fromDataDir(datadir) } - /** Returns a `Future` that is completed when both lnd and bitcoind have the same block height - * Fails the future if they are not synchronized within the given timeout. + /** Returns a `Future` that is completed when both lnd and bitcoind have the + * same block height Fails the future if they are not synchronized within the + * given timeout. */ def awaitLndInSync(lnd: LndRpcClient, bitcoind: BitcoindRpcClient)(implicit - system: ActorSystem): Future[Unit] = { + system: ActorSystem + ): Future[Unit] = { import system.dispatcher - TestAsyncUtil.retryUntilSatisfiedF(conditionF = - () => clientInSync(lnd, bitcoind), - interval = 1.seconds) + TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => clientInSync(lnd, bitcoind), + interval = 1.seconds + ) } private def clientInSync(client: LndRpcClient, bitcoind: BitcoindRpcClient)( - implicit ec: ExecutionContext): Future[Boolean] = + implicit ec: ExecutionContext + ): Future[Boolean] = for { blockCount <- bitcoind.getBlockCount() info <- client.getInfo @@ -153,8 +163,9 @@ trait LndRpcTestUtil extends BitcoinSLogger { /** Shuts down an lnd daemon and the bitcoind daemon it is associated with */ - def shutdown(lndRpcClient: LndRpcClient)(implicit - system: ActorSystem): Future[Unit] = { + def shutdown( + lndRpcClient: LndRpcClient + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher val shutdownF = for { bitcoindRpc <- startedBitcoindRpcClient() @@ -165,14 +176,16 @@ trait LndRpcTestUtil extends BitcoinSLogger { } shutdownF.failed.foreach { err: Throwable => logger.info( - s"Killed a bitcoind instance, but could not find an lnd process to kill") + s"Killed a bitcoind instance, but could not find an lnd process to kill" + ) throw err } shutdownF } def connectLNNodes(client: LndRpcClient, otherClient: LndRpcClient)(implicit - ec: ExecutionContext): Future[Unit] = { + ec: ExecutionContext + ): Future[Unit] = { val infoF = otherClient.getInfo val nodeIdF = client.getInfo.map(_.identityPubkey) val connectionF: Future[Unit] = infoF.flatMap { info => @@ -182,8 +195,10 @@ trait LndRpcTestUtil extends BitcoinSLogger { otherClient.getInfo.map(info => new URI(info.uris.head)) } uriF.flatMap(uri => - client.connectPeer(NodeId(info.identityPubkey), - new InetSocketAddress(uri.getHost, uri.getPort))) + client.connectPeer( + NodeId(info.identityPubkey), + new InetSocketAddress(uri.getHost, uri.getPort) + )) } def isConnected: Future[Boolean] = { @@ -195,9 +210,10 @@ trait LndRpcTestUtil extends BitcoinSLogger { } logger.debug(s"Awaiting connection between clients") - val connected = TestAsyncUtil.retryUntilSatisfiedF(conditionF = - () => isConnected, - interval = 1.second) + val connected = TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => isConnected, + interval = 1.second + ) connected.map(_ => logger.debug(s"Successfully connected two clients")) @@ -207,8 +223,8 @@ trait LndRpcTestUtil extends BitcoinSLogger { def fundLNNodes( bitcoind: BitcoindRpcClient, client: LndRpcClient, - otherClient: LndRpcClient)(implicit - ec: ExecutionContext): Future[Unit] = { + otherClient: LndRpcClient + )(implicit ec: ExecutionContext): Future[Unit] = { for { addrA <- client.getNewAddress addrB <- otherClient.getNewAddress @@ -224,8 +240,8 @@ trait LndRpcTestUtil extends BitcoinSLogger { def createNodePair( bitcoind: BitcoindRpcClient, channelSize: CurrencyUnit = DEFAULT_CHANNEL_AMT, - channelPushAmt: CurrencyUnit = DEFAULT_CHANNEL_AMT / Satoshis(2))(implicit - ec: ExecutionContext): Future[(LndRpcClient, LndRpcClient)] = { + channelPushAmt: CurrencyUnit = DEFAULT_CHANNEL_AMT / Satoshis(2) + )(implicit ec: ExecutionContext): Future[(LndRpcClient, LndRpcClient)] = { val actorSystemA = ActorSystem.create("bitcoin-s-lnd-test-" + FileUtil.randomDirName) @@ -265,11 +281,13 @@ trait LndRpcTestUtil extends BitcoinSLogger { _ <- AsyncUtil.awaitConditionF(() => isSynced) _ <- AsyncUtil.awaitConditionF(() => isFunded) - _ <- openChannel(bitcoind = bitcoind, - n1 = client, - n2 = otherClient, - amt = channelSize, - pushAmt = channelPushAmt) + _ <- openChannel( + bitcoind = bitcoind, + n1 = client, + n2 = otherClient, + amt = channelSize, + pushAmt = channelPushAmt + ) _ <- TestAsyncUtil.nonBlockingSleep(2.seconds) } yield (client, otherClient) @@ -283,8 +301,8 @@ trait LndRpcTestUtil extends BitcoinSLogger { n1: LndRpcClient, n2: LndRpcClient, amt: CurrencyUnit = DEFAULT_CHANNEL_AMT, - pushAmt: CurrencyUnit = DEFAULT_CHANNEL_AMT / Satoshis(2))(implicit - ec: ExecutionContext): Future[TransactionOutPoint] = { + pushAmt: CurrencyUnit = DEFAULT_CHANNEL_AMT / Satoshis(2) + )(implicit ec: ExecutionContext): Future[TransactionOutPoint] = { val n1NodeIdF = n1.nodeId val n2NodeIdF = n2.nodeId @@ -296,13 +314,15 @@ trait LndRpcTestUtil extends BitcoinSLogger { val fundedChannelIdF = nodeIdsF.flatMap { case (nodeId1, nodeId2) => logger.debug( - s"Opening a channel from $nodeId1 -> $nodeId2 with amount $amt") - n1.openChannel(nodeId = nodeId2, - fundingAmount = amt, - pushAmt = pushAmt, - satPerVByte = SatoshisPerVirtualByte.fromLong(10), - privateChannel = false) - .map(_.get) + s"Opening a channel from $nodeId1 -> $nodeId2 with amount $amt" + ) + n1.openChannel( + nodeId = nodeId2, + fundingAmount = amt, + pushAmt = pushAmt, + satPerVByte = SatoshisPerVirtualByte.fromLong(10), + privateChannel = false + ).map(_.get) } val genF = for { @@ -325,7 +345,8 @@ trait LndRpcTestUtil extends BitcoinSLogger { openedF.flatMap { _ => nodeIdsF.map { case (nodeId1, nodeId2) => logger.debug( - s"Channel successfully opened $nodeId1 -> $nodeId2 with amount $amt") + s"Channel successfully opened $nodeId1 -> $nodeId2 with amount $amt" + ) } } @@ -334,8 +355,8 @@ trait LndRpcTestUtil extends BitcoinSLogger { private def awaitUntilChannelActive( client: LndRpcClient, - outPoint: TransactionOutPoint)(implicit - ec: ExecutionContext): Future[Unit] = { + outPoint: TransactionOutPoint + )(implicit ec: ExecutionContext): Future[Unit] = { def isActive: Future[Boolean] = { client.findChannel(outPoint).map { case None => false @@ -343,8 +364,10 @@ trait LndRpcTestUtil extends BitcoinSLogger { } } - TestAsyncUtil.retryUntilSatisfiedF(conditionF = () => isActive, - interval = 1.seconds) + TestAsyncUtil.retryUntilSatisfiedF( + conditionF = () => isActive, + interval = 1.seconds + ) } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/BaseNodeTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/BaseNodeTest.scala index 33976c8248..0fbe85b32c 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/BaseNodeTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/BaseNodeTest.scala @@ -46,10 +46,12 @@ trait BaseNodeTest extends BitcoinSFixture with EmbeddedPg { BitcoinAddress("2NFyxovf6MyxfHqtVjstGzs6HeLqv92Nq4U") /** Helper method to generate blocks every interval - * @return a cancellable that will stop generating blocks + * @return + * a cancellable that will stop generating blocks */ - def genBlockInterval(bitcoind: BitcoindRpcClient)(implicit - system: ActorSystem): Cancellable = { + def genBlockInterval( + bitcoind: BitcoindRpcClient + )(implicit system: ActorSystem): Cancellable = { var counter = 0 val desiredBlocks = 5 @@ -73,20 +75,24 @@ trait BaseNodeTest extends BitcoinSFixture with EmbeddedPg { val genesisChainApi: ChainApi = new ChainApi { override def processHeaders( - headers: Vector[BlockHeader]): Future[ChainApi] = + headers: Vector[BlockHeader] + ): Future[ChainApi] = Future.successful(this) override def getHeader( - hash: DoubleSha256DigestBE): Future[Option[BlockHeaderDb]] = + hash: DoubleSha256DigestBE + ): Future[Option[BlockHeaderDb]] = Future.successful(None) - override def getHeaders(hashes: Vector[DoubleSha256DigestBE]): Future[ - Vector[Option[BlockHeaderDb]]] = { + override def getHeaders( + hashes: Vector[DoubleSha256DigestBE] + ): Future[Vector[Option[BlockHeaderDb]]] = { Future.successful(Vector.fill(hashes.length)(None)) } override def getHeadersAtHeight( - height: Int): Future[Vector[BlockHeaderDb]] = + height: Int + ): Future[Vector[BlockHeaderDb]] = Future.successful(Vector.empty) override def getBlockCount(): Future[Int] = Future.successful(0) @@ -96,34 +102,40 @@ trait BaseNodeTest extends BitcoinSFixture with EmbeddedPg { override def processFilterHeaders( filterHeaders: Vector[FilterHeader], - stopHash: DoubleSha256DigestBE): Future[ChainApi] = + stopHash: DoubleSha256DigestBE + ): Future[ChainApi] = Future.successful(this) override def nextBlockHeaderBatchRange( prevStopHash: DoubleSha256DigestBE, stopHash: DoubleSha256DigestBE, - batchSize: Int): Future[Option[FilterSyncMarker]] = + batchSize: Int + ): Future[Option[FilterSyncMarker]] = Future.successful(None) override def nextFilterHeaderBatchRange( stopBlockHash: DoubleSha256DigestBE, batchSize: Int, - startHeightOpt: Option[Int]): Future[Option[FilterSyncMarker]] = + startHeightOpt: Option[Int] + ): Future[Option[FilterSyncMarker]] = Future.successful(None) override def processFilters( - message: Vector[CompactFilterMessage]): Future[ChainApi] = + message: Vector[CompactFilterMessage] + ): Future[ChainApi] = Future.successful(this) override def processCheckpoints( checkpoints: Vector[DoubleSha256DigestBE], - blockHash: DoubleSha256DigestBE): Future[ChainApi] = + blockHash: DoubleSha256DigestBE + ): Future[ChainApi] = Future.successful(this) override def getFilterHeaderCount(): Future[Int] = Future.successful(0) override def getFilterHeadersAtHeight( - height: Int): Future[Vector[CompactFilterHeaderDb]] = + height: Int + ): Future[Vector[CompactFilterHeaderDb]] = Future.successful(Vector.empty) override def getBestFilterHeader(): Future[Option[CompactFilterHeaderDb]] = @@ -133,17 +145,20 @@ trait BaseNodeTest extends BitcoinSFixture with EmbeddedPg { Future.successful(None) } - override def getFilterHeader(blockHash: DoubleSha256DigestBE): Future[ - Option[CompactFilterHeaderDb]] = Future.successful(None) + override def getFilterHeader( + blockHash: DoubleSha256DigestBE + ): Future[Option[CompactFilterHeaderDb]] = Future.successful(None) override def getFilter( - hash: DoubleSha256DigestBE): Future[Option[CompactFilterDb]] = + hash: DoubleSha256DigestBE + ): Future[Option[CompactFilterDb]] = Future.successful(None) override def getFilterCount(): Future[Int] = Future.successful(0) override def getFiltersAtHeight( - height: Int): Future[Vector[CompactFilterDb]] = + height: Int + ): Future[Vector[CompactFilterDb]] = Future.successful(Vector.empty) override def getHeightByBlockStamp(blockStamp: BlockStamp): Future[Int] = @@ -151,11 +166,13 @@ trait BaseNodeTest extends BitcoinSFixture with EmbeddedPg { override def getHeadersBetween( from: BlockHeaderDb, - to: BlockHeaderDb): Future[Vector[BlockHeaderDb]] = + to: BlockHeaderDb + ): Future[Vector[BlockHeaderDb]] = Future.successful(Vector.empty) override def getBlockHeight( - blockHash: DoubleSha256DigestBE): Future[Option[Int]] = + blockHash: DoubleSha256DigestBE + ): Future[Option[Int]] = Future.successful(None) override def getBestBlockHash(): Future[DoubleSha256DigestBE] = @@ -166,12 +183,14 @@ trait BaseNodeTest extends BitcoinSFixture with EmbeddedPg { } override def getNumberOfConfirmations( - blockHashOpt: DoubleSha256DigestBE): Future[Option[Int]] = + blockHashOpt: DoubleSha256DigestBE + ): Future[Option[Int]] = Future.successful(None) override def getFiltersBetweenHeights( startHeight: Int, - endHeight: Int): Future[Vector[ChainQueryApi.FilterResponse]] = + endHeight: Int + ): Future[Vector[ChainQueryApi.FilterResponse]] = Future.successful(Vector.empty) override def epochSecondToBlockHeight(time: Long): Future[Int] = diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/MockNodeApi.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/MockNodeApi.scala index a17ca439b9..f6ffb1cb67 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/MockNodeApi.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/MockNodeApi.scala @@ -10,11 +10,13 @@ object MockNodeApi extends NodeApi { val mock: NodeApi = this override def broadcastTransactions( - transactions: Vector[Transaction]): Future[Unit] = + transactions: Vector[Transaction] + ): Future[Unit] = Future.unit override def downloadBlocks( - blockHashes: Vector[DoubleSha256DigestBE]): Future[Unit] = Future.unit + blockHashes: Vector[DoubleSha256DigestBE] + ): Future[Unit] = Future.unit override def getConnectionCount: Future[Int] = Future.successful(0) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeFundedWalletBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeFundedWalletBitcoind.scala index 58e7d9827f..94ba6ed98b 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeFundedWalletBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeFundedWalletBitcoind.scala @@ -9,10 +9,9 @@ import org.bitcoins.testkit.node.fixture.{ } /** Creates - * 1. a funded bitcoind wallet - * 2. a funded bitcoin-s wallet - * 3. a chain handler with the appropriate tables created - * 4. a neutrino node that is connected to the bitcoin instance -- but not started! + * 1. a funded bitcoind wallet 2. a funded bitcoin-s wallet 3. a chain + * handler with the appropriate tables created 4. a neutrino node that is + * connected to the bitcoin instance -- but not started! */ trait NodeFundedWalletBitcoind { def node: Node @@ -26,10 +25,11 @@ trait NodeFundedWalletBitcoind { case class NeutrinoNodeFundedWalletBitcoind( node: NeutrinoNode, wallet: NeutrinoHDWalletApi, - bitcoindRpc: BitcoindRpcClient) - extends NodeFundedWalletBitcoind { + bitcoindRpc: BitcoindRpcClient +) extends NodeFundedWalletBitcoind { - override def toNodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoind = { + override def toNodeConnectedWithBitcoind + : NeutrinoNodeConnectedWithBitcoind = { NeutrinoNodeConnectedWithBitcoind(node, bitcoindRpc) } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestUtil.scala index d853f5c1a8..4214e35d1b 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestUtil.scala @@ -18,30 +18,37 @@ import scala.concurrent.{ExecutionContext, Future} abstract class NodeTestUtil extends P2PLogger { - /** Helper method to get the [[java.net.InetSocketAddress]] - * we need to connect to to make a p2p connection with bitcoind + /** Helper method to get the [[java.net.InetSocketAddress]] we need to connect + * to to make a p2p connection with bitcoind * @param bitcoindRpcClient * @return */ - def getBitcoindSocketAddress(bitcoindRpcClient: BitcoindRpcClient)(implicit - executionContext: ExecutionContext): Future[InetSocketAddress] = { + def getBitcoindSocketAddress( + bitcoindRpcClient: BitcoindRpcClient + )(implicit executionContext: ExecutionContext): Future[InetSocketAddress] = { if (TorUtil.torEnabled) { for { networkInfo <- bitcoindRpcClient.getNetworkInfo } yield { val onionAddress = networkInfo.localaddresses .find(_.address.endsWith(".onion")) - .getOrElse(throw new IllegalArgumentException( - s"bitcoind instance is not configured to use Tor: ${bitcoindRpcClient}")) + .getOrElse( + throw new IllegalArgumentException( + s"bitcoind instance is not configured to use Tor: ${bitcoindRpcClient}" + ) + ) - InetSocketAddress.createUnresolved(onionAddress.address, - onionAddress.port) + InetSocketAddress.createUnresolved( + onionAddress.address, + onionAddress.port + ) } } else { val instance = bitcoindRpcClient.instance Future.successful( - new InetSocketAddress(instance.uri.getHost, instance.p2pPort)) + new InetSocketAddress(instance.uri.getHost, instance.p2pPort) + ) } } @@ -52,15 +59,17 @@ abstract class NodeTestUtil extends P2PLogger { address = InetSocketAddress.createUnresolved("127.0.0.1", 9050), credentialsOpt = None, randomizeCredentials = true - )) + ) + ) } else None } - /** Gets the [[Peer]] that - * corresponds to [[org.bitcoins.rpc.client.common.BitcoindRpcClient]] + /** Gets the [[Peer]] that corresponds to + * [[org.bitcoins.rpc.client.common.BitcoindRpcClient]] */ - def getBitcoindPeer(bitcoindRpcClient: BitcoindRpcClient)(implicit - executionContext: ExecutionContext): Future[Peer] = + def getBitcoindPeer( + bitcoindRpcClient: BitcoindRpcClient + )(implicit executionContext: ExecutionContext): Future[Peer] = for { socket <- getBitcoindSocketAddress(bitcoindRpcClient) } yield { @@ -70,7 +79,8 @@ abstract class NodeTestUtil extends P2PLogger { /** Checks if the given node and bitcoind is synced */ def isSameBestHash(node: Node, rpc: BitcoindRpcClient)(implicit - ec: ExecutionContext): Future[Boolean] = { + ec: ExecutionContext + ): Future[Boolean] = { val hashF = rpc.getBestBlockHash() for { chainApi <- node.chainApiFromDb() @@ -84,8 +94,8 @@ abstract class NodeTestUtil extends P2PLogger { private def isSameBestFilter( node: NeutrinoNode, rpc: BitcoindRpcClient, - bestBlockHashBEOpt: Option[DoubleSha256DigestBE])(implicit - ec: ExecutionContext): Future[Boolean] = { + bestBlockHashBEOpt: Option[DoubleSha256DigestBE] + )(implicit ec: ExecutionContext): Future[Boolean] = { val bestBlockHashBEF = bestBlockHashBEOpt match { case Some(bestBlockHash) => Future.successful(bestBlockHash) @@ -105,7 +115,8 @@ abstract class NodeTestUtil extends P2PLogger { } def isSameBestFilterHeight(node: NeutrinoNode, rpc: BitcoindRpcClient)( - implicit ec: ExecutionContext): Future[Boolean] = { + implicit ec: ExecutionContext + ): Future[Boolean] = { val rpcCountF = rpc.getBlockCount() for { chainApi <- node.chainApiFromDb() @@ -117,7 +128,8 @@ abstract class NodeTestUtil extends P2PLogger { } def isSameBestFilterHeaderHeight(node: NeutrinoNode, rpc: BitcoindRpcClient)( - implicit ec: ExecutionContext): Future[Boolean] = { + implicit ec: ExecutionContext + ): Future[Boolean] = { val rpcCountF = rpc.getBlockCount() for { chainApi <- node.chainApiFromDb() @@ -128,11 +140,12 @@ abstract class NodeTestUtil extends P2PLogger { } } - /** Checks if the given light client and bitcoind - * has the same number of blocks in their blockchains + /** Checks if the given light client and bitcoind has the same number of + * blocks in their blockchains */ def isSameBlockCount(node: Node, rpc: BitcoindRpcClient)(implicit - ec: ExecutionContext): Future[Boolean] = { + ec: ExecutionContext + ): Future[Boolean] = { val rpcCountF = rpc.getBlockCount() for { chainApi <- node.chainApiFromDb() @@ -147,40 +160,45 @@ abstract class NodeTestUtil extends P2PLogger { /** Awaits sync between the given node and bitcoind client */ def awaitSync(node: NeutrinoNode, rpc: BitcoindRpcClient)(implicit - sys: ActorSystem): Future[Unit] = { + sys: ActorSystem + ): Future[Unit] = { awaitAllSync(node, rpc) } /** Awaits sync between the given node and bitcoind client */ def awaitCompactFilterHeadersSync(node: NeutrinoNode, rpc: BitcoindRpcClient)( - implicit sys: ActorSystem): Future[Unit] = { + implicit sys: ActorSystem + ): Future[Unit] = { import sys.dispatcher TestAsyncUtil - .retryUntilSatisfiedF(() => isSameBestFilterHeaderHeight(node, rpc), - 1.second, - maxTries = syncTries) + .retryUntilSatisfiedF( + () => isSameBestFilterHeaderHeight(node, rpc), + 1.second, + maxTries = syncTries + ) } /** Awaits sync between the given node and bitcoind client */ def awaitCompactFiltersSync( node: NeutrinoNode, rpc: BitcoindRpcClient, - bestBlockHashBEOpt: Option[DoubleSha256DigestBE] = None)(implicit - sys: ActorSystem): Future[Unit] = { + bestBlockHashBEOpt: Option[DoubleSha256DigestBE] = None + )(implicit sys: ActorSystem): Future[Unit] = { import sys.dispatcher TestAsyncUtil .retryUntilSatisfiedF( () => isSameBestFilter(node, rpc, bestBlockHashBEOpt), 1.second, - maxTries = syncTries) + maxTries = syncTries + ) } /** The future doesn't complete until the nodes best hash is the given hash */ def awaitBestHash( node: Node, bitcoind: BitcoindRpcClient, - bestHashOpt: Option[DoubleSha256DigestBE] = None)(implicit - system: ActorSystem): Future[Unit] = { + bestHashOpt: Option[DoubleSha256DigestBE] = None + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher def bestBitcoinSHashF: Future[DoubleSha256DigestBE] = { node.chainApiFromDb().flatMap(_.getBestBlockHash()) @@ -206,17 +224,21 @@ abstract class NodeTestUtil extends P2PLogger { ) } - /** Awaits header, filter header and filter sync between the neutrino node and rpc client - * @param the node we are syncing - * @param bitcoind the node we are syncing against - * @param bestBlockHashBE the best block hash we are expected to sync to, this is useful for reorg situations. - * If None given, we use bitcoind's best block header + /** Awaits header, filter header and filter sync between the neutrino node and + * rpc client + * @param the + * node we are syncing + * @param bitcoind + * the node we are syncing against + * @param bestBlockHashBE + * the best block hash we are expected to sync to, this is useful for reorg + * situations. If None given, we use bitcoind's best block header */ def awaitAllSync( node: NeutrinoNode, bitcoind: BitcoindRpcClient, - bestBlockHashBE: Option[DoubleSha256DigestBE] = None)(implicit - system: ActorSystem): Future[Unit] = { + bestBlockHashBE: Option[DoubleSha256DigestBE] = None + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher for { _ <- NodeTestUtil.awaitBestHash(node, bitcoind, bestBlockHashBE) @@ -226,7 +248,8 @@ abstract class NodeTestUtil extends P2PLogger { } def awaitSyncAndIBD(node: NeutrinoNode, bitcoind: BitcoindRpcClient)(implicit - system: ActorSystem): Future[Unit] = { + system: ActorSystem + ): Future[Unit] = { import system.dispatcher for { @@ -250,30 +273,35 @@ abstract class NodeTestUtil extends P2PLogger { } - /** returns a Future that isn't completed until the peer manager has [[expectedConnectionCount]] connections */ + /** returns a Future that isn't completed until the peer manager has + * [[expectedConnectionCount]] connections + */ def awaitConnectionCount( node: Node, expectedConnectionCount: Int, interval: FiniteDuration = 1.second, - maxTries: Int = 30)(implicit ec: ExecutionContext): Future[Unit] = { + maxTries: Int = 30 + )(implicit ec: ExecutionContext): Future[Unit] = { AsyncUtil.retryUntilSatisfiedF( () => node.getConnectionCount.map(_ == expectedConnectionCount), interval = interval, - maxTries = maxTries) + maxTries = maxTries + ) } - /** get our neutrino node's uri from a test bitcoind instance to send rpc commands for our node. - * The peer must be initialized by the node. + /** get our neutrino node's uri from a test bitcoind instance to send rpc + * commands for our node. The peer must be initialized by the node. */ def getNodeURIFromBitcoind( bitcoind: BitcoindRpcClient, - localAddressBitcoinS: InetSocketAddress)(implicit - system: ActorSystem): Future[URI] = { + localAddressBitcoinS: InetSocketAddress + )(implicit system: ActorSystem): Future[URI] = { import system.dispatcher bitcoind.getPeerInfo.map { peerInfo => val localFilter = peerInfo.filter { p => p.networkInfo.addrlocal.isDefined && p.subver.contains( - NodeConstants.userAgent) && p.networkInfo.addr.getPort == localAddressBitcoinS.getPort + NodeConstants.userAgent + ) && p.networkInfo.addr.getPort == localAddressBitcoinS.getPort } val result = localFilter.head.networkInfo.addr result @@ -281,7 +309,8 @@ abstract class NodeTestUtil extends P2PLogger { } def disconnectNode(bitcoind: BitcoindRpcClient, node: NeutrinoNode)(implicit - system: ActorSystem): Future[Unit] = { + system: ActorSystem + ): Future[Unit] = { import system.dispatcher for { peer <- NodeTestUtil.getBitcoindPeer(bitcoind) @@ -298,7 +327,8 @@ abstract class NodeTestUtil extends P2PLogger { } def getStartedNodeCustomConfig(initNode: NeutrinoNode, config: Config)( - implicit ec: ExecutionContext): Future[NeutrinoNode] = { + implicit ec: ExecutionContext + ): Future[NeutrinoNode] = { val stoppedConfigF = for { _ <- initNode.stop() _ <- initNode.nodeConfig.stop() diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala index eebe402ada..c453d501ad 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala @@ -23,28 +23,34 @@ import org.scalatest.FutureOutcome import scala.concurrent.Future /** Test trait for using a bitcoin-s [[Node]] that requires a cached bitcoind. - * The cached bitcoind will be share across tests in the test suite that extends - * this trait. + * The cached bitcoind will be share across tests in the test suite that + * extends this trait. */ trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor { _: CachedBitcoind[_] => def withNeutrinoNodeConnectedToBitcoindCached( test: OneArgAsyncTest, - bitcoind: BitcoindRpcClient)(implicit + bitcoind: BitcoindRpcClient + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { - val nodeWithBitcoindBuilder: () => Future[ - NeutrinoNodeConnectedWithBitcoind] = { () => + appConfig: BitcoinSAppConfig + ): FutureOutcome = { + val nodeWithBitcoindBuilder + : () => Future[NeutrinoNodeConnectedWithBitcoind] = { () => require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { peer <- NodeUnitTest.createPeer(bitcoind) - node <- NodeUnitTest.createNeutrinoNode(peer, None)(system, - appConfig.chainConf, - appConfig.nodeConf) + node <- NodeUnitTest.createNeutrinoNode(peer, None)( + system, + appConfig.chainConf, + appConfig.nodeConf + ) started <- node.start() - _ <- NodeTestUtil.awaitConnectionCount(node = node, - expectedConnectionCount = 1) + _ <- NodeTestUtil.awaitConnectionCount( + node = node, + expectedConnectionCount = 1 + ) } yield NeutrinoNodeConnectedWithBitcoind(started, bitcoind) } @@ -52,72 +58,86 @@ trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor { build = nodeWithBitcoindBuilder, { x: NeutrinoNodeConnectedWithBitcoind => NodeUnitTest.destroyNode(x.node, appConfig) - })(test) + } + )(test) } def withNeutrinoNodeUnstarted( test: OneArgAsyncTest, - bitcoind: BitcoindRpcClient)(implicit + bitcoind: BitcoindRpcClient + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { - val nodeWithBitcoindBuilder: () => Future[ - NeutrinoNodeConnectedWithBitcoind] = { () => + appConfig: BitcoinSAppConfig + ): FutureOutcome = { + val nodeWithBitcoindBuilder + : () => Future[NeutrinoNodeConnectedWithBitcoind] = { () => require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { _ <- appConfig.walletConf.kmConf.start() node <- NodeUnitTest.createNeutrinoNode(bitcoind, None)( system, appConfig.chainConf, - appConfig.nodeConf) + appConfig.nodeConf + ) } yield NeutrinoNodeConnectedWithBitcoind(node, bitcoind) } makeDependentFixture[NeutrinoNodeConnectedWithBitcoind]( build = nodeWithBitcoindBuilder, { x: NeutrinoNodeConnectedWithBitcoind => tearDownNode(x.node, appConfig) - })(test) + } + )(test) } def withNeutrinoNodeConnectedToBitcoinds( test: OneArgAsyncTest, - bitcoinds: Vector[BitcoindRpcClient])(implicit + bitcoinds: Vector[BitcoindRpcClient] + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { - val nodeWithBitcoindBuilder: () => Future[ - NeutrinoNodeConnectedWithBitcoinds] = { () => + appConfig: BitcoinSAppConfig + ): FutureOutcome = { + val nodeWithBitcoindBuilder + : () => Future[NeutrinoNodeConnectedWithBitcoinds] = { () => require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { _ <- appConfig.walletConf.kmConf.start() node <- NodeUnitTest.createNeutrinoNode(bitcoinds, None)( system, appConfig.chainConf, - appConfig.nodeConf) + appConfig.nodeConf + ) startedNode <- node.start() - _ <- NodeTestUtil.awaitConnectionCount(node = node, - expectedConnectionCount = 1) + _ <- NodeTestUtil.awaitConnectionCount( + node = node, + expectedConnectionCount = 1 + ) } yield NeutrinoNodeConnectedWithBitcoinds(startedNode, bitcoinds) } makeDependentFixture[NeutrinoNodeConnectedWithBitcoinds]( build = nodeWithBitcoindBuilder, { x: NeutrinoNodeConnectedWithBitcoinds => tearDownNode(x.node, appConfig) - })(test) + } + )(test) } def withUnsyncedNeutrinoNodeConnectedToBitcoinds( test: OneArgAsyncTest, - bitcoinds: Vector[BitcoindRpcClient])(implicit + bitcoinds: Vector[BitcoindRpcClient] + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { - val nodeWithBitcoindBuilder: () => Future[ - NeutrinoNodeConnectedWithBitcoinds] = { () => + appConfig: BitcoinSAppConfig + ): FutureOutcome = { + val nodeWithBitcoindBuilder + : () => Future[NeutrinoNodeConnectedWithBitcoinds] = { () => require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { _ <- appConfig.walletConf.kmConf.start() node <- NodeUnitTest.createNeutrinoNode(bitcoinds, None)( system, appConfig.chainConf, - appConfig.nodeConf) + appConfig.nodeConf + ) startedNode <- node.start() _ <- NodeTestUtil.awaitConnectionCount(node, bitcoinds.size) } yield NeutrinoNodeConnectedWithBitcoinds(startedNode, bitcoinds) @@ -126,23 +146,27 @@ trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor { build = nodeWithBitcoindBuilder, { x: NeutrinoNodeConnectedWithBitcoinds => tearDownNode(x.node, appConfig) - })(test) + } + )(test) } def withUnsyncedNeutrinoNodeConnectedToBitcoind( test: OneArgAsyncTest, - bitcoind: BitcoindRpcClient)(implicit + bitcoind: BitcoindRpcClient + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { - val nodeWithBitcoindBuilder: () => Future[ - NeutrinoNodeConnectedWithBitcoind] = { () => + appConfig: BitcoinSAppConfig + ): FutureOutcome = { + val nodeWithBitcoindBuilder + : () => Future[NeutrinoNodeConnectedWithBitcoind] = { () => require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { _ <- appConfig.walletConf.kmConf.start() node <- NodeUnitTest.createNeutrinoNode(bitcoind, None)( system, appConfig.chainConf, - appConfig.nodeConf) + appConfig.nodeConf + ) startedNode <- node.start() _ <- NodeTestUtil.awaitConnectionCount(node, 1) } yield NeutrinoNodeConnectedWithBitcoind(startedNode, bitcoind) @@ -151,21 +175,25 @@ trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor { build = nodeWithBitcoindBuilder, { x: NeutrinoNodeConnectedWithBitcoind => tearDownNode(x.node, appConfig) - })(test) + } + )(test) } def withNeutrinoNodeFundedWalletBitcoind( test: OneArgAsyncTest, bitcoind: BitcoindRpcClient, - walletCallbacks: WalletCallbacks = WalletCallbacks.empty)(implicit + walletCallbacks: WalletCallbacks = WalletCallbacks.empty + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { + appConfig: BitcoinSAppConfig + ): FutureOutcome = { makeDependentFixture[NeutrinoNodeFundedWalletBitcoind]( build = () => NodeUnitTest .createNeutrinoNodeFundedWalletFromBitcoind( bitcoind, - walletCallbacks = walletCallbacks)(system, appConfig), + walletCallbacks = walletCallbacks + )(system, appConfig), { x: NeutrinoNodeFundedWalletBitcoind => tearDownNodeWithBitcoind(x, appConfig) } @@ -174,7 +202,8 @@ trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor { def withBitcoindPeer( test: OneArgAsyncTest, - bitcoind: BitcoindRpcClient): FutureOutcome = { + bitcoind: BitcoindRpcClient + ): FutureOutcome = { makeDependentFixture[Peer]( () => NodeTestUtil.getBitcoindPeer(bitcoind), _ => Future.unit @@ -183,7 +212,8 @@ trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor { private def tearDownNodeWithBitcoind( nodeWithBitcoind: NodeFundedWalletBitcoind, - appConfig: BitcoinSAppConfig): Future[Unit] = { + appConfig: BitcoinSAppConfig + ): Future[Unit] = { val node = nodeWithBitcoind.node val destroyNodeF = tearDownNode(node, appConfig) val destroyWalletF = @@ -197,11 +227,12 @@ trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor { private def tearDownNode( node: Node, - appConfig: BitcoinSAppConfig): Future[Unit] = { + appConfig: BitcoinSAppConfig + ): Future[Unit] = { val destroyNodeF = NodeUnitTest.destroyNode(node, appConfig) for { _ <- destroyNodeF - //need to stop chainAppConfig too since this is a test + // need to stop chainAppConfig too since this is a test _ <- node.chainAppConfig.stop() } yield () } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala index c9d7035f7e..e1851b5a67 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala @@ -26,7 +26,8 @@ trait NodeUnitTest extends BaseNodeTest { def withDisconnectedNeutrinoNode(test: OneArgAsyncTest)(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { + appConfig: BitcoinSAppConfig + ): FutureOutcome = { val nodeBuilder: () => Future[NeutrinoNode] = { () => require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) @@ -34,9 +35,10 @@ trait NodeUnitTest extends BaseNodeTest { node <- NodeUnitTest.createNeutrinoNode(NodeUnitTest.emptyPeer, None)( system, appConfig.chainConf, - appConfig.nodeConf) - //we aren't calling node.start(), but we need to call appConfig.start() - //to make sure migrations are run + appConfig.nodeConf + ) + // we aren't calling node.start(), but we need to call appConfig.start() + // to make sure migrations are run _ <- node.chainConfig.start() _ <- node.nodeConfig.start() } yield node @@ -46,8 +48,8 @@ trait NodeUnitTest extends BaseNodeTest { build = nodeBuilder, destroy = (_: Node) => { for { - _ <- ChainUnitTest.destroyAllTables()(appConfig.chainConf, - system.dispatcher) + _ <- ChainUnitTest + .destroyAllTables()(appConfig.chainConf, system.dispatcher) _ <- appConfig.stop() } yield () } @@ -56,9 +58,10 @@ trait NodeUnitTest extends BaseNodeTest { def withNeutrinoNodeConnectedToBitcoindV22(test: OneArgAsyncTest)(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { - val nodeWithBitcoindBuilder: () => Future[ - NeutrinoNodeConnectedWithBitcoindV22] = { () => + appConfig: BitcoinSAppConfig + ): FutureOutcome = { + val nodeWithBitcoindBuilder + : () => Future[NeutrinoNodeConnectedWithBitcoindV22] = { () => require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { bitcoind <- @@ -66,9 +69,11 @@ trait NodeUnitTest extends BaseNodeTest { .createBitcoindWithFunds(Some(V22)) .map(_.asInstanceOf[BitcoindV22RpcClient]) peer <- NodeUnitTest.createPeer(bitcoind) - node <- NodeUnitTest.createNeutrinoNode(peer, None)(system, - appConfig.chainConf, - appConfig.nodeConf) + node <- NodeUnitTest.createNeutrinoNode(peer, None)( + system, + appConfig.chainConf, + appConfig.nodeConf + ) started <- node.start() _ <- NodeUnitTest.syncNeutrinoNode(started, bitcoind) } yield NeutrinoNodeConnectedWithBitcoindV22(node, bitcoind) @@ -77,24 +82,28 @@ trait NodeUnitTest extends BaseNodeTest { makeDependentFixture( build = nodeWithBitcoindBuilder, destroy = NodeUnitTest.destroyNodeConnectedWithBitcoind( - _: NodeConnectedWithBitcoind)(system, appConfig) + _: NodeConnectedWithBitcoind + )(system, appConfig) )(test) } def withNeutrinoNodeConnectedToBitcoind( test: OneArgAsyncTest, - versionOpt: Option[BitcoindVersion] = None)(implicit + versionOpt: Option[BitcoindVersion] = None + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { - val nodeWithBitcoindBuilder: () => Future[ - NeutrinoNodeConnectedWithBitcoind] = { () => + appConfig: BitcoinSAppConfig + ): FutureOutcome = { + val nodeWithBitcoindBuilder + : () => Future[NeutrinoNodeConnectedWithBitcoind] = { () => require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { bitcoind <- BitcoinSFixture.createBitcoind(versionOpt) node <- NodeUnitTest.createNeutrinoNode(bitcoind, None)( system, appConfig.chainConf, - appConfig.nodeConf) + appConfig.nodeConf + ) startedNode <- node.start() syncedNode <- NodeUnitTest.syncNeutrinoNode(startedNode, bitcoind) } yield NeutrinoNodeConnectedWithBitcoind(syncedNode, bitcoind) @@ -102,47 +111,55 @@ trait NodeUnitTest extends BaseNodeTest { makeDependentFixture( build = nodeWithBitcoindBuilder, destroy = NodeUnitTest.destroyNodeConnectedWithBitcoind( - _: NodeConnectedWithBitcoind)(system, appConfig) + _: NodeConnectedWithBitcoind + )(system, appConfig) )(test) } def withUnstartedNeutrinoNodeBitcoinds( test: OneArgAsyncTest, - bitcoinds: Vector[BitcoindRpcClient])(implicit + bitcoinds: Vector[BitcoindRpcClient] + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { - val nodeWithBitcoindBuilder: () => Future[ - NeutrinoNodeNotConnectedWithBitcoinds] = { () => + appConfig: BitcoinSAppConfig + ): FutureOutcome = { + val nodeWithBitcoindBuilder + : () => Future[NeutrinoNodeNotConnectedWithBitcoinds] = { () => require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { _ <- appConfig.walletConf.kmConf.start() node <- NodeUnitTest.createNeutrinoNode(bitcoinds, None)( system, appConfig.chainConf, - appConfig.nodeConf) + appConfig.nodeConf + ) } yield NeutrinoNodeNotConnectedWithBitcoinds(node, bitcoinds) } makeDependentFixture[NeutrinoNodeNotConnectedWithBitcoinds]( build = nodeWithBitcoindBuilder, destroy = - NodeUnitTest.destroyNodeNotConnectedWithBitcoinds(_)(system, - appConfig))(test) + NodeUnitTest.destroyNodeNotConnectedWithBitcoinds(_)(system, appConfig) + )(test) } def withNeutrinoNodeFundedWalletBitcoind( test: OneArgAsyncTest, versionOpt: Option[BitcoindVersion] = None, - walletCallbacks: WalletCallbacks = WalletCallbacks.empty)(implicit + walletCallbacks: WalletCallbacks = WalletCallbacks.empty + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): FutureOutcome = { + appConfig: BitcoinSAppConfig + ): FutureOutcome = { makeDependentFixture( build = () => NodeUnitTest .createNeutrinoNodeFundedWalletBitcoind( versionOpt = versionOpt, - walletCallbacks = walletCallbacks)(system, appConfig), + walletCallbacks = walletCallbacks + )(system, appConfig), destroy = NodeUnitTest.destroyNodeFundedWalletBitcoind( - _: NodeFundedWalletBitcoind)(system, appConfig) + _: NodeFundedWalletBitcoind + )(system, appConfig) )(test) } } @@ -152,7 +169,8 @@ object NodeUnitTest extends P2PLogger { def buildNode(peer: Peer, walletCreationTimeOpt: Option[Instant])(implicit chainConf: ChainAppConfig, nodeConf: NodeAppConfig, - system: ActorSystem): Future[NeutrinoNode] = { + system: ActorSystem + ): Future[NeutrinoNode] = { import system.dispatcher val chainConfStartedF = { @@ -176,19 +194,24 @@ object NodeUnitTest extends P2PLogger { private def buildNeutrinoNode( peer: Peer, - walletCreationTimeOpt: Option[Instant])(implicit + walletCreationTimeOpt: Option[Instant] + )(implicit chainConf: ChainAppConfig, nodeConf: NodeAppConfig, - system: ActorSystem): NeutrinoNode = { - NeutrinoNode(walletCreationTimeOpt, - nodeConf, - chainConf, - system, - paramPeers = Vector(peer)) + system: ActorSystem + ): NeutrinoNode = { + NeutrinoNode( + walletCreationTimeOpt, + nodeConf, + chainConf, + system, + paramPeers = Vector(peer) + ) } def destroyNode(node: Node, appConfig: BitcoinSAppConfig)(implicit - ec: ExecutionContext): Future[Unit] = { + ec: ExecutionContext + ): Future[Unit] = { for { _ <- node.stop() @@ -200,9 +223,11 @@ object NodeUnitTest extends P2PLogger { } def destroyNodeConnectedWithBitcoind( - nodeConnectedWithBitcoind: NodeConnectedWithBitcoind)(implicit + nodeConnectedWithBitcoind: NodeConnectedWithBitcoind + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): Future[Unit] = { + appConfig: BitcoinSAppConfig + ): Future[Unit] = { logger.debug(s"Beginning tear down of node connected with bitcoind") import system.dispatcher val node = nodeConnectedWithBitcoind.node @@ -219,11 +244,13 @@ object NodeUnitTest extends P2PLogger { resultF } - //does not destroys the bitcoinds + // does not destroys the bitcoinds private def destroyNodeConnectedWithBitcoinds( - nodeConnectedWithBitcoind: NodeConnectedWithBitcoinds)(implicit + nodeConnectedWithBitcoind: NodeConnectedWithBitcoinds + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): Future[Unit] = { + appConfig: BitcoinSAppConfig + ): Future[Unit] = { logger.debug(s"Beginning tear down of node connected with bitcoind") import system.dispatcher val node = nodeConnectedWithBitcoind.node @@ -239,106 +266,134 @@ object NodeUnitTest extends P2PLogger { } private def destroyNodeNotConnectedWithBitcoinds( - x: NeutrinoNodeNotConnectedWithBitcoinds)(implicit + x: NeutrinoNodeNotConnectedWithBitcoinds + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): Future[Unit] = { + appConfig: BitcoinSAppConfig + ): Future[Unit] = { destroyNodeConnectedWithBitcoinds( - NeutrinoNodeConnectedWithBitcoinds(x.node, x.bitcoinds)) + NeutrinoNodeConnectedWithBitcoinds(x.node, x.bitcoinds) + ) } - /** Creates a neutrino node, a funded bitcoin-s wallet, all of which are connected to bitcoind */ + /** Creates a neutrino node, a funded bitcoin-s wallet, all of which are + * connected to bitcoind + */ private def createNeutrinoNodeFundedWalletBitcoind( versionOpt: Option[BitcoindVersion], - walletCallbacks: WalletCallbacks)(implicit + walletCallbacks: WalletCallbacks + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): Future[ - NeutrinoNodeFundedWalletBitcoind] = { + appConfig: BitcoinSAppConfig + ): Future[NeutrinoNodeFundedWalletBitcoind] = { import system.dispatcher require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { bitcoind <- BitcoinSFixture.createBitcoindWithFunds(versionOpt) - node <- createNeutrinoNode(bitcoind, None)(system, - appConfig.chainConf, - appConfig.nodeConf) + node <- createNeutrinoNode(bitcoind, None)( + system, + appConfig.chainConf, + appConfig.nodeConf + ) fundedWallet <- BitcoinSWalletTest.fundedWalletAndBitcoind( bitcoindRpcClient = bitcoind, nodeApi = node, chainQueryApi = node, - walletCallbacks = walletCallbacks) + walletCallbacks = walletCallbacks + ) startedNode <- node.start() syncedNode <- syncNeutrinoNode(startedNode, bitcoind) - //callbacks are executed asynchronously, which is how we fund the wallet - //so we need to wait until the wallet balances are correct + // callbacks are executed asynchronously, which is how we fund the wallet + // so we need to wait until the wallet balances are correct _ <- BitcoinSWalletTest.awaitWalletBalances(fundedWallet)( appConfig.walletConf, - system) + system + ) } yield { - NeutrinoNodeFundedWalletBitcoind(node = syncedNode, - wallet = fundedWallet.wallet, - bitcoindRpc = fundedWallet.bitcoind) + NeutrinoNodeFundedWalletBitcoind( + node = syncedNode, + wallet = fundedWallet.wallet, + bitcoindRpc = fundedWallet.bitcoind + ) } } def createNeutrinoNodeFundedWalletFromBitcoind( bitcoind: BitcoindRpcClient, - walletCallbacks: WalletCallbacks)(implicit + walletCallbacks: WalletCallbacks + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): Future[ - NeutrinoNodeFundedWalletBitcoind] = { + appConfig: BitcoinSAppConfig + ): Future[NeutrinoNodeFundedWalletBitcoind] = { import system.dispatcher require(appConfig.nodeConf.nodeType == NodeType.NeutrinoNode) for { _ <- appConfig.walletConf.kmConf.start() - node <- createNeutrinoNode(bitcoind, None)(system, - appConfig.chainConf, - appConfig.nodeConf) + node <- createNeutrinoNode(bitcoind, None)( + system, + appConfig.chainConf, + appConfig.nodeConf + ) fundedWallet <- BitcoinSWalletTest.fundedWalletAndBitcoind( bitcoindRpcClient = bitcoind, nodeApi = node, chainQueryApi = bitcoind, - walletCallbacks = walletCallbacks) + walletCallbacks = walletCallbacks + ) startedNode <- node.start() - _ <- NodeTestUtil.awaitConnectionCount(node = node, - expectedConnectionCount = 1) - //callbacks are executed asynchronously, which is how we fund the wallet - //so we need to wait until the wallet balances are correct + _ <- NodeTestUtil.awaitConnectionCount( + node = node, + expectedConnectionCount = 1 + ) + // callbacks are executed asynchronously, which is how we fund the wallet + // so we need to wait until the wallet balances are correct _ <- BitcoinSWalletTest.awaitWalletBalances(fundedWallet)( appConfig.walletConf, - system) + system + ) } yield { - NeutrinoNodeFundedWalletBitcoind(node = startedNode, - wallet = fundedWallet.wallet, - bitcoindRpc = fundedWallet.bitcoind) + NeutrinoNodeFundedWalletBitcoind( + node = startedNode, + wallet = fundedWallet.wallet, + bitcoindRpc = fundedWallet.bitcoind + ) } } private def destroyNodeFundedWalletBitcoind( - fundedWalletBitcoind: NodeFundedWalletBitcoind)(implicit + fundedWalletBitcoind: NodeFundedWalletBitcoind + )(implicit system: ActorSystem, - appConfig: BitcoinSAppConfig): Future[Unit] = { + appConfig: BitcoinSAppConfig + ): Future[Unit] = { import system.dispatcher val walletWithBitcoind = { - WalletWithBitcoindRpc(fundedWalletBitcoind.wallet, - fundedWalletBitcoind.bitcoindRpc, - appConfig.walletConf) + WalletWithBitcoindRpc( + fundedWalletBitcoind.wallet, + fundedWalletBitcoind.bitcoindRpc, + appConfig.walletConf + ) } - //these need to be done in order, as the spv node needs to be - //stopped before the bitcoind node is stopped + // these need to be done in order, as the spv node needs to be + // stopped before the bitcoind node is stopped val destroyedF = for { _ <- BitcoinSWalletTest.destroyOnlyWalletWithBitcoindCached( - walletWithBitcoind) + walletWithBitcoind + ) _ <- destroyNodeConnectedWithBitcoind( - fundedWalletBitcoind.toNodeConnectedWithBitcoind) + fundedWalletBitcoind.toNodeConnectedWithBitcoind + ) } yield () destroyedF } - def createPeer(bitcoind: BitcoindRpcClient)(implicit - executionContext: ExecutionContext): Future[Peer] = { + def createPeer( + bitcoind: BitcoindRpcClient + )(implicit executionContext: ExecutionContext): Future[Peer] = { NodeTestUtil.getBitcoindPeer(bitcoind) } @@ -347,15 +402,17 @@ object NodeUnitTest extends P2PLogger { Peer(id = None, socket = socket, socks5ProxyParams = None) } - /** Creates a Neutrino node peered with the given bitcoind client, this does NOT - * start the neutrino node + /** Creates a Neutrino node peered with the given bitcoind client, this does + * NOT start the neutrino node */ def createNeutrinoNode( bitcoind: BitcoindRpcClient, - walletCreationTimeOpt: Option[Instant])(implicit + walletCreationTimeOpt: Option[Instant] + )(implicit system: ActorSystem, chainAppConfig: ChainAppConfig, - nodeAppConfig: NodeAppConfig): Future[NeutrinoNode] = { + nodeAppConfig: NodeAppConfig + ): Future[NeutrinoNode] = { import system.dispatcher val checkConfigF = Future { @@ -368,24 +425,27 @@ object NodeUnitTest extends P2PLogger { _ <- nodeAppConfig.start() peer <- createPeer(bitcoind) } yield { - NeutrinoNode(walletCreationTimeOpt, - paramPeers = Vector(peer), - nodeConfig = nodeAppConfig, - chainConfig = chainAppConfig, - actorSystem = system) + NeutrinoNode( + walletCreationTimeOpt, + paramPeers = Vector(peer), + nodeConfig = nodeAppConfig, + chainConfig = chainAppConfig, + actorSystem = system + ) } nodeF } - /** Creates a Neutrino node peered with the given peer, this does NOT - * start the neutrino node + /** Creates a Neutrino node peered with the given peer, this does NOT start + * the neutrino node */ def createNeutrinoNode(peer: Peer, walletCreationTimeOpt: Option[Instant])( implicit system: ActorSystem, chainAppConfig: ChainAppConfig, - nodeAppConfig: NodeAppConfig): Future[NeutrinoNode] = { + nodeAppConfig: NodeAppConfig + ): Future[NeutrinoNode] = { import system.dispatcher val checkConfigF = Future { @@ -397,25 +457,29 @@ object NodeUnitTest extends P2PLogger { _ <- chainAppConfig.start() _ <- nodeAppConfig.start() } yield { - NeutrinoNode(walletCreationTimeOpt, - paramPeers = Vector(peer), - nodeConfig = nodeAppConfig, - chainConfig = chainAppConfig, - actorSystem = system) + NeutrinoNode( + walletCreationTimeOpt, + paramPeers = Vector(peer), + nodeConfig = nodeAppConfig, + chainConfig = chainAppConfig, + actorSystem = system + ) } nodeF } - /** Creates a Neutrino node peered with the given bitcoind client, this does NOT - * start the neutrino node + /** Creates a Neutrino node peered with the given bitcoind client, this does + * NOT start the neutrino node */ def createNeutrinoNode( bitcoinds: Vector[BitcoindRpcClient], - creationTimeOpt: Option[Instant])(implicit + creationTimeOpt: Option[Instant] + )(implicit system: ActorSystem, chainAppConfig: ChainAppConfig, - nodeAppConfig: NodeAppConfig): Future[NeutrinoNode] = { + nodeAppConfig: NodeAppConfig + ): Future[NeutrinoNode] = { import system.dispatcher val checkConfigF = Future { @@ -429,26 +493,30 @@ object NodeUnitTest extends P2PLogger { _ <- nodeAppConfig.start() peers <- peersF } yield { - NeutrinoNode(walletCreationTimeOpt = creationTimeOpt, - paramPeers = peers, - nodeConfig = nodeAppConfig, - chainConfig = chainAppConfig, - actorSystem = system) + NeutrinoNode( + walletCreationTimeOpt = creationTimeOpt, + paramPeers = peers, + nodeConfig = nodeAppConfig, + chainConfig = chainAppConfig, + actorSystem = system + ) } nodeF } def syncNeutrinoNode(node: NeutrinoNode, bitcoind: BitcoindRpcClient)(implicit - system: ActorSystem): Future[NeutrinoNode] = { + system: ActorSystem + ): Future[NeutrinoNode] = { import system.dispatcher for { syncing <- node.chainApiFromDb().flatMap(_.isSyncing()) newNode <- { if (syncing) { - //do nothing as we are already syncing + // do nothing as we are already syncing logger.info( - s"Node is already syncing, skipping initiating a new sync.") + s"Node is already syncing, skipping initiating a new sync." + ) NodeTestUtil.awaitSyncAndIBD(node, bitcoind).map(_ => node) } else { neutrinoNodeSyncHelper(node, bitcoind) @@ -459,13 +527,13 @@ object NodeUnitTest extends P2PLogger { private def neutrinoNodeSyncHelper( node: NeutrinoNode, - bitcoind: BitcoindRpcClient)(implicit - system: ActorSystem): Future[NeutrinoNode] = { + bitcoind: BitcoindRpcClient + )(implicit system: ActorSystem): Future[NeutrinoNode] = { import system.dispatcher for { - //wait for bitcoind to be synced internally - //see: https://github.com/bitcoin/bitcoin/issues/27085 - //see: https://github.com/bitcoin-s/bitcoin-s/issues/4976 + // wait for bitcoind to be synced internally + // see: https://github.com/bitcoin/bitcoin/issues/27085 + // see: https://github.com/bitcoin-s/bitcoin-s/issues/4976 _ <- bitcoind.syncWithValidationInterfaceQueue() _ <- node.sync() _ <- AsyncUtil.retryUntilSatisfiedF(() => @@ -473,10 +541,10 @@ object NodeUnitTest extends P2PLogger { } yield node } - /** This is needed for postgres, we do not drop tables in between individual tests with postgres - * rather an entire test suite shares the same postgres database. - * therefore, we need to clean the database after each test, so that migrations can be applied during - * the setup phase for the next test. + /** This is needed for postgres, we do not drop tables in between individual + * tests with postgres rather an entire test suite shares the same postgres + * database. therefore, we need to clean the database after each test, so + * that migrations can be applied during the setup phase for the next test. * @param appConfig */ private def cleanTables(appConfig: BitcoinSAppConfig): Unit = { diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/fixture/NodeConnectedWithBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/fixture/NodeConnectedWithBitcoind.scala index 8a409fe5cd..9bb5451986 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/fixture/NodeConnectedWithBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/fixture/NodeConnectedWithBitcoind.scala @@ -4,7 +4,9 @@ import org.bitcoins.node.{NeutrinoNode, Node} import org.bitcoins.rpc.client.common.BitcoindRpcClient import org.bitcoins.rpc.client.v22.BitcoindV22RpcClient -/** Gives us a fixture that has a Neutrino node connected with the bitcoind instance */ +/** Gives us a fixture that has a Neutrino node connected with the bitcoind + * instance + */ trait NodeConnectedWithBitcoind { def node: Node def bitcoind: BitcoindRpcClient @@ -12,8 +14,8 @@ trait NodeConnectedWithBitcoind { case class NeutrinoNodeConnectedWithBitcoind( node: NeutrinoNode, - bitcoind: BitcoindRpcClient) - extends NodeConnectedWithBitcoind + bitcoind: BitcoindRpcClient +) extends NodeConnectedWithBitcoind trait NodeConnectedWithBitcoinds { def node: Node @@ -27,9 +29,10 @@ case class NeutrinoNodeConnectedWithBitcoinds( case class NeutrinoNodeConnectedWithBitcoindV22( node: NeutrinoNode, - bitcoind: BitcoindV22RpcClient) - extends NodeConnectedWithBitcoind + bitcoind: BitcoindV22RpcClient +) extends NodeConnectedWithBitcoind case class NeutrinoNodeNotConnectedWithBitcoinds( node: NeutrinoNode, - bitcoinds: Vector[BitcoindRpcClient]) + bitcoinds: Vector[BitcoindRpcClient] +) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/oracle/OracleTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/oracle/OracleTestUtil.scala index 7d5c3afc0a..fb0ae77891 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/oracle/OracleTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/oracle/OracleTestUtil.scala @@ -7,8 +7,9 @@ import scala.concurrent.{ExecutionContext, Future} object OracleTestUtil { - def destroyDLCOracleAppConfig(config: DLCOracleAppConfig)(implicit - ec: ExecutionContext): Future[Unit] = { + def destroyDLCOracleAppConfig( + config: DLCOracleAppConfig + )(implicit ec: ExecutionContext): Future[Unit] = { val _ = config.clean() for { _ <- config.stop() diff --git a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala index 91a33c7b27..e6ba1910a5 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindFixtures.scala @@ -18,12 +18,14 @@ trait BitcoindFixtures extends BitcoinSFixture with EmbeddedPg { def withNewestFundedBitcoindCached( test: OneArgAsyncTest, - bitcoind: BitcoindRpcClient): FutureOutcome = { + bitcoind: BitcoindRpcClient + ): FutureOutcome = { makeDependentFixture[BitcoindRpcClient]( () => Future.successful(bitcoind), { case _ => Future.unit // don't want to destroy anything since it is cached - })(test) + } + )(test) } } @@ -47,8 +49,8 @@ trait BitcoindFixturesFundedCached extends BitcoindFixtures { } } -/** Test trait that caches a [[BitcoindV22RpcClient]] that is funded - * and available to use with fixtures +/** Test trait that caches a [[BitcoindV22RpcClient]] that is funded and + * available to use with fixtures */ trait BitcoindFixturesFundedCachedV22 extends BitcoinSAsyncFixtureTest @@ -67,12 +69,14 @@ trait BitcoindFixturesFundedCachedV22 def withV22FundedBitcoindCached( test: OneArgAsyncTest, - bitcoind: BitcoindV22RpcClient): FutureOutcome = { + bitcoind: BitcoindV22RpcClient + ): FutureOutcome = { makeDependentFixture[BitcoindV22RpcClient]( () => Future.successful(bitcoind), { case _ => Future.unit // don't want to destroy anything since it is cached - })(test) + } + )(test) } override def afterAll(): Unit = { @@ -81,8 +85,8 @@ trait BitcoindFixturesFundedCachedV22 } } -/** Test trait that caches a [[BitcoindV23RpcClient]] that is funded - * and available to use with fixtures +/** Test trait that caches a [[BitcoindV23RpcClient]] that is funded and + * available to use with fixtures */ trait BitcoindFixturesFundedCachedV23 extends BitcoinSAsyncFixtureTest @@ -101,12 +105,14 @@ trait BitcoindFixturesFundedCachedV23 def withV23FundedBitcoindCached( test: OneArgAsyncTest, - bitcoind: BitcoindV23RpcClient): FutureOutcome = { + bitcoind: BitcoindV23RpcClient + ): FutureOutcome = { makeDependentFixture[BitcoindV23RpcClient]( () => Future.successful(bitcoind), { case _ => Future.unit // don't want to destroy anything since it is cached - })(test) + } + )(test) } override def afterAll(): Unit = { @@ -132,12 +138,14 @@ trait BitcoindFixturesFundedCachedV24 def withV24FundedBitcoindCached( test: OneArgAsyncTest, - bitcoind: BitcoindV24RpcClient): FutureOutcome = { + bitcoind: BitcoindV24RpcClient + ): FutureOutcome = { makeDependentFixture[BitcoindV24RpcClient]( () => Future.successful(bitcoind), { _ => Future.unit // don't want to destroy anything since it is cached - })(test) + } + )(test) } override def afterAll(): Unit = { @@ -175,19 +183,22 @@ trait BitcoindFixturesCachedPair[T <: BitcoindRpcClient] def with2BitcoindsCached( test: OneArgAsyncTest, - bitcoinds: NodePair[T]): FutureOutcome = { + bitcoinds: NodePair[T] + ): FutureOutcome = { makeDependentFixture[NodePair[T]]( () => Future.successful(bitcoinds), destroy = { case _: NodePair[T] => - //do nothing since we are caching bitcoinds - //the test trait may want to re-use them + // do nothing since we are caching bitcoinds + // the test trait may want to re-use them Future.unit } )(test) } } -/** Bitcoind fixtures with two cached bitcoind rpc clients that are [[BitcoindVersion.newest]] that are connected via p2p */ +/** Bitcoind fixtures with two cached bitcoind rpc clients that are + * [[BitcoindVersion.newest]] that are connected via p2p + */ trait BitcoindFixturesCachedPairV22 extends BitcoinSAsyncFixtureTest with BitcoindFixturesCachedPair[BitcoindV22RpcClient] { @@ -239,12 +250,13 @@ trait BitcoindFixturesCachedTriple[T <: BitcoindRpcClient] def with3BitcoindsCached( test: OneArgAsyncTest, - bitcoinds: NodeTriple[T]): FutureOutcome = { + bitcoinds: NodeTriple[T] + ): FutureOutcome = { makeDependentFixture[NodeTriple[T]]( () => Future.successful(bitcoinds), destroy = { case _: NodeTriple[T] => - //do nothing since we are caching bitcoinds - //the test trait may want to re-use them + // do nothing since we are caching bitcoinds + // the test trait may want to re-use them Future.unit } )(test) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala index 87350f9d30..6bc8aaa609 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/rpc/BitcoindRpcTestUtil.scala @@ -68,14 +68,18 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { val hashTx = newInetSocketAddres val rawBlock = newInetSocketAddres val rawTx = newInetSocketAddres - val zmqConfig = ZmqConfig(hashBlock = Some(hashBlock), - rawBlock = Some(rawBlock), - hashTx = Some(hashTx), - rawTx = Some(rawTx)) - config(uri = newUri, - rpcUri = newUri, - zmqConfig = zmqConfig, - pruneMode = false) + val zmqConfig = ZmqConfig( + hashBlock = Some(hashBlock), + rawBlock = Some(rawBlock), + hashTx = Some(hashTx), + rawTx = Some(rawTx) + ) + config( + uri = newUri, + rpcUri = newUri, + zmqConfig = zmqConfig, + pruneMode = false + ) } def config( @@ -83,17 +87,18 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { rpcUri: URI, zmqConfig: ZmqConfig, pruneMode: Boolean, - blockFilterIndex: Boolean = false): BitcoindConfig = { + blockFilterIndex: Boolean = false + ): BitcoindConfig = { val pass = FileUtil.randomDirName val username = "random_user_name" /* pruning and txindex are not compatible */ val txindex = if (pruneMode) 0 else 1 - //windows environments don't allow the -daemon flag - //see: https://github.com/bitcoin-s/bitcoin-s/issues/3684 + // windows environments don't allow the -daemon flag + // see: https://github.com/bitcoin-s/bitcoin-s/issues/3684 val isDaemon = if (EnvUtil.isWindows) 0 else 1 - //if bitcoind is not a daemon, we get a ton of logs - //from bitcoind written to stdout, so turn off debug if we are not a daemon + // if bitcoind is not a daemon, we get a ton of logs + // from bitcoind written to stdout, so turn off debug if we are not a daemon val isDebug = if (isDaemon == 1) 1 else 0 val conf = s""" |regtest=1 @@ -140,9 +145,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { BitcoindConfig(config = configTor, datadir = FileUtil.tmpDir()) } - /** Creates a `bitcoind` config within the system temp - * directory, writes the file and returns the written - * file + /** Creates a `bitcoind` config within the system temp directory, writes the + * file and returns the written file */ def writtenConfig( uri: URI, @@ -151,11 +155,13 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { pruneMode: Boolean, blockFilterIndex: Boolean = false ): Path = { - val conf = config(uri = uri, - rpcUri = rpcUri, - zmqConfig = zmqConfig, - pruneMode = pruneMode, - blockFilterIndex = blockFilterIndex) + val conf = config( + uri = uri, + rpcUri = rpcUri, + zmqConfig = zmqConfig, + pruneMode = pruneMode, + blockFilterIndex = blockFilterIndex + ) val datadir = conf.datadir val written = BitcoindConfig.writeConfigToFile(conf, datadir) @@ -167,7 +173,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { def getBinary( version: BitcoindVersion, - binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory): File = + binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory + ): File = version match { // default to newest version case Unknown => getBinary(BitcoindVersion.newest, binaryDirectory) @@ -184,7 +191,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { if (filtered.isEmpty) throw new RuntimeException( - s"bitcoind ${known.toString} is not installed in $binaryDirectory. Run `sbt downloadBitcoind`") + s"bitcoind ${known.toString} is not installed in $binaryDirectory. Run `sbt downloadBitcoind`" + ) // might be multiple versions downloaded for // each major version, i.e. 0.16.2 and 0.16.3 @@ -204,16 +212,18 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { pruneMode: Boolean = false, versionOpt: Option[BitcoindVersion] = None, binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory, - enableNeutrino: Boolean = true)(implicit - system: ActorSystem): BitcoindInstanceLocal = { + enableNeutrino: Boolean = true + )(implicit system: ActorSystem): BitcoindInstanceLocal = { val uri = new URI("http://localhost:" + port) val rpcUri = new URI("http://localhost:" + rpcPort) val configFile = - writtenConfig(uri, - rpcUri, - zmqConfig, - pruneMode, - blockFilterIndex = enableNeutrino) + writtenConfig( + uri, + rpcUri, + zmqConfig, + pruneMode, + blockFilterIndex = enableNeutrino + ) val conf = BitcoindConfig(configFile) val binary: File = versionOpt match { case Some(version) => getBinary(version) @@ -223,7 +233,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } else { throw new RuntimeException( "Could not locate bitcoind. Make sure it is installed on your PATH, or if working with Bitcoin-S " + - "directly, try running 'sbt downloadBitcoind'") + "directly, try running 'sbt downloadBitcoind'" + ) } } @@ -238,12 +249,14 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { pruneMode: Boolean = false, binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory )(implicit system: ActorSystem): BitcoindInstanceLocal = - instance(port = port, - rpcPort = rpcPort, - zmqConfig = zmqConfig, - pruneMode = pruneMode, - versionOpt = Some(BitcoindVersion.V22), - binaryDirectory = binaryDirectory) + instance( + port = port, + rpcPort = rpcPort, + zmqConfig = zmqConfig, + pruneMode = pruneMode, + versionOpt = Some(BitcoindVersion.V22), + binaryDirectory = binaryDirectory + ) def v23Instance( port: Int = RpcUtil.randomPort, @@ -252,12 +265,14 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { pruneMode: Boolean = false, binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory )(implicit system: ActorSystem): BitcoindInstanceLocal = - instance(port = port, - rpcPort = rpcPort, - zmqConfig = zmqConfig, - pruneMode = pruneMode, - versionOpt = Some(BitcoindVersion.V23), - binaryDirectory = binaryDirectory) + instance( + port = port, + rpcPort = rpcPort, + zmqConfig = zmqConfig, + pruneMode = pruneMode, + versionOpt = Some(BitcoindVersion.V23), + binaryDirectory = binaryDirectory + ) def v24Instance( port: Int = RpcUtil.randomPort, @@ -266,12 +281,14 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { pruneMode: Boolean = false, binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory )(implicit system: ActorSystem): BitcoindInstanceLocal = - instance(port = port, - rpcPort = rpcPort, - zmqConfig = zmqConfig, - pruneMode = pruneMode, - versionOpt = Some(BitcoindVersion.V24), - binaryDirectory = binaryDirectory) + instance( + port = port, + rpcPort = rpcPort, + zmqConfig = zmqConfig, + pruneMode = pruneMode, + versionOpt = Some(BitcoindVersion.V24), + binaryDirectory = binaryDirectory + ) /** Gets an instance of bitcoind with the given version */ def getInstance( @@ -280,35 +297,43 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { rpcPort: Int = RpcUtil.randomPort, zmqConfig: ZmqConfig = RpcUtil.zmqConfig, pruneMode: Boolean = false, - binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory)(implicit - system: ActorSystem): BitcoindInstanceLocal = { + binaryDirectory: Path = BitcoindRpcTestClient.sbtBinaryDirectory + )(implicit system: ActorSystem): BitcoindInstanceLocal = { bitcoindVersion match { case BitcoindVersion.V22 => - BitcoindRpcTestUtil.v22Instance(port, - rpcPort, - zmqConfig, - pruneMode, - binaryDirectory = binaryDirectory) + BitcoindRpcTestUtil.v22Instance( + port, + rpcPort, + zmqConfig, + pruneMode, + binaryDirectory = binaryDirectory + ) case BitcoindVersion.V23 => - BitcoindRpcTestUtil.v23Instance(port, - rpcPort, - zmqConfig, - pruneMode, - binaryDirectory = binaryDirectory) + BitcoindRpcTestUtil.v23Instance( + port, + rpcPort, + zmqConfig, + pruneMode, + binaryDirectory = binaryDirectory + ) case BitcoindVersion.V24 => - BitcoindRpcTestUtil.v24Instance(port, - rpcPort, - zmqConfig, - pruneMode, - binaryDirectory = binaryDirectory) + BitcoindRpcTestUtil.v24Instance( + port, + rpcPort, + zmqConfig, + pruneMode, + binaryDirectory = binaryDirectory + ) case BitcoindVersion.Unknown => sys.error( - s"Could not create a bitcoind version with version=${BitcoindVersion.Unknown}") + s"Could not create a bitcoind version with version=${BitcoindVersion.Unknown}" + ) } } - def startServers(servers: Vector[BitcoindRpcClient])(implicit - ec: ExecutionContext): Future[Unit] = { + def startServers( + servers: Vector[BitcoindRpcClient] + )(implicit ec: ExecutionContext): Future[Unit] = { val startedServersF = Future.traverse(servers) { server => server.start().flatMap { res => val createWalletF = for { @@ -329,8 +354,9 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { /** Stops the given servers and deletes their data directories */ - def stopServers(servers: Vector[BitcoindRpcClient])(implicit - system: ActorSystem): Future[Unit] = { + def stopServers( + servers: Vector[BitcoindRpcClient] + )(implicit system: ActorSystem): Future[Unit] = { implicit val ec: ExecutionContextExecutor = system.getDispatcher val serverStopsF = Future.traverse(servers) { s => @@ -351,8 +377,9 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { /** Stops the given server and deletes its data directory */ - def stopServer(server: BitcoindRpcClient)(implicit - system: ActorSystem): Future[Unit] = { + def stopServer( + server: BitcoindRpcClient + )(implicit system: ActorSystem): Future[Unit] = { stopServers(Vector(server)) } @@ -362,7 +389,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { from: BitcoindRpcClient, to: BitcoindRpcClient, interval: FiniteDuration = 100.milliseconds, - maxTries: Int = 50)(implicit system: ActorSystem): Future[Unit] = { + maxTries: Int = 50 + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher val isConnected: () => Future[Boolean] = () => { @@ -373,43 +401,49 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } } - AsyncUtil.retryUntilSatisfiedF(conditionF = isConnected, - interval = interval, - maxTries = maxTries) + AsyncUtil.retryUntilSatisfiedF( + conditionF = isConnected, + interval = interval, + maxTries = maxTries + ) } /** Return index of output of TX `txid` with value `amount` * - * @see function we're mimicking in - * [[https://github.com/bitcoin/bitcoin/blob/master/test/functional/test_framework/util.py#L410 Core test suite]] + * @see + * function we're mimicking in + * [[https://github.com/bitcoin/bitcoin/blob/master/test/functional/test_framework/util.py#L410 Core test suite]] */ def findOutput( client: BitcoindRpcClient, txid: DoubleSha256DigestBE, amount: Bitcoins, - blockhash: Option[DoubleSha256DigestBE] = None)(implicit - executionContext: ExecutionContext): Future[UInt32] = { + blockhash: Option[DoubleSha256DigestBE] = None + )(implicit executionContext: ExecutionContext): Future[UInt32] = { client.getRawTransaction(txid, blockhash).map { tx => tx.vout.zipWithIndex .find { case (output, _) => output.value == amount } .map { case (_, i) => UInt32(i) } - .getOrElse(throw new RuntimeException( - s"Could not find output for $amount in TX ${txid.hex}")) + .getOrElse( + throw new RuntimeException( + s"Could not find output for $amount in TX ${txid.hex}" + ) + ) } } - /** Generates the specified amount of blocks with all provided clients - * and waits until they are synced. + /** Generates the specified amount of blocks with all provided clients and + * waits until they are synced. * - * @return Vector of Blockhashes of generated blocks, with index corresponding to the - * list of provided clients + * @return + * Vector of Blockhashes of generated blocks, with index corresponding to + * the list of provided clients */ - def generateAllAndSync( - clients: Vector[BitcoindRpcClient], - blocks: Int = 6)(implicit - system: ActorSystem): Future[Vector[Vector[DoubleSha256DigestBE]]] = { + def generateAllAndSync(clients: Vector[BitcoindRpcClient], blocks: Int = 6)( + implicit system: ActorSystem + ): Future[Vector[Vector[DoubleSha256DigestBE]]] = { import system.dispatcher val sliding: Vector[Vector[BitcoindRpcClient]] = @@ -428,13 +462,15 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { genereratedHashesF.map(_.reverse.toVector) } - /** Generates the specified amount of blocks and waits until - * the provided clients are synced. + /** Generates the specified amount of blocks and waits until the provided + * clients are synced. * - * @return Blockhashes of generated blocks + * @return + * Blockhashes of generated blocks */ def generateAndSync(clients: Vector[BitcoindRpcClient], blocks: Int = 6)( - implicit system: ActorSystem): Future[Vector[DoubleSha256DigestBE]] = { + implicit system: ActorSystem + ): Future[Vector[DoubleSha256DigestBE]] = { require(clients.length > 1, "Can't sync less than 2 nodes") import system.dispatcher @@ -456,7 +492,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { client1: BitcoindRpcClient, client2: BitcoindRpcClient, interval: FiniteDuration = BitcoindRpcTestUtil.DEFAULT_LONG_INTERVAL, - maxTries: Int = 50)(implicit system: ActorSystem): Future[Unit] = { + maxTries: Int = 50 + )(implicit system: ActorSystem): Future[Unit] = { implicit val ec: ExecutionContextExecutor = system.dispatcher def isSynced(): Future[Boolean] = { @@ -467,16 +504,19 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } } - AsyncUtil.retryUntilSatisfiedF(conditionF = () => isSynced(), - interval = interval, - maxTries = maxTries) + AsyncUtil.retryUntilSatisfiedF( + conditionF = () => isSynced(), + interval = interval, + maxTries = maxTries + ) } def awaitSameBlockHeight( client1: BitcoindRpcClient, client2: BitcoindRpcClient, interval: FiniteDuration = BitcoindRpcTestUtil.DEFAULT_LONG_INTERVAL, - maxTries: Int = 50)(implicit system: ActorSystem): Future[Unit] = { + maxTries: Int = 50 + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher def isSameBlockHeight(): Future[Boolean] = { @@ -487,16 +527,19 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } } - AsyncUtil.retryUntilSatisfiedF(conditionF = () => isSameBlockHeight(), - interval = interval, - maxTries = maxTries) + AsyncUtil.retryUntilSatisfiedF( + conditionF = () => isSameBlockHeight(), + interval = interval, + maxTries = maxTries + ) } def awaitDisconnected( from: BitcoindRpcClient, to: BitcoindRpcClient, interval: FiniteDuration = 100.milliseconds, - maxTries: Int = 50)(implicit system: ActorSystem): Future[Unit] = { + maxTries: Int = 50 + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher def isDisconnected(): Future[Boolean] = { @@ -507,30 +550,37 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { case exception: BitcoindException if exception.getMessage().contains("Node has not been added") => from.getPeerInfo.map( - _.forall(_.networkInfo.addr != to.instance.uri)) + _.forall(_.networkInfo.addr != to.instance.uri) + ) } } - AsyncUtil.retryUntilSatisfiedF(conditionF = () => isDisconnected(), - interval = interval, - maxTries = maxTries) + AsyncUtil.retryUntilSatisfiedF( + conditionF = () => isDisconnected(), + interval = interval, + maxTries = maxTries + ) } def awaitStopped( client: BitcoindRpcClient, interval: FiniteDuration = 100.milliseconds, - maxTries: Int = 50)(implicit system: ActorSystem): Future[Unit] = { + maxTries: Int = 50 + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher - AsyncUtil.retryUntilSatisfiedF(conditionF = { () => client.isStoppedF }, - interval = interval, - maxTries = maxTries) + AsyncUtil.retryUntilSatisfiedF( + conditionF = { () => client.isStoppedF }, + interval = interval, + maxTries = maxTries + ) } def removeDataDirectory( client: BitcoindRpcClient, interval: FiniteDuration = 100.milliseconds, - maxTries: Int = 50)(implicit system: ActorSystem): Future[Unit] = { + maxTries: Int = 50 + )(implicit system: ActorSystem): Future[Unit] = { implicit val ec = system.dispatcher AsyncUtil .retryUntilSatisfiedF( @@ -557,7 +607,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { def createUnconnectedNodePair( clientAccum: RpcClientAccum = Vector.newBuilder )(implicit - system: ActorSystem): Future[(BitcoindRpcClient, BitcoindRpcClient)] = { + system: ActorSystem + ): Future[(BitcoindRpcClient, BitcoindRpcClient)] = { implicit val ec: ExecutionContextExecutor = system.getDispatcher val client1: BitcoindRpcClient = BitcoindRpcClient.withActorSystem(instance()) @@ -570,8 +621,9 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } } - def syncPairs(pairs: Vector[(BitcoindRpcClient, BitcoindRpcClient)])(implicit - system: ActorSystem): Future[Unit] = { + def syncPairs( + pairs: Vector[(BitcoindRpcClient, BitcoindRpcClient)] + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher val futures = pairs.map { case (first, second) => BitcoindRpcTestUtil.awaitSynced(first, second) @@ -582,8 +634,9 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { /** Connects and waits non-blockingly until all the provided pairs of clients * are connected */ - def connectPairs(pairs: Vector[(BitcoindRpcClient, BitcoindRpcClient)])( - implicit system: ActorSystem): Future[Unit] = { + def connectPairs( + pairs: Vector[(BitcoindRpcClient, BitcoindRpcClient)] + )(implicit system: ActorSystem): Future[Unit] = { import system.dispatcher val addNodesF: Future[Vector[Unit]] = { val addedF = pairs.map { case (first, second) => @@ -605,8 +658,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { private def createNodeSequence[T <: BitcoindRpcClient]( numNodes: Int, - version: BitcoindVersion)(implicit - system: ActorSystem): Future[Vector[T]] = { + version: BitcoindVersion + )(implicit system: ActorSystem): Future[Vector[T]] = { import system.dispatcher val clients: Vector[T] = (0 until numNodes).map { _ => @@ -615,13 +668,16 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { BitcoindRpcClient.withActorSystem(BitcoindRpcTestUtil.instance()) case BitcoindVersion.V22 => BitcoindV22RpcClient.withActorSystem( - BitcoindRpcTestUtil.v22Instance()) + BitcoindRpcTestUtil.v22Instance() + ) case BitcoindVersion.V23 => BitcoindV23RpcClient.withActorSystem( - BitcoindRpcTestUtil.v23Instance()) + BitcoindRpcTestUtil.v23Instance() + ) case BitcoindVersion.V24 => BitcoindV24RpcClient.withActorSystem( - BitcoindRpcTestUtil.v24Instance()) + BitcoindRpcTestUtil.v24Instance() + ) } // this is safe as long as this method is never @@ -647,8 +703,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { private def createNodePairInternal[T <: BitcoindRpcClient]( version: BitcoindVersion, - clientAccum: RpcClientAccum)(implicit - system: ActorSystem): Future[(T, T)] = { + clientAccum: RpcClientAccum + )(implicit system: ActorSystem): Future[(T, T)] = { import system.dispatcher createNodePairInternal[T](version).map { pair => @@ -658,8 +714,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } private def createNodePairInternal[T <: BitcoindRpcClient]( - version: BitcoindVersion)(implicit - system: ActorSystem): Future[(T, T)] = { + version: BitcoindVersion + )(implicit system: ActorSystem): Future[(T, T)] = { import system.dispatcher createNodeSequence[T](numNodes = 2, version).map { @@ -669,28 +725,35 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } } - /** Returns a pair of [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] + /** Returns a pair of + * [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] * that are connected with some blocks in the chain */ def createNodePair[T <: BitcoindRpcClient]( - clientAccum: RpcClientAccum = Vector.newBuilder)(implicit - system: ActorSystem): Future[(BitcoindRpcClient, BitcoindRpcClient)] = + clientAccum: RpcClientAccum = Vector.newBuilder + )(implicit + system: ActorSystem + ): Future[(BitcoindRpcClient, BitcoindRpcClient)] = createNodePair[T](BitcoindVersion.newest).map { pair => clientAccum.++=(Vector(pair._1, pair._2)) pair }(system.dispatcher) - def createNodePair[T <: BitcoindRpcClient](version: BitcoindVersion)(implicit - system: ActorSystem): Future[(T, T)] = { + def createNodePair[T <: BitcoindRpcClient]( + version: BitcoindVersion + )(implicit system: ActorSystem): Future[(T, T)] = { createNodePairInternal(version) } - /** Returns a pair of [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] + /** Returns a pair of + * [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] * that are not connected but have the same blocks in the chain */ def createUnconnectedNodePairWithBlocks[T <: BitcoindRpcClient]( - clientAccum: RpcClientAccum = Vector.newBuilder)(implicit - system: ActorSystem): Future[(BitcoindRpcClient, BitcoindRpcClient)] = { + clientAccum: RpcClientAccum = Vector.newBuilder + )(implicit + system: ActorSystem + ): Future[(BitcoindRpcClient, BitcoindRpcClient)] = { import system.dispatcher for { (first, second) <- createNodePair(clientAccum) @@ -703,20 +766,24 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } } - def createNodePairV22(clientAccum: RpcClientAccum)(implicit - system: ActorSystem): Future[ + def createNodePairV22( + clientAccum: RpcClientAccum + )(implicit system: ActorSystem): Future[ (BitcoindV22RpcClient, BitcoindV22RpcClient) - ] = //shouldn't this be V22 + ] = // shouldn't this be V22 createNodePairInternal(BitcoindVersion.V22, clientAccum) - /** Returns a pair of [[org.bitcoins.rpc.client.v23.BitcoindV23RpcClient BitcoindV23RpcClient]] + /** Returns a pair of + * [[org.bitcoins.rpc.client.v23.BitcoindV23RpcClient BitcoindV23RpcClient]] * that are connected with some blocks in the chain */ def createNodePairV23(clientAccum: RpcClientAccum)(implicit - system: ActorSystem): Future[(BitcoindV23RpcClient, BitcoindV23RpcClient)] = + system: ActorSystem + ): Future[(BitcoindV23RpcClient, BitcoindV23RpcClient)] = createNodePairInternal(BitcoindVersion.V23, clientAccum) - /** Returns a triple of [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] + /** Returns a triple of + * [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] * that are connected with some blocks in the chain */ private def createNodeTripleInternal[T <: BitcoindRpcClient]( @@ -733,7 +800,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } } - /** Returns a triple of [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] + /** Returns a triple of + * [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] * that are connected with some blocks in the chain */ private def createNodeTripleInternal[T <: BitcoindRpcClient]( @@ -748,29 +816,31 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } } - /** Returns a triple of org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient - * that are connected with some blocks in the chain + /** Returns a triple of org.bitcoins.rpc.client.common.BitcoindRpcClient + * BitcoindRpcClient that are connected with some blocks in the chain */ def createNodeTriple( clientAccum: RpcClientAccum - )(implicit system: ActorSystem): Future[ - (BitcoindRpcClient, BitcoindRpcClient, BitcoindRpcClient)] = { + )(implicit + system: ActorSystem + ): Future[(BitcoindRpcClient, BitcoindRpcClient, BitcoindRpcClient)] = { createNodeTripleInternal(BitcoindVersion.Unknown, clientAccum) } - /** Returns a triple of org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient - * that are connected with some blocks in the chain + /** Returns a triple of org.bitcoins.rpc.client.common.BitcoindRpcClient + * BitcoindRpcClient that are connected with some blocks in the chain */ - def createNodeTriple[T <: BitcoindRpcClient](version: BitcoindVersion)( - implicit system: ActorSystem): Future[(T, T, T)] = { + def createNodeTriple[T <: BitcoindRpcClient]( + version: BitcoindVersion + )(implicit system: ActorSystem): Future[(T, T, T)] = { createNodeTripleInternal(version) } def createRawCoinbaseTransaction( sender: BitcoindRpcClient, receiver: BitcoindRpcClient, - amount: Bitcoins = Bitcoins(1))(implicit - executionContext: ExecutionContext): Future[Transaction] = { + amount: Bitcoins = Bitcoins(1) + )(implicit executionContext: ExecutionContext): Future[Transaction] = { for { address <- sender.getNewAddress blocks <- sender.generateToAddress(2, address) @@ -778,16 +848,23 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { block1 <- sender.getBlock(blocks(1)) transaction0 <- sender.getTransaction(block0.tx(0)) transaction1 <- sender.getTransaction(block1.tx(0)) - input0 = TransactionOutPoint(transaction0.txid.flip, - UInt32(transaction0.blockindex.get)) - input1 = TransactionOutPoint(transaction1.txid.flip, - UInt32(transaction1.blockindex.get)) + input0 = TransactionOutPoint( + transaction0.txid.flip, + UInt32(transaction0.blockindex.get) + ) + input1 = TransactionOutPoint( + transaction1.txid.flip, + UInt32(transaction1.blockindex.get) + ) sig: ScriptSignature = ScriptSignature.empty address <- receiver.getNewAddress tx <- sender.createRawTransaction( - Vector(TransactionInput(input0, sig, UInt32(1)), - TransactionInput(input1, sig, UInt32(2))), - Map(address -> amount)) + Vector( + TransactionInput(input0, sig, UInt32(1)), + TransactionInput(input1, sig, UInt32(2)) + ), + Map(address -> amount) + ) } yield tx } @@ -795,12 +872,15 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { /** Bitcoin Core 0.16 and 0.17 has diffrent APIs for signing raw transactions. * This method tries to construct either a * [[org.bitcoins.rpc.client.v16.BitcoindV16RpcClient BitcoindV16RpcClient]] - * or a [[org.bitcoins.rpc.client.v16.BitcoindV16RpcClient BitcoindV16RpcClient]] - * from the provided `signer`, and then calls the appropriate method on the result. + * or a + * [[org.bitcoins.rpc.client.v16.BitcoindV16RpcClient BitcoindV16RpcClient]] + * from the provided `signer`, and then calls the appropriate method on the + * result. * - * @throws RuntimeException if no versioned - * [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] - * can be constructed. + * @throws RuntimeException + * if no versioned + * [[org.bitcoins.rpc.client.common.BitcoindRpcClient BitcoindRpcClient]] + * can be constructed. */ def signRawTransaction( signer: BitcoindRpcClient, @@ -816,14 +896,16 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { v22.signRawTransactionWithWallet(transaction, utxoDeps) case unknown: BitcoindRpcClient => sys.error( - s"Cannot sign tx with unknown version of bitcoind, got=$unknown") + s"Cannot sign tx with unknown version of bitcoind, got=$unknown" + ) } - /** Gets the pubkey (if it exists) asscociated with a given - * bitcoin address in a version-agnostic manner + /** Gets the pubkey (if it exists) asscociated with a given bitcoin address in + * a version-agnostic manner */ def getPubkey(client: BitcoindRpcClient, address: BitcoinAddress)(implicit - system: ActorSystem): Future[Option[ECPublicKey]] = { + system: ActorSystem + ): Future[Option[ECPublicKey]] = { import system.dispatcher client match { @@ -837,8 +919,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { def sendCoinbaseTransaction( sender: BitcoindRpcClient, receiver: BitcoindRpcClient, - amount: Bitcoins = Bitcoins(1))(implicit - actorSystem: ActorSystem): Future[GetTransactionResult] = { + amount: Bitcoins = Bitcoins(1) + )(implicit actorSystem: ActorSystem): Future[GetTransactionResult] = { implicit val ec: ExecutionContextExecutor = actorSystem.dispatcher for { rawcoinbasetx <- createRawCoinbaseTransaction(sender, receiver, amount) @@ -851,12 +933,12 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } yield transaction } - /** @return The first block (after genesis) in the - * given node's blockchain + /** @return + * The first block (after genesis) in the given node's blockchain */ def getFirstBlock(node: BitcoindRpcClient)(implicit - executionContext: ExecutionContext): Future[ - GetBlockWithTransactionsResult] = { + executionContext: ExecutionContext + ): Future[GetBlockWithTransactionsResult] = { node .getBlockHash(1) .flatMap(node.getBlockWithTransactions) @@ -866,8 +948,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { def waitUntilBlock( blockHeight: Int, client: BitcoindRpcClient, - addressForMining: BitcoinAddress)(implicit - ec: ExecutionContext): Future[Unit] = { + addressForMining: BitcoinAddress + )(implicit ec: ExecutionContext): Future[Unit] = { for { currentCount <- client.getBlockCount() blocksToMine = blockHeight - currentCount @@ -875,15 +957,14 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } yield () } - /** Produces a confirmed transaction from `sender` to `address` - * for `amount` + /** Produces a confirmed transaction from `sender` to `address` for `amount` */ def fundBlockChainTransaction( sender: BitcoindRpcClient, receiver: BitcoindRpcClient, address: BitcoinAddress, - amount: Bitcoins)(implicit - system: ActorSystem): Future[DoubleSha256DigestBE] = { + amount: Bitcoins + )(implicit system: ActorSystem): Future[DoubleSha256DigestBE] = { implicit val ec: ExecutionContextExecutor = system.dispatcher @@ -907,14 +988,13 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } } - /** Produces a unconfirmed transaction from `sender` to `address` - * for `amount` + /** Produces a unconfirmed transaction from `sender` to `address` for `amount` */ def fundMemPoolTransaction( sender: BitcoindRpcClient, address: BitcoinAddress, - amount: Bitcoins)(implicit - system: ActorSystem): Future[DoubleSha256DigestBE] = { + amount: Bitcoins + )(implicit system: ActorSystem): Future[DoubleSha256DigestBE] = { import system.dispatcher sender .createRawTransaction(Vector.empty, Map(address -> amount)) @@ -929,7 +1009,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { /** Stops the provided nodes and deletes their data directories */ def deleteNodePair(client1: BitcoindRpcClient, client2: BitcoindRpcClient)( - implicit executionContext: ExecutionContext): Future[Unit] = { + implicit executionContext: ExecutionContext + ): Future[Unit] = { val stopsF = List(client1, client2).map { client => implicit val sys = client.system for { @@ -944,7 +1025,8 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { /** Checks whether the provided client has seen the given block hash */ def hasSeenBlock(client: BitcoindRpcClient, hash: DoubleSha256DigestBE)( - implicit ec: ExecutionContext): Future[Boolean] = { + implicit ec: ExecutionContext + ): Future[Boolean] = { val p = Promise[Boolean]() client.getBlock(hash.flip).onComplete { @@ -956,31 +1038,33 @@ trait BitcoindRpcTestUtil extends BitcoinSLogger { } def hasSeenBlock(client1: BitcoindRpcClient, hash: DoubleSha256Digest)( - implicit ec: ExecutionContext): Future[Boolean] = { + implicit ec: ExecutionContext + ): Future[Boolean] = { hasSeenBlock(client1, hash.flip) } - /** @param clientAccum If provided, the generated client is added to - * this vectorbuilder. + /** @param clientAccum + * If provided, the generated client is added to this vectorbuilder. */ def startedBitcoindRpcClient( instanceOpt: Option[BitcoindInstanceLocal] = None, - clientAccum: RpcClientAccum)(implicit - system: ActorSystem): Future[BitcoindRpcClient] = { + clientAccum: RpcClientAccum + )(implicit system: ActorSystem): Future[BitcoindRpcClient] = { implicit val ec: ExecutionContextExecutor = system.dispatcher val instance = instanceOpt.getOrElse(BitcoindRpcTestUtil.instance()) require( instance.datadir.getPath.startsWith(Properties.tmpDir), - s"${instance.datadir} is not in user temp dir! This could lead to bad things happening.") + s"${instance.datadir} is not in user temp dir! This could lead to bad things happening." + ) - //start the bitcoind instance so eclair can properly use it + // start the bitcoind instance so eclair can properly use it val rpc = BitcoindRpcClient.withActorSystem(instance) val startedF = startServers(Vector(rpc)) val blocksToGenerate = 102 - //fund the wallet by generating 102 blocks, need this to get over coinbase maturity + // fund the wallet by generating 102 blocks, need this to get over coinbase maturity val generatedF = startedF.flatMap { _ => clientAccum += rpc rpc.generate(blocksToGenerate) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/rpc/CachedBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/rpc/CachedBitcoind.scala index beaf08f83c..9debe93fd8 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/rpc/CachedBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/rpc/CachedBitcoind.scala @@ -11,32 +11,32 @@ import org.bitcoins.testkit.util.BitcoinSPekkoAsyncTest import java.util.concurrent.atomic.{AtomicBoolean, AtomicReference} import scala.concurrent.{Await, Future} -/** A trait that holds a cached instance of a [[org.bitcoins.rpc.client.common.BitcoindRpcClient]] - * This is useful for using with fixtures to avoid creating a new bitcoind everytime a - * new test is run. +/** A trait that holds a cached instance of a + * [[org.bitcoins.rpc.client.common.BitcoindRpcClient]] This is useful for + * using with fixtures to avoid creating a new bitcoind everytime a new test is + * run. * - * The idea is our wallet/chain/node can just use the cached bitcoind rather than a fresh one. - * This does mean that test cases have to be written in such a way where assertions - * are not dependent on specific bitcoind state. + * The idea is our wallet/chain/node can just use the cached bitcoind rather + * than a fresh one. This does mean that test cases have to be written in such + * a way where assertions are not dependent on specific bitcoind state. */ trait CachedBitcoind[T <: BitcoindRpcClient] { _: BitcoinSPekkoAsyncTest => /** Flag to indicate if the bitcoind was used * - * If we don't have this, we have no way - * to know if we should cleanup the cached bitcoind - * in the [[afterAll()]] method or not. + * If we don't have this, we have no way to know if we should cleanup the + * cached bitcoind in the [[afterAll()]] method or not. * - * We do not want to accidentally create a bitcoind - * inside of [[afterAll()]] just to have it - * cleaned up in the same method. + * We do not want to accidentally create a bitcoind inside of [[afterAll()]] + * just to have it cleaned up in the same method. */ protected val isBitcoindUsed: AtomicBoolean = new AtomicBoolean(false) } /** A cached bitcoind that has zero blocks in its chainstate. This is useful for - * testing at certain times when we need to make sure bitcoind is ONLY initialized, no chain state. + * testing at certain times when we need to make sure bitcoind is ONLY + * initialized, no chain state. */ trait CachedBitcoindNoFunds[T <: BitcoindRpcClient] extends CachedBitcoind[T] { _: BitcoinSPekkoAsyncTest => @@ -44,7 +44,7 @@ trait CachedBitcoindNoFunds[T <: BitcoindRpcClient] extends CachedBitcoind[T] { override def afterAll(): Unit = { if (isBitcoindUsed.get()) { - //if it was used, shut down the cached bitcoind + // if it was used, shut down the cached bitcoind val stoppedF = for { cachedBitcoind <- cachedBitcoind _ <- BitcoindRpcTestUtil.stopServer(cachedBitcoind) @@ -52,7 +52,7 @@ trait CachedBitcoindNoFunds[T <: BitcoindRpcClient] extends CachedBitcoind[T] { Await.result(stoppedF, duration) } else { - //do nothing since bitcoind wasn't used + // do nothing since bitcoind wasn't used } } } @@ -80,7 +80,7 @@ trait CachedBitcoindFunded[T <: BitcoindRpcClient] extends CachedBitcoind[T] { override def afterAll(): Unit = { if (isBitcoindUsed.get()) { - //if it was used, shut down the cached bitcoind + // if it was used, shut down the cached bitcoind val stoppedF = for { cachedBitcoind <- cachedBitcoindWithFundsF _ <- BitcoindRpcTestUtil.stopServer(cachedBitcoind) @@ -91,7 +91,7 @@ trait CachedBitcoindFunded[T <: BitcoindRpcClient] extends CachedBitcoind[T] { Await.result(stoppedF, duration) } else { - //do nothing since bitcoind wasn't used + // do nothing since bitcoind wasn't used } } } @@ -99,8 +99,8 @@ trait CachedBitcoindFunded[T <: BitcoindRpcClient] extends CachedBitcoind[T] { trait CachedBitcoindNewest extends CachedBitcoindFunded[BitcoindRpcClient] { _: BitcoinSPekkoAsyncTest => - override protected lazy val cachedBitcoindWithFundsF: Future[ - BitcoindRpcClient] = { + override protected lazy val cachedBitcoindWithFundsF + : Future[BitcoindRpcClient] = { val _ = isBitcoindUsed.set(true) BitcoinSFixture .createBitcoindWithFunds(Some(BitcoindVersion.newest)) @@ -110,8 +110,8 @@ trait CachedBitcoindNewest extends CachedBitcoindFunded[BitcoindRpcClient] { trait CachedBitcoindNewestNoP2pBlockFilters extends CachedBitcoindNewest { _: BitcoinSPekkoAsyncTest => - override protected lazy val cachedBitcoindWithFundsF: Future[ - BitcoindRpcClient] = { + override protected lazy val cachedBitcoindWithFundsF + : Future[BitcoindRpcClient] = { val _ = isBitcoindUsed.set(true) BitcoinSFixture .createBitcoind(Some(BitcoindVersion.newest), enableNeutrino = false) @@ -122,8 +122,8 @@ trait CachedBitcoindBlockFilterRpcNewest extends CachedBitcoindFunded[BitcoindRpcClient] { _: BitcoinSPekkoAsyncTest => - override protected lazy val cachedBitcoindWithFundsF: Future[ - BitcoindRpcClient] = { + override protected lazy val cachedBitcoindWithFundsF + : Future[BitcoindRpcClient] = { val _ = isBitcoindUsed.set(true) BitcoinSFixture .createBitcoindBlockFilterRpcWithFunds(Some(BitcoindVersion.newest)) @@ -133,8 +133,8 @@ trait CachedBitcoindBlockFilterRpcNewest trait CachedBitcoindV22 extends CachedBitcoindFunded[BitcoindV22RpcClient] { _: BitcoinSPekkoAsyncTest => - override protected lazy val cachedBitcoindWithFundsF: Future[ - BitcoindV22RpcClient] = { + override protected lazy val cachedBitcoindWithFundsF + : Future[BitcoindV22RpcClient] = { val _ = isBitcoindUsed.set(true) BitcoinSFixture .createBitcoindWithFunds(Some(BitcoindVersion.V22)) @@ -145,8 +145,8 @@ trait CachedBitcoindV22 extends CachedBitcoindFunded[BitcoindV22RpcClient] { trait CachedBitcoindV23 extends CachedBitcoindFunded[BitcoindV23RpcClient] { _: BitcoinSPekkoAsyncTest => - override protected lazy val cachedBitcoindWithFundsF: Future[ - BitcoindV23RpcClient] = { + override protected lazy val cachedBitcoindWithFundsF + : Future[BitcoindV23RpcClient] = { val _ = isBitcoindUsed.set(true) BitcoinSFixture .createBitcoindWithFunds(Some(BitcoindVersion.V23)) @@ -157,8 +157,8 @@ trait CachedBitcoindV23 extends CachedBitcoindFunded[BitcoindV23RpcClient] { trait CachedBitcoindV24 extends CachedBitcoindFunded[BitcoindV24RpcClient] { _: BitcoinSPekkoAsyncTest => - override protected lazy val cachedBitcoindWithFundsF: Future[ - BitcoindV24RpcClient] = { + override protected lazy val cachedBitcoindWithFundsF + : Future[BitcoindV24RpcClient] = { val _ = isBitcoindUsed.set(true) BitcoinSFixture .createBitcoindWithFunds(Some(BitcoindVersion.V24)) @@ -170,31 +170,29 @@ trait CachedBitcoindCollection[T <: BitcoindRpcClient] extends CachedBitcoind[T] { _: BitcoinSPekkoAsyncTest => - /** The version of bitcoind we are creating in the collection - * By default, we just use the newest version of bitcoind + /** The version of bitcoind we are creating in the collection By default, we + * just use the newest version of bitcoind */ def version: BitcoindVersion /** Flag to indicate if the bitcoinds were used * - * If we don't have this, we have no way - * to know if we should cleanup the cached bitcoind - * in the [[afterAll()]] method or not. + * If we don't have this, we have no way to know if we should cleanup the + * cached bitcoind in the [[afterAll()]] method or not. * - * We do not want to accidentally create a bitcoind - * inside of [[afterAll()]] just to have it - * cleaned up in the same method. + * We do not want to accidentally create a bitcoind inside of [[afterAll()]] + * just to have it cleaned up in the same method. */ protected val isClientsUsed: AtomicBoolean = new AtomicBoolean(false) - protected lazy val cachedClients: AtomicReference[ - Vector[BitcoindRpcClient]] = { + protected lazy val cachedClients + : AtomicReference[Vector[BitcoindRpcClient]] = { new AtomicReference[Vector[BitcoindRpcClient]](Vector.empty) } override def afterAll(): Unit = { if (isClientsUsed.get()) { - //if it was used, shut down the cached bitcoind + // if it was used, shut down the cached bitcoind val clients = cachedClients.get() val stoppedF = for { _ <- BitcoindRpcTestUtil.stopServers(clients) @@ -202,7 +200,7 @@ trait CachedBitcoindCollection[T <: BitcoindRpcClient] Await.result(stoppedF, duration) } else { - //do nothing since bitcoind wasn't used + // do nothing since bitcoind wasn't used } } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/server/BitcoinSServerMainBitcoindFixture.scala b/testkit/src/main/scala/org/bitcoins/testkit/server/BitcoinSServerMainBitcoindFixture.scala index a23644843e..c2a98141d7 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/server/BitcoinSServerMainBitcoindFixture.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/server/BitcoinSServerMainBitcoindFixture.scala @@ -14,8 +14,8 @@ import org.scalatest.FutureOutcome import scala.concurrent.Future -/** Starts an instnace of [[BitcoinSserverMain]] that is - * using bitcoind as a backend +/** Starts an instnace of [[BitcoinSserverMain]] that is using bitcoind as a + * backend */ trait BitcoinSServerMainBitcoindFixture extends BitcoinSFixture @@ -33,13 +33,16 @@ trait BitcoinSServerMainBitcoindFixture walletHolder <- server.start() account1 = WalletTestUtil.getHdAccount1(config.walletConf) - //needed for fundWalletWithBitcoind - _ <- walletHolder.createNewAccount(hdAccount = account1, - keyManagerParams = - walletHolder.keyManager.kmParams) - walletWithBitcoind = WalletWithBitcoindRpc(walletHolder, - bitcoind, - config.walletConf) + // needed for fundWalletWithBitcoind + _ <- walletHolder.createNewAccount( + hdAccount = account1, + keyManagerParams = walletHolder.keyManager.kmParams + ) + walletWithBitcoind = WalletWithBitcoindRpc( + walletHolder, + bitcoind, + config.walletConf + ) _ <- FundWalletUtil.fundWalletWithBitcoind(walletWithBitcoind) } yield { ServerWithBitcoind(bitcoind, server) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/server/BitcoinSServerMainUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/server/BitcoinSServerMainUtil.scala index dd58057411..edf262b58f 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/server/BitcoinSServerMainUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/server/BitcoinSServerMainUtil.scala @@ -17,8 +17,8 @@ import scala.concurrent.{ExecutionContext, Future} object BitcoinSServerMainUtil { - /** Builds a configuration with the proper bitcoind credentials and bitcoin-s node mode set to bitcoind - * and sets tor config + /** Builds a configuration with the proper bitcoind credentials and bitcoin-s + * node mode set to bitcoind and sets tor config */ def buildBitcoindConfig(instance: BitcoindInstance): Config = { val version = instance match { @@ -49,15 +49,17 @@ object BitcoinSServerMainUtil { } /** Builds a [[BitcoinSAppConfig]] that uses a bitcoind backend */ - def buildBitcoindBitcoinSAppConfig(bitcoind: BitcoindRpcClient)(implicit - system: ActorSystem): BitcoinSAppConfig = { + def buildBitcoindBitcoinSAppConfig( + bitcoind: BitcoindRpcClient + )(implicit system: ActorSystem): BitcoinSAppConfig = { val conf = BitcoinSServerMainUtil.buildBitcoindConfig(bitcoind.instance) val datadir = FileUtil.tmpDir() BitcoinSAppConfig(datadir.toPath, Vector(conf)) } - def destroyBitcoinSAppConfig(appConfig: BitcoinSAppConfig)(implicit - ec: ExecutionContext): Future[Unit] = { + def destroyBitcoinSAppConfig( + appConfig: BitcoinSAppConfig + )(implicit ec: ExecutionContext): Future[Unit] = { val stopF = appConfig .stop() .map(_ => BitcoinSTestAppConfig.deleteAppConfig(appConfig)) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/server/ServerWithBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/server/ServerWithBitcoind.scala index 1c4cb8f96d..4e3b5736f6 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/server/ServerWithBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/server/ServerWithBitcoind.scala @@ -5,4 +5,5 @@ import org.bitcoins.server.BitcoinSServerMain case class ServerWithBitcoind( bitcoind: BitcoindRpcClient, - server: BitcoinSServerMain) + server: BitcoinSServerMain +) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/server/WalletLoaderFixtures.scala b/testkit/src/main/scala/org/bitcoins/testkit/server/WalletLoaderFixtures.scala index bc03a78c49..4c95f6b6f5 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/server/WalletLoaderFixtures.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/server/WalletLoaderFixtures.scala @@ -21,17 +21,20 @@ trait WalletLoaderFixtures bitcoind <- cachedBitcoindWithFundsF config = BitcoinSServerMainUtil.buildBitcoindBitcoinSAppConfig(bitcoind) _ <- config.start() - //initialize the default wallet so it can be used in tests - _ <- config.walletConf.createHDWallet(nodeApi = bitcoind, - chainQueryApi = bitcoind, - feeRateApi = bitcoind) + // initialize the default wallet so it can be used in tests + _ <- config.walletConf.createHDWallet( + nodeApi = bitcoind, + chainQueryApi = bitcoind, + feeRateApi = bitcoind + ) walletHolder = WalletHolder.empty loader = DLCWalletBitcoindBackendLoader( walletHolder = walletHolder, bitcoind = bitcoind, nodeApi = bitcoind, - feeProvider = bitcoind)(config, system) + feeProvider = bitcoind + )(config, system) } yield WalletHolderWithBitcoindLoaderApi(walletHolder, loader) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/tor/CachedTor.scala b/testkit/src/main/scala/org/bitcoins/testkit/tor/CachedTor.scala index 87a508e5cd..7c0d783026 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/tor/CachedTor.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/tor/CachedTor.scala @@ -8,9 +8,8 @@ import java.util.concurrent.atomic.AtomicBoolean import scala.concurrent.duration.DurationInt import scala.concurrent.{Await, Future} -/** A trait that holds a cached instance of a the tor daemon - * This is useful for using with fixtures to avoid starting tor everytime a - * new test is run. +/** A trait that holds a cached instance of a the tor daemon This is useful for + * using with fixtures to avoid starting tor everytime a new test is run. */ trait CachedTor { _: BitcoinSPekkoAsyncTest => diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoinSAsyncTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoinSAsyncTest.scala index c5ebf45622..4e5c389052 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoinSAsyncTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoinSAsyncTest.scala @@ -12,8 +12,8 @@ import org.scalatest.flatspec.{AsyncFlatSpec, FixtureAsyncFlatSpec} import scala.concurrent.ExecutionContext -/** A bitcoin-s async test trait, that uses akka's actor system - * execution context to run the scalatest test suites +/** A bitcoin-s async test trait, that uses akka's actor system execution + * context to run the scalatest test suites */ trait BitcoinSPekkoAsyncTest extends BaseAsyncTest with BitcoinSLogger { this: AsyncTestSuite => @@ -24,8 +24,8 @@ trait BitcoinSPekkoAsyncTest extends BaseAsyncTest with BitcoinSLogger { } implicit val networkParam: NetworkParameters = BitcoindRpcTestUtil.network - /** Needed because the default execution context will become overloaded - * if we do not specify a unique execution context for each suite + /** Needed because the default execution context will become overloaded if we + * do not specify a unique execution context for each suite */ implicit override def executionContext: ExecutionContext = system.dispatcher @@ -35,19 +35,19 @@ trait BitcoinSPekkoAsyncTest extends BaseAsyncTest with BitcoinSLogger { } } -/** A trait that uses [[AsyncFlatSpec]] to execute tests - * This is different than [[BitcoinsBaseAsyncTest]] in the sense that - * it extends [[AsyncFlatSpec]]. Some test cases in bitcoin-s we want - * to provide fixtures, which means that suite needs to extend [[FixtureAsyncFlatSpec FixtureAsyncFlatSpec]] - * to be able to use that fixture +/** A trait that uses [[AsyncFlatSpec]] to execute tests This is different than + * [[BitcoinsBaseAsyncTest]] in the sense that it extends [[AsyncFlatSpec]]. + * Some test cases in bitcoin-s we want to provide fixtures, which means that + * suite needs to extend [[FixtureAsyncFlatSpec FixtureAsyncFlatSpec]] to be + * able to use that fixture * * This test trait should be used for async tests that do NOT use a fixture. */ trait BitcoinSAsyncTest extends AsyncFlatSpec with BitcoinSPekkoAsyncTest /** A trait that uses [[FixtureAsyncFlatSpec AsyncFlatSpec]] to execute tests - * This is different than [[BitcoinSAsyncTest BitcoinSAsyncTest]] as you can use a fixture - * with this test suite. + * This is different than [[BitcoinSAsyncTest BitcoinSAsyncTest]] as you can + * use a fixture with this test suite. */ trait BitcoinSAsyncFixtureTest extends FixtureAsyncFlatSpec diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoindRpcTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoindRpcTest.scala index faff3aa44a..ac8930d7ce 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoindRpcTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoindRpcTest.scala @@ -32,14 +32,13 @@ trait BitcoindRpcBaseTest extends BitcoinSLogger { } } - /** Bitcoind RPC clients can be added to this builder - * as they are created in tests. After tests have - * stopped running (either by succeeding or failing) + /** Bitcoind RPC clients can be added to this builder as they are created in + * tests. After tests have stopped running (either by succeeding or failing) * all clients found in the builder is shut down. */ - lazy val clientAccum: mutable.Builder[ - BitcoindRpcClient, - Vector[BitcoindRpcClient]] = Vector.newBuilder + lazy val clientAccum + : mutable.Builder[BitcoindRpcClient, Vector[BitcoindRpcClient]] = + Vector.newBuilder override def afterAll(): Unit = { val stopF = BitcoindRpcTestUtil.stopServers(clientAccum.result()) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoindRpcTestClient.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoindRpcTestClient.scala index 221a6621a1..7fd0380c0a 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoindRpcTestClient.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/BitcoindRpcTestClient.scala @@ -11,19 +11,23 @@ import scala.concurrent.Future /** Helper class to start a bitcoind client with the given binary */ case class BitcoindRpcTestClient( override val binary: Path, - version: BitcoindVersion)(implicit system: ActorSystem) + version: BitcoindVersion +)(implicit system: ActorSystem) extends RpcBinaryUtil[BitcoindRpcClient] { - require(Files.exists(binary), - s"Path did not exist! got=${binary.toAbsolutePath.toString}") + require( + Files.exists(binary), + s"Path did not exist! got=${binary.toAbsolutePath.toString}" + ) import system.dispatcher private lazy val bitcoindInstance: BitcoindInstanceLocal = { - BitcoindRpcTestUtil.getInstance(bitcoindVersion = version, - binaryDirectory = binaryDirectory) + BitcoindRpcTestUtil.getInstance( + bitcoindVersion = version, + binaryDirectory = binaryDirectory + ) } - /** Cached client. This is defined if start() has been called - * else None + /** Cached client. This is defined if start() has been called else None */ private var clientOpt: Option[BitcoindRpcClient] = None @@ -32,9 +36,10 @@ case class BitcoindRpcTestClient( case Some(client) => Future.successful(client) case None => val clientF = - BitcoindRpcTestUtil.startedBitcoindRpcClient(Some(bitcoindInstance), - clientAccum = - Vector.newBuilder) + BitcoindRpcTestUtil.startedBitcoindRpcClient( + Some(bitcoindInstance), + clientAccum = Vector.newBuilder + ) clientF.map { c => clientOpt = Some(c) c @@ -47,7 +52,8 @@ case class BitcoindRpcTestClient( case Some(cli) => cli.stop() case None => Future.failed( - new RuntimeException(s"BitcoindRpcClient was not defined!")) + new RuntimeException(s"BitcoindRpcClient was not defined!") + ) } } @@ -58,8 +64,9 @@ object BitcoindRpcTestClient extends SbtBinaryFactory { override val sbtBinaryDirectory: Path = TestkitBinaries.baseBinaryDirectory.resolve("bitcoind") - def fromSbtDownload(bitcoindVersion: BitcoindVersion)(implicit - system: ActorSystem): BitcoindRpcTestClient = { + def fromSbtDownload( + bitcoindVersion: BitcoindVersion + )(implicit system: ActorSystem): BitcoindRpcTestClient = { val binary = BitcoindRpcTestUtil.getBinary(bitcoindVersion, sbtBinaryDirectory) BitcoindRpcTestClient(binary.toPath, bitcoindVersion) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/BytesUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/BytesUtil.scala index fcdd3e4afa..a9abd2a5ef 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/BytesUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/BytesUtil.scala @@ -44,12 +44,13 @@ object BytesUtil { case Some((sig, index)) => P2WSHWitnessV0( EmptyScriptPubKey, - p2wsh.stack.updated(index, - flipBit(ECDigitalSignature(sig)).bytes)) + p2wsh.stack.updated(index, flipBit(ECDigitalSignature(sig)).bytes) + ) case None => P2WSHWitnessV0( EmptyScriptPubKey, - p2wsh.stack.updated(0, flipAtIndex(p2wsh.stack.head, 0))) + p2wsh.stack.updated(0, flipAtIndex(p2wsh.stack.head, 0)) + ) } } } @@ -62,7 +63,8 @@ object BytesUtil { def flipBit( cetSigs: CETSignatures, - refundSig: PartialSignature): (CETSignatures, PartialSignature) = { + refundSig: PartialSignature + ): (CETSignatures, PartialSignature) = { val badOutcomeSigs = cetSigs.outcomeSigs.map { case (outcome, sig) => outcome -> flipBit(sig) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/EclairRpcTestClient.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/EclairRpcTestClient.scala index ff419f8cef..8971539843 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/EclairRpcTestClient.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/EclairRpcTestClient.scala @@ -13,11 +13,13 @@ import scala.concurrent.Future /** Helper class to start a eclair client with the given binary */ case class EclairRpcTestClient( override val binary: Path, - bitcoindRpcClientOpt: Option[BitcoindRpcClient])(implicit - system: ActorSystem) + bitcoindRpcClientOpt: Option[BitcoindRpcClient] +)(implicit system: ActorSystem) extends RpcBinaryUtil[EclairRpcClient] { - require(Files.exists(binary), - s"Path did not exist! got=${binary.toAbsolutePath.toString}") + require( + Files.exists(binary), + s"Path did not exist! got=${binary.toAbsolutePath.toString}" + ) import system.dispatcher private lazy val bitcoindRpcClientF: Future[BitcoindRpcClient] = { @@ -40,7 +42,7 @@ case class EclairRpcTestClient( } override def start(): Future[EclairRpcClient] = { - //should we start bitcoind rpc client here too? + // should we start bitcoind rpc client here too? for { rpcClient <- eclairRpcClientF started <- rpcClient.start() @@ -48,7 +50,7 @@ case class EclairRpcTestClient( } override def stop(): Future[EclairRpcClient] = { - //should we stop bitcoind rpc client here too? + // should we stop bitcoind rpc client here too? for { rpcClient <- eclairRpcClientF stopped <- rpcClient.stop() @@ -65,12 +67,14 @@ object EclairRpcTestClient extends SbtBinaryFactory { def fromSbtDownloadOpt( eclairVersionOpt: Option[String], eclairCommitOpt: Option[String], - bitcoindRpcClientOpt: Option[BitcoindRpcClient])(implicit - system: ActorSystem): Option[EclairRpcTestClient] = { + bitcoindRpcClientOpt: Option[BitcoindRpcClient] + )(implicit system: ActorSystem): Option[EclairRpcTestClient] = { val fileOpt = - getBinary(eclairVersionOpt = eclairVersionOpt, - eclairCommitOpt = eclairCommitOpt, - binaryDirectory = sbtBinaryDirectory) + getBinary( + eclairVersionOpt = eclairVersionOpt, + eclairCommitOpt = eclairCommitOpt, + binaryDirectory = sbtBinaryDirectory + ) fileOpt.map(f => EclairRpcTestClient(binary = f.toPath, bitcoindRpcClientOpt)) @@ -79,12 +83,13 @@ object EclairRpcTestClient extends SbtBinaryFactory { def fromSbtDownload( eclairVersionOpt: Option[String], eclairCommitOpt: Option[String], - bitcoindRpcClientOpt: Option[BitcoindRpcClient])(implicit - system: ActorSystem): EclairRpcTestClient = { - val eclairOpt = fromSbtDownloadOpt(eclairVersionOpt = eclairCommitOpt, - eclairCommitOpt = eclairCommitOpt, - bitcoindRpcClientOpt = - bitcoindRpcClientOpt) + bitcoindRpcClientOpt: Option[BitcoindRpcClient] + )(implicit system: ActorSystem): EclairRpcTestClient = { + val eclairOpt = fromSbtDownloadOpt( + eclairVersionOpt = eclairCommitOpt, + eclairCommitOpt = eclairCommitOpt, + bitcoindRpcClientOpt = bitcoindRpcClientOpt + ) eclairOpt match { case Some(client) => client case None => @@ -92,7 +97,8 @@ object EclairRpcTestClient extends SbtBinaryFactory { s"Could not find eclair that was downloaded by sbt " + s"with version=$eclairVersionOpt " + s"commit=$eclairCommitOpt at " + - s"path=${sbtBinaryDirectory.toAbsolutePath.toString}") + s"path=${sbtBinaryDirectory.toAbsolutePath.toString}" + ) } } @@ -100,17 +106,20 @@ object EclairRpcTestClient extends SbtBinaryFactory { def getBinary( eclairVersionOpt: Option[String], eclairCommitOpt: Option[String], - binaryDirectory: Path): Option[File] = { + binaryDirectory: Path + ): Option[File] = { val path = binaryDirectory .resolve(eclairVersionOpt.getOrElse(EclairRpcClient.version)) .resolve( - s"eclair-node-${EclairRpcClient.version}-${eclairCommitOpt.getOrElse(EclairRpcClient.commit)}") + s"eclair-node-${EclairRpcClient.version}-${eclairCommitOpt.getOrElse(EclairRpcClient.commit)}" + ) .resolve("bin") .resolve( if (sys.props("os.name").toLowerCase.contains("windows")) "eclair-node.bat" else - "eclair-node.sh") + "eclair-node.sh" + ) if (Files.exists(path)) { Some(path.toFile) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/FileUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/FileUtil.scala index dc73a166c2..194e1823a0 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/FileUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/FileUtil.scala @@ -16,15 +16,15 @@ object FileUtil extends BitcoinSLogger { /** Deletes the given temporary directory * - * @throws IllegalArgumentException if the - * given directory isn't in the user - * temp dir location + * @throws IllegalArgumentException + * if the given directory isn't in the user temp dir location */ def deleteTmpDir(dir: File): Boolean = { val isTemp = dir.getPath startsWith Properties.tmpDir if (!isTemp) { logger.warn( - s"Directory $dir is not in the system temp dir location! You most likely didn't mean to delete this directory.") + s"Directory $dir is not in the system temp dir location! You most likely didn't mean to delete this directory." + ) false } else if (!dir.isDirectory) { dir.delete() @@ -34,7 +34,7 @@ object FileUtil extends BitcoinSLogger { case Some(files) => files.foreach(deleteTmpDir) case None => - //do nothing since list files must have returned null + // do nothing since list files must have returned null } dir.delete() } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/PekkoUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/PekkoUtil.scala index 63bcb1cb0b..546d4725b7 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/PekkoUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/PekkoUtil.scala @@ -8,8 +8,9 @@ import scala.concurrent.duration.FiniteDuration trait PekkoUtil { /** Returns a future that will sleep until the given duration has passed */ - def nonBlockingSleep(duration: FiniteDuration)(implicit - system: ActorSystem): Future[Unit] = { + def nonBlockingSleep( + duration: FiniteDuration + )(implicit system: ActorSystem): Future[Unit] = { val p = Promise[Unit]() system.scheduler .scheduleOnce(duration)(p.success(()))(system.dispatcher) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/RpcBinaryUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/RpcBinaryUtil.scala index 2dc4608415..6701a69d55 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/RpcBinaryUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/RpcBinaryUtil.scala @@ -6,8 +6,8 @@ import org.bitcoins.core.util.StartStopAsync import java.nio.file.Path -/** A utility trait for handling binaries like bitcoind/eclair. - * All common utility methods should go in this trait +/** A utility trait for handling binaries like bitcoind/eclair. All common + * utility methods should go in this trait */ trait RpcBinaryUtil[T] extends StartStopAsync[T] with BitcoinSLogger { diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/ScalaTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/ScalaTestUtil.scala index de4ea8f378..27572087c1 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/ScalaTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/ScalaTestUtil.scala @@ -5,12 +5,14 @@ import org.scalatest.{Assertion, Assertions} import scala.concurrent.{ExecutionContext, Future} /** Helper methods for working with the scalatest testing framewrok - * @see [[http://www.scalatest.org/user_guide/using_assertions scalatest documentation]] + * @see + * [[http://www.scalatest.org/user_guide/using_assertions scalatest documentation]] */ object ScalaTestUtil { - def toAssertF(vecFut: Vector[Future[Assertion]])(implicit - ec: ExecutionContext): Future[Assertion] = { + def toAssertF( + vecFut: Vector[Future[Assertion]] + )(implicit ec: ExecutionContext): Future[Assertion] = { val futVec = Future.sequence(vecFut) futVec.map(_.foldLeft(Assertions.succeed) { case (_, next) => next diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/TestkitBinaries.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/TestkitBinaries.scala index 4606889f0a..5508e1f0b3 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/TestkitBinaries.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/TestkitBinaries.scala @@ -8,15 +8,15 @@ object TestkitBinaries { private val base: Path = Paths.get(".bitcoin-s", "binaries") - /** The base directory where binaries needed in tests - * are located. + /** The base directory where binaries needed in tests are located. */ lazy val baseBinaryDirectory: Path = { val home = Paths.get(Properties.userHome) fromRoot(home) } - /** Gives you an arbitrary root path, and then tacks on .bitcoin-s/binaries/ onto the end of it + /** Gives you an arbitrary root path, and then tacks on .bitcoin-s/binaries/ + * onto the end of it */ def fromRoot(path: Path): Path = { path.resolve(base) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/util/TorUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/util/TorUtil.scala index da2ac6e96b..6e08f57da9 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/util/TorUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/util/TorUtil.scala @@ -14,12 +14,16 @@ object TorUtil extends BitcoinSLogger { .isDefined def torProxyAddress = - new InetSocketAddress(InetAddress.getLoopbackAddress, - TorParams.DefaultProxyPort) + new InetSocketAddress( + InetAddress.getLoopbackAddress, + TorParams.DefaultProxyPort + ) def torControlAddress = - new InetSocketAddress(InetAddress.getLoopbackAddress, - TorParams.DefaultControlPort) + new InetSocketAddress( + InetAddress.getLoopbackAddress, + TorParams.DefaultControlPort + ) def torProxyEnabled: Boolean = portIsBound(torProxyAddress) def torControlEnabled: Boolean = portIsBound(torControlAddress) @@ -27,9 +31,11 @@ object TorUtil extends BitcoinSLogger { def verifyTorEnabled(): Unit = { assume( torProxyEnabled, - s"Tor daemon is not running or listening port ${TorParams.DefaultProxyPort}") + s"Tor daemon is not running or listening port ${TorParams.DefaultProxyPort}" + ) assume( torControlEnabled, - s"Tor daemon is not running or listening port ${TorParams.DefaultControlPort}") + s"Tor daemon is not running or listening port ${TorParams.DefaultControlPort}" + ) } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BaseWalletTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BaseWalletTest.scala index 6305e525d1..420809f080 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BaseWalletTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BaseWalletTest.scala @@ -47,13 +47,15 @@ trait BaseWalletTest extends EmbeddedPg { object BaseWalletTest { def getFreshConfig(pgUrl: () => Option[String], config: Vector[Config])( - implicit system: ActorSystem): BitcoinSAppConfig = { + implicit system: ActorSystem + ): BitcoinSAppConfig = { BitcoinSTestAppConfig.getNeutrinoWithEmbeddedDbTestConfig(pgUrl, config) } def getFreshWalletAppConfig( pgUrl: () => Option[String], - config: Vector[Config])(implicit system: ActorSystem): WalletAppConfig = { + config: Vector[Config] + )(implicit system: ActorSystem): WalletAppConfig = { getFreshConfig(pgUrl, config).walletConf } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSDualWalletTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSDualWalletTest.scala index 05d34a4760..697854152c 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSDualWalletTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSDualWalletTest.scala @@ -27,9 +27,9 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest { override protected def getFreshConfig: BitcoinSAppConfig = { val segwitConfig = BaseWalletTest.segwitWalletConf val randomHex = CryptoUtil.randomBytes(3).toHex - //with postgres, we need unique wallet names as postgres wallets - //share the same database. They have a unique schema with the database - //based on wallet name which is why we set this here. + // with postgres, we need unique wallet names as postgres wallets + // share the same database. They have a unique schema with the database + // based on wallet name which is why we set this here. val walletNameConfig = ConfigFactory.parseString(s"bitcoin-s.wallet.walletName=$randomHex") val extraConfig = segwitConfig.withFallback(walletNameConfig) @@ -60,9 +60,9 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest { super.beforeAll() } - /** Creates two segwit wallets that are funded with some bitcoin, these wallets are NOT - * peered with a bitcoind so the funds in the wallets are not tied to an - * underlying blockchain + /** Creates two segwit wallets that are funded with some bitcoin, these + * wallets are NOT peered with a bitcoind so the funds in the wallets are not + * tied to an underlying blockchain */ def withDualFundedDLCWallets(test: OneArgAsyncTest): FutureOutcome = { makeDependentFixture( @@ -70,9 +70,8 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest { for { walletA <- FundWalletUtil.createFundedDLCWallet(nodeApi, chainQueryApi) - walletB <- FundWalletUtil.createFundedDLCWallet( - nodeApi, - chainQueryApi)(config2, system) + walletB <- FundWalletUtil + .createFundedDLCWallet(nodeApi, chainQueryApi)(config2, system) } yield (walletA, walletB), destroy = { fundedWallets: (FundedDLCWallet, FundedDLCWallet) => for { @@ -86,28 +85,33 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest { /** Dual funded DLC wallets that are backed by a bitcoind node */ def withDualFundedDLCWallets( test: OneArgAsyncTest, - bitcoind: BitcoindRpcClient): FutureOutcome = { + bitcoind: BitcoindRpcClient + ): FutureOutcome = { makeDependentFixture( build = () => { createDualFundedDLCWallet(nodeApi = bitcoind, chainQueryApi = bitcoind) }, destroy = { fundedWallets: (FundedDLCWallet, FundedDLCWallet) => - destroyDLCWallets(dlcWallet1 = fundedWallets._1.wallet, - dlcWallet2 = fundedWallets._2.wallet) + destroyDLCWallets( + dlcWallet1 = fundedWallets._1.wallet, + dlcWallet2 = fundedWallets._2.wallet + ) } )(test) } private def createDualFundedDLCWallet( nodeApi: NodeApi, - chainQueryApi: ChainQueryApi): Future[ - (FundedDLCWallet, FundedDLCWallet)] = { - val walletAF = FundWalletUtil.createFundedDLCWallet(nodeApi = nodeApi, - chainQueryApi = - chainQueryApi) + chainQueryApi: ChainQueryApi + ): Future[(FundedDLCWallet, FundedDLCWallet)] = { + val walletAF = FundWalletUtil.createFundedDLCWallet( + nodeApi = nodeApi, + chainQueryApi = chainQueryApi + ) val walletBF = FundWalletUtil.createFundedDLCWallet(nodeApi, chainQueryApi)( config2, - system) + system + ) for { walletA <- walletAF walletB <- walletBF @@ -116,7 +120,8 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest { private def destroyDLCWallets( dlcWallet1: DLCWallet, - dlcWallet2: DLCWallet): Future[Unit] = { + dlcWallet2: DLCWallet + ): Future[Unit] = { val destroy1F = destroyDLCWallet(dlcWallet1) val destroy2F = destroyDLCWallet(dlcWallet2) for { @@ -128,16 +133,21 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest { /** Creates 2 funded segwit wallets that have a DLC initiated */ def withDualDLCWallets( test: OneArgAsyncTest, - contractOraclePair: ContractOraclePair): FutureOutcome = { + contractOraclePair: ContractOraclePair + ): FutureOutcome = { makeDependentFixture( build = () => { - createDualWalletsWithDLC(contractOraclePair = contractOraclePair, - nodeApi = nodeApi, - chainQueryApi = chainQueryApi) + createDualWalletsWithDLC( + contractOraclePair = contractOraclePair, + nodeApi = nodeApi, + chainQueryApi = chainQueryApi + ) }, destroy = { dlcWallets: (InitializedDLCWallet, InitializedDLCWallet) => - destroyDLCWallets(dlcWallet1 = dlcWallets._1.wallet, - dlcWallet2 = dlcWallets._2.wallet) + destroyDLCWallets( + dlcWallet1 = dlcWallets._1.wallet, + dlcWallet2 = dlcWallets._2.wallet + ) } )(test) } @@ -145,27 +155,33 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest { def withDualDLCWallets( test: OneArgAsyncTest, contractOraclePair: ContractOraclePair, - bitcoind: BitcoindRpcClient): FutureOutcome = { + bitcoind: BitcoindRpcClient + ): FutureOutcome = { makeDependentFixture( build = () => { - createDualWalletsWithDLC(contractOraclePair = contractOraclePair, - bitcoind = bitcoind) + createDualWalletsWithDLC( + contractOraclePair = contractOraclePair, + bitcoind = bitcoind + ) }, destroy = { dlcWallets: (InitializedDLCWallet, InitializedDLCWallet) => - destroyDLCWallets(dlcWallet1 = dlcWallets._1.wallet, - dlcWallet2 = dlcWallets._2.wallet) + destroyDLCWallets( + dlcWallet1 = dlcWallets._1.wallet, + dlcWallet2 = dlcWallets._2.wallet + ) } )(test) } private def createDualWalletsWithDLC( contractOraclePair: ContractOraclePair, - bitcoind: BitcoindRpcClient): Future[ - (InitializedDLCWallet, InitializedDLCWallet)] = { + bitcoind: BitcoindRpcClient + ): Future[(InitializedDLCWallet, InitializedDLCWallet)] = { for { walletA <- FundWalletUtil.createFundedDLCWalletWithBitcoind(bitcoind) walletB <- FundWalletUtil.createFundedDLCWalletWithBitcoind( - bitcoind = bitcoind)(config2, system) + bitcoind = bitcoind + )(config2, system) amt = expectedDefaultAmt / Satoshis(2) contractInfo = SingleContractInfo(amt.satoshis, contractOraclePair) (dlcWalletA, dlcWalletB) <- @@ -176,15 +192,17 @@ trait BitcoinSDualWalletTest extends BitcoinSWalletTest { private def createDualWalletsWithDLC( contractOraclePair: ContractOraclePair, nodeApi: NodeApi, - chainQueryApi: ChainQueryApi): Future[ - (InitializedDLCWallet, InitializedDLCWallet)] = { + chainQueryApi: ChainQueryApi + ): Future[(InitializedDLCWallet, InitializedDLCWallet)] = { for { - walletA <- FundWalletUtil.createFundedDLCWallet(nodeApi = nodeApi, - chainQueryApi = - chainQueryApi) + walletA <- FundWalletUtil.createFundedDLCWallet( + nodeApi = nodeApi, + chainQueryApi = chainQueryApi + ) walletB <- FundWalletUtil.createFundedDLCWallet( nodeApi = nodeApi, - chainQueryApi = chainQueryApi)(config2, system) + chainQueryApi = chainQueryApi + )(config2, system) amt = expectedDefaultAmt / Satoshis(2) contractInfo = SingleContractInfo(amt.satoshis, contractOraclePair) (dlcWalletA, dlcWalletB) <- diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTest.scala index acfa179440..7d227ca02f 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTest.scala @@ -89,8 +89,9 @@ trait BitcoinSWalletTest * peered with a bitcoind so the funds in the wallet are not tied to an * underlying blockchain */ - def withFundedWallet(test: OneArgAsyncTest)(implicit - walletAppConfig: WalletAppConfig): FutureOutcome = { + def withFundedWallet( + test: OneArgAsyncTest + )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = { makeDependentFixture( build = () => FundWalletUtil.createFundedWallet(nodeApi, chainQueryApi), destroy = { funded: FundedWallet => @@ -102,8 +103,9 @@ trait BitcoinSWalletTest )(test) } - def withFundedSegwitWallet(test: OneArgAsyncTest)(implicit - walletAppConfig: WalletAppConfig): FutureOutcome = { + def withFundedSegwitWallet( + test: OneArgAsyncTest + )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = { makeDependentFixture( build = () => FundWalletUtil.createFundedWallet(nodeApi, chainQueryApi), destroy = { funded: FundedWallet => @@ -119,8 +121,9 @@ trait BitcoinSWalletTest * peered with a bitcoind so the funds in the wallet are not tied to an * underlying blockchain */ - def withFundedDLCWallet(test: OneArgAsyncTest)(implicit - config: BitcoinSAppConfig): FutureOutcome = { + def withFundedDLCWallet( + test: OneArgAsyncTest + )(implicit config: BitcoinSAppConfig): FutureOutcome = { makeDependentFixture( build = () => FundWalletUtil.createFundedDLCWallet(nodeApi, chainQueryApi), @@ -143,8 +146,9 @@ trait BitcoinSWalletTest } /** Fixture for a wallet with default configuration with no funds in it */ - def withNewWallet(test: OneArgAsyncTest)(implicit - walletAppConfig: WalletAppConfig): FutureOutcome = { + def withNewWallet( + test: OneArgAsyncTest + )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = { makeDependentFixture[Wallet]( build = { () => createDefaultWallet(nodeApi, chainQueryApi) @@ -158,16 +162,20 @@ trait BitcoinSWalletTest )(test) } - def withNewWallet2Accounts(test: OneArgAsyncTest)(implicit - walletAppConfig: WalletAppConfig): FutureOutcome = { - makeDependentFixture(build = { () => - createWallet2Accounts(nodeApi, chainQueryApi) - }, - destroy = destroyWallet)(test) + def withNewWallet2Accounts( + test: OneArgAsyncTest + )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = { + makeDependentFixture( + build = { () => + createWallet2Accounts(nodeApi, chainQueryApi) + }, + destroy = destroyWallet + )(test) } - def withNewWalletAndBitcoind(test: OneArgAsyncTest)(implicit - walletAppConfig: WalletAppConfig): FutureOutcome = { + def withNewWalletAndBitcoind( + test: OneArgAsyncTest + )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = { val builder: () => Future[WalletWithBitcoindRpc] = BitcoinSFixture.composeBuildersAndWrap( builder = { () => @@ -183,7 +191,8 @@ trait BitcoinSWalletTest makeDependentFixture( builder, - destroy = destroyWalletWithBitcoind(_: WalletWithBitcoindRpc))(test) + destroy = destroyWalletWithBitcoind(_: WalletWithBitcoindRpc) + )(test) } def withWalletConfig(test: OneArgAsyncTest): FutureOutcome = { @@ -203,7 +212,7 @@ trait BitcoinSWalletTest } val destroy: WalletAppConfig => Future[Unit] = _ => { - //it might not be started, so don't stop it + // it might not be started, so don't stop it Future.unit } makeDependentFixture(builder, destroy = destroy)(test) @@ -238,8 +247,8 @@ object BitcoinSWalletTest extends WalletLogger { def createWalletAppConfig( pgUrl: () => Option[String], - configs: Vector[Config])(implicit - system: ActorSystem): Future[WalletAppConfig] = { + configs: Vector[Config] + )(implicit system: ActorSystem): Future[WalletAppConfig] = { import system.dispatcher val walletAppConfigF = createWalletAppConfigNotStarted(pgUrl, configs) for { @@ -250,8 +259,8 @@ object BitcoinSWalletTest extends WalletLogger { def createWalletAppConfigNotStarted( pgUrl: () => Option[String], - configs: Vector[Config])(implicit - system: ActorSystem): Future[WalletAppConfig] = { + configs: Vector[Config] + )(implicit system: ActorSystem): Future[WalletAppConfig] = { val baseConf = BaseWalletTest.getFreshWalletAppConfig(pgUrl, configs) val walletNameOpt = if (NumberGenerator.bool.sampleSome) { Some(UUID.randomUUID().toString.replace("-", "")) @@ -265,21 +274,22 @@ object BitcoinSWalletTest extends WalletLogger { BitcoinSAppConfig( baseConf.baseDatadir, - (walletNameOverride +: baseConf.configOverrides)).walletConf + (walletNameOverride +: baseConf.configOverrides) + ).walletConf case None => baseConf } Future.successful(walletConf) } - /** Returns a function that can be used to create a wallet fixture. - * If you pass in a configuration to this method that configuration - * is given to the wallet as user-provided overrides. You could for - * example use this to override the default data directory, network - * or account type. + /** Returns a function that can be used to create a wallet fixture. If you + * pass in a configuration to this method that configuration is given to the + * wallet as user-provided overrides. You could for example use this to + * override the default data directory, network or account type. */ private def createNewWallet(nodeApi: NodeApi, chainQueryApi: ChainQueryApi)( - implicit walletConfig: WalletAppConfig): () => Future[Wallet] = { () => + implicit walletConfig: WalletAppConfig + ): () => Future[Wallet] = { () => { import walletConfig.ec // we want to check we're not overwriting @@ -297,7 +307,8 @@ object BitcoinSWalletTest extends WalletLogger { private def createDLCWallet(nodeApi: NodeApi, chainQueryApi: ChainQueryApi)( implicit config: BitcoinSAppConfig, - ec: ExecutionContext): Future[DLCWallet] = { + ec: ExecutionContext + ): Future[DLCWallet] = { // we want to check we're not overwriting // any user data @@ -312,7 +323,8 @@ object BitcoinSWalletTest extends WalletLogger { val wallet = DLCWallet(nodeApi, chainQueryApi, new RandomFeeProvider)( config.walletConf, - config.dlcConf) + config.dlcConf + ) Wallet .initialize(wallet, config.walletConf.bip39PasswordOpt) @@ -322,49 +334,53 @@ object BitcoinSWalletTest extends WalletLogger { /** Creates a wallet with the default configuration */ def createDefaultWallet(nodeApi: NodeApi, chainQueryApi: ChainQueryApi)( - implicit walletAppConfig: WalletAppConfig): Future[Wallet] = { + implicit walletAppConfig: WalletAppConfig + ): Future[Wallet] = { createNewWallet(nodeApi = nodeApi, chainQueryApi = chainQueryApi)( walletAppConfig )() // get the standard config } - /** Creates a default wallet with bitcoind where the [[ChainQueryApi]] fed to the wallet - * is implemented by bitcoind + /** Creates a default wallet with bitcoind where the [[ChainQueryApi]] fed to + * the wallet is implemented by bitcoind */ def createWalletWithBitcoindCallbacks(bitcoind: BitcoindRpcClient)(implicit walletAppConfig: WalletAppConfig, - system: ActorSystem): Future[WalletWithBitcoindRpc] = { + system: ActorSystem + ): Future[WalletWithBitcoindRpc] = { import system.dispatcher - //we need to create a promise so we can inject the wallet with the callback - //after we have created it into SyncUtil.getNodeApiWalletCallback - //so we don't lose the internal state of the wallet + // we need to create a promise so we can inject the wallet with the callback + // after we have created it into SyncUtil.getNodeApiWalletCallback + // so we don't lose the internal state of the wallet val walletCallbackP = Promise[Wallet]() val walletWithBitcoindF = for { wallet <- BitcoinSWalletTest.createWallet2Accounts(bitcoind, bitcoind) - //create the wallet with the appropriate callbacks now that - //we have them + // create the wallet with the appropriate callbacks now that + // we have them walletWithCallback = Wallet( nodeApi = SyncUtil.getNodeApiWalletCallback(bitcoind, walletCallbackP.future), chainQueryApi = bitcoind, feeRateApi = new RandomFeeProvider )(wallet.walletConfig) - //complete the walletCallbackP so we can handle the callbacks when they are - //called without hanging forever. + // complete the walletCallbackP so we can handle the callbacks when they are + // called without hanging forever. _ = walletCallbackP.success(walletWithCallback) - } yield WalletWithBitcoindRpc(walletWithCallback, - bitcoind, - wallet.walletConfig) + } yield WalletWithBitcoindRpc( + walletWithCallback, + bitcoind, + wallet.walletConfig + ) walletWithBitcoindF.failed.foreach(err => walletCallbackP.failure(err)) walletWithBitcoindF } - def createWallet2Accounts(nodeApi: NodeApi, chainQueryApi: ChainQueryApi)( - implicit - config: WalletAppConfig, - system: ActorSystem): Future[Wallet] = { + def createWallet2Accounts( + nodeApi: NodeApi, + chainQueryApi: ChainQueryApi + )(implicit config: WalletAppConfig, system: ActorSystem): Future[Wallet] = { implicit val ec: ExecutionContextExecutor = system.dispatcher val defaultWalletF = @@ -372,9 +388,10 @@ object BitcoinSWalletTest extends WalletLogger { for { wallet <- defaultWalletF account1 = WalletTestUtil.getHdAccount1(wallet.walletConfig) - newAccountWallet <- wallet.createNewAccount(hdAccount = account1, - kmParams = - wallet.keyManager.kmParams) + newAccountWallet <- wallet.createNewAccount( + hdAccount = account1, + kmParams = wallet.keyManager.kmParams + ) } yield newAccountWallet } @@ -382,19 +399,25 @@ object BitcoinSWalletTest extends WalletLogger { def createDLCWallet2Accounts(nodeApi: NodeApi, chainQueryApi: ChainQueryApi)( implicit config: BitcoinSAppConfig, - system: ActorSystem): Future[DLCWallet] = { + system: ActorSystem + ): Future[DLCWallet] = { implicit val ec: ExecutionContextExecutor = system.dispatcher for { - wallet <- createDLCWallet(nodeApi = nodeApi, - chainQueryApi = chainQueryApi) + wallet <- createDLCWallet( + nodeApi = nodeApi, + chainQueryApi = chainQueryApi + ) account1 = WalletTestUtil.getHdAccount1(wallet.walletConfig) - newAccountWallet <- wallet.createNewAccount(hdAccount = account1, - kmParams = - wallet.keyManager.kmParams) + newAccountWallet <- wallet.createNewAccount( + hdAccount = account1, + kmParams = wallet.keyManager.kmParams + ) } yield newAccountWallet.asInstanceOf[DLCWallet] } - /** Pairs the given wallet with a bitcoind instance that has money in the bitcoind wallet */ + /** Pairs the given wallet with a bitcoind instance that has money in the + * bitcoind wallet + */ def createWalletWithBitcoind( wallet: Wallet )(implicit system: ActorSystem): Future[WalletWithBitcoindRpc] = { @@ -404,7 +427,9 @@ object BitcoinSWalletTest extends WalletLogger { system.dispatcher) } - /** Pairs the given wallet with a bitcoind instance that has money in the bitcoind wallet */ + /** Pairs the given wallet with a bitcoind instance that has money in the + * bitcoind wallet + */ def createWalletWithBitcoind( wallet: Wallet, versionOpt: Option[BitcoindVersion] @@ -417,7 +442,8 @@ object BitcoinSWalletTest extends WalletLogger { def createWalletWithBitcoind(bitcoind: BitcoindRpcClient)(implicit system: ActorSystem, - config: WalletAppConfig): Future[WalletWithBitcoindRpc] = { + config: WalletAppConfig + ): Future[WalletWithBitcoindRpc] = { createWalletWithBitcoindCallbacks(bitcoind) } @@ -426,49 +452,60 @@ object BitcoinSWalletTest extends WalletLogger { bitcoindRpcClient: BitcoindRpcClient ): Future[WalletWithBitcoindRpc] = { Future.successful( - WalletWithBitcoindRpc(wallet, bitcoindRpcClient, wallet.walletConfig)) + WalletWithBitcoindRpc(wallet, bitcoindRpcClient, wallet.walletConfig) + ) } - /** Gives us a funded bitcoin-s wallet and the bitcoind instance that funded that wallet */ + /** Gives us a funded bitcoin-s wallet and the bitcoind instance that funded + * that wallet + */ def fundedWalletAndBitcoind( versionOpt: Option[BitcoindVersion], nodeApi: NodeApi, chainQueryApi: ChainQueryApi, - walletCallbacks: WalletCallbacks)(implicit + walletCallbacks: WalletCallbacks + )(implicit config: BitcoinSAppConfig, - system: ActorSystem): Future[WalletWithBitcoindRpc] = { + system: ActorSystem + ): Future[WalletWithBitcoindRpc] = { import system.dispatcher config.walletConf.addCallbacks(walletCallbacks) for { wallet <- BitcoinSWalletTest.createWallet2Accounts( nodeApi, - chainQueryApi)(config.walletConf, system) + chainQueryApi + )(config.walletConf, system) withBitcoind <- createWalletWithBitcoind(wallet, versionOpt) funded <- FundWalletUtil.fundWalletWithBitcoind(withBitcoind) } yield funded } - /** Funds a wallet with bitcoind, this method adds [[CallbackUtil.createNeutrinoNodeCallbacksForWallet()]] - * which processes filters/blocks that can be used to fund the wallet. + /** Funds a wallet with bitcoind, this method adds + * [[CallbackUtil.createNeutrinoNodeCallbacksForWallet()]] which processes + * filters/blocks that can be used to fund the wallet. * - * It's important to note that this does NOT synchronize the wallet with a chain state. - * This should be done by the caller of this method. A useful method to help you with that - * in neutrino node cases is [[BitcoinSWalletTest.awaitWalletBalances]] + * It's important to note that this does NOT synchronize the wallet with a + * chain state. This should be done by the caller of this method. A useful + * method to help you with that in neutrino node cases is + * [[BitcoinSWalletTest.awaitWalletBalances]] */ def fundedWalletAndBitcoind( bitcoindRpcClient: BitcoindRpcClient, nodeApi: NodeApi, chainQueryApi: ChainQueryApi, - walletCallbacks: WalletCallbacks)(implicit + walletCallbacks: WalletCallbacks + )(implicit config: BitcoinSAppConfig, - system: ActorSystem): Future[WalletWithBitcoindRpc] = { + system: ActorSystem + ): Future[WalletWithBitcoindRpc] = { import system.dispatcher config.walletConf.addCallbacks(walletCallbacks) for { wallet <- BitcoinSWalletTest.createWallet2Accounts( nodeApi = nodeApi, - chainQueryApi = chainQueryApi)(config.walletConf, system) - //add callbacks for wallet + chainQueryApi = chainQueryApi + )(config.walletConf, system) + // add callbacks for wallet nodeCallbacks <- BitcoinSWalletTest.createNeutrinoNodeCallbacksForWallet(wallet)(system) _ = config.nodeConf.addCallbacks(nodeCallbacks) @@ -478,8 +515,8 @@ object BitcoinSWalletTest extends WalletLogger { } def destroyWalletWithBitcoind[T <: BitcoindRpcClient]( - walletWithBitcoind: WalletWithBitcoind[T])(implicit - ec: ExecutionContext): Future[Unit] = { + walletWithBitcoind: WalletWithBitcoind[T] + )(implicit ec: ExecutionContext): Future[Unit] = { val bitcoind = walletWithBitcoind.bitcoind val stopF = bitcoind.stop() val destroyWalletF = destroyOnlyWalletWithBitcoindCached(walletWithBitcoind) @@ -489,20 +526,22 @@ object BitcoinSWalletTest extends WalletLogger { } yield () } - /** Destorys the [[WalletApi]] and [[WalletAppConfig]] inside of [[WalletWithBitcoind]]. - * This method does not touch the bitcoind instance so it can be re-used in [[CachedBitcoind]] tests + /** Destorys the [[WalletApi]] and [[WalletAppConfig]] inside of + * [[WalletWithBitcoind]]. This method does not touch the bitcoind instance + * so it can be re-used in [[CachedBitcoind]] tests */ def destroyOnlyWalletWithBitcoindCached( - walletWithBitcoind: WalletWithBitcoind[_])(implicit - ec: ExecutionContext): Future[Unit] = { + walletWithBitcoind: WalletWithBitcoind[_] + )(implicit ec: ExecutionContext): Future[Unit] = { for { _ <- destroyWallet(walletWithBitcoind.wallet) _ <- destroyWalletAppConfig(walletWithBitcoind.walletConfig) } yield () } - def destroyWallet(wallet: WalletApi)(implicit - ec: ExecutionContext): Future[Unit] = { + def destroyWallet( + wallet: WalletApi + )(implicit ec: ExecutionContext): Future[Unit] = { for { _ <- wallet.stop() } yield () @@ -517,8 +556,9 @@ object BitcoinSWalletTest extends WalletLogger { } yield () } - def destroyWalletAppConfig(walletAppConfig: WalletAppConfig)(implicit - ec: ExecutionContext): Future[Unit] = { + def destroyWalletAppConfig( + walletAppConfig: WalletAppConfig + )(implicit ec: ExecutionContext): Future[Unit] = { for { _ <- walletAppConfig.dropTable("flyway_schema_history") _ <- walletAppConfig.dropAll() @@ -526,27 +566,32 @@ object BitcoinSWalletTest extends WalletLogger { } yield () } - /** Constructs callbacks for the wallet from the node to process blocks and compact filters */ - def createNeutrinoNodeCallbacksForWallet(wallet: Wallet)(implicit - system: ActorSystem): Future[NodeCallbacks] = { + /** Constructs callbacks for the wallet from the node to process blocks and + * compact filters + */ + def createNeutrinoNodeCallbacksForWallet( + wallet: Wallet + )(implicit system: ActorSystem): Future[NodeCallbacks] = { CallbackUtil.createNeutrinoNodeCallbacksForWallet(wallet) } - /** Makes sure our wallet is fully funded with the default amounts specified in - * [[BitcoinSWalletTest]]. This will future won't be completed until balances satisfy [[isSameWalletBalances()]] + /** Makes sure our wallet is fully funded with the default amounts specified + * in [[BitcoinSWalletTest]]. This will future won't be completed until + * balances satisfy [[isSameWalletBalances()]] */ - def awaitWalletBalances(fundedWallet: WalletWithBitcoind[_])(implicit - config: WalletAppConfig, - system: ActorSystem): Future[Unit] = { - AsyncUtil.retryUntilSatisfiedF(conditionF = - () => isSameWalletBalances(fundedWallet), - interval = 1.seconds, - maxTries = 100)(system.dispatcher) + def awaitWalletBalances( + fundedWallet: WalletWithBitcoind[_] + )(implicit config: WalletAppConfig, system: ActorSystem): Future[Unit] = { + AsyncUtil.retryUntilSatisfiedF( + conditionF = () => isSameWalletBalances(fundedWallet), + interval = 1.seconds, + maxTries = 100 + )(system.dispatcher) } - private def isSameWalletBalances(fundedWallet: WalletWithBitcoind[_])(implicit - config: WalletAppConfig, - system: ActorSystem): Future[Boolean] = { + private def isSameWalletBalances( + fundedWallet: WalletWithBitcoind[_] + )(implicit config: WalletAppConfig, system: ActorSystem): Future[Boolean] = { import system.dispatcher val defaultAccount = config.defaultAccount val hdAccount1 = WalletTestUtil.getHdAccount1(config) @@ -579,23 +624,27 @@ object BitcoinSWalletTest extends WalletLogger { def buildBip39PasswordWithExtraConfig( bip39PasswordOpt: Option[String], - extraConfig: Option[Config]): Config = { + extraConfig: Option[Config] + ): Config = { val bip39PasswordConfig = BitcoinSWalletTest.buildBip39PasswordConfig(bip39PasswordOpt) val merged = bip39PasswordConfig.withFallback( - extraConfig.getOrElse(ConfigFactory.empty)) + extraConfig.getOrElse(ConfigFactory.empty) + ) merged } - def getSegwitWalletConfigWithBip39PasswordOpt(pgUrl: Option[String])(implicit - system: ActorSystem): BitcoinSAppConfig = { + def getSegwitWalletConfigWithBip39PasswordOpt( + pgUrl: Option[String] + )(implicit system: ActorSystem): BitcoinSAppConfig = { val segwitConfig = BaseWalletTest.segwitWalletConf val extraConfig = BitcoinSWalletTest.buildBip39PasswordWithExtraConfig( bip39PasswordOpt = KeyManagerTestUtil.bip39PasswordOpt, - extraConfig = Some(segwitConfig)) + extraConfig = Some(segwitConfig) + ) BaseWalletTest.getFreshConfig(() => pgUrl, Vector(extraConfig)) } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTestCachedBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTestCachedBitcoind.scala index a1ad81b125..f877ec932c 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTestCachedBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTestCachedBitcoind.scala @@ -20,35 +20,38 @@ import org.scalatest.{FutureOutcome, Outcome} import scala.concurrent.Future import scala.util.{Failure, Success} -/** Bitcoin-s wallet test trait that uses cached bitcoinds - * rather than fresh bitcoinds. +/** Bitcoin-s wallet test trait that uses cached bitcoinds rather than fresh + * bitcoinds. * - * This should be used by default unless there is a reason your - * test suite needs fresh bitcoin's for every unit test inside of it + * This should be used by default unless there is a reason your test suite + * needs fresh bitcoin's for every unit test inside of it */ trait BitcoinSWalletTestCachedBitcoind extends BitcoinSFixture with BaseWalletTest with EmbeddedPg { _: CachedBitcoind[_] => - /** Creates a funded wallet fixture with bitcoind - * This is different than [[withFundedWalletAndBitcoind()]] - * in the sense that it does NOT destroy the given bitcoind. - * It is the responsibility of the caller of this method to - * do that, if needed. + /** Creates a funded wallet fixture with bitcoind This is different than + * [[withFundedWalletAndBitcoind()]] in the sense that it does NOT destroy + * the given bitcoind. It is the responsibility of the caller of this method + * to do that, if needed. */ def withFundedWalletAndBitcoindCached( test: OneArgAsyncTest, - bitcoind: BitcoindRpcClient)(implicit - walletAppConfig: WalletAppConfig): FutureOutcome = { + bitcoind: BitcoindRpcClient + )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = { val builder: () => Future[WalletWithBitcoind[_]] = { () => for { walletWithBitcoind <- createWalletWithBitcoindCallbacks( - bitcoind = bitcoind) + bitcoind = bitcoind + ) fundedWallet <- FundWalletUtil.fundWalletWithBitcoind( - walletWithBitcoind) - _ <- SyncUtil.syncWalletFullBlocks(wallet = fundedWallet.wallet, - bitcoind = bitcoind) + walletWithBitcoind + ) + _ <- SyncUtil.syncWalletFullBlocks( + wallet = fundedWallet.wallet, + bitcoind = bitcoind + ) _ <- BitcoinSWalletTest.awaitWalletBalances(fundedWallet) } yield fundedWallet } @@ -57,13 +60,14 @@ trait BitcoinSWalletTestCachedBitcoind builder, { case walletWithBitcoind: WalletWithBitcoind[_] => destroyOnlyWalletWithBitcoindCached(walletWithBitcoind) - })(test) + } + )(test) } def withNewWalletAndBitcoindCached( test: OneArgAsyncTest, - bitcoind: BitcoindRpcClient)(implicit - walletAppConfig: WalletAppConfig): FutureOutcome = { + bitcoind: BitcoindRpcClient + )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = { val builder: () => Future[WalletWithBitcoind[_]] = BitcoinSFixture.composeBuildersAndWrap( builder = { () => @@ -81,25 +85,29 @@ trait BitcoinSWalletTestCachedBitcoind builder, { case walletWithBitcoind: WalletWithBitcoind[_] => destroyOnlyWalletWithBitcoindCached(walletWithBitcoind) - })(test) + } + )(test) } - def withFundedWalletAndBitcoind(test: OneArgAsyncTest)(implicit - walletAppConfig: WalletAppConfig): FutureOutcome = { + def withFundedWalletAndBitcoind( + test: OneArgAsyncTest + )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = { val bitcoindF = BitcoinSFixture .createBitcoindWithFunds(None) - //create a bitcoind, then pretend that it is cached - //so we can re-use code in withFundedWalletBitcoindCached + // create a bitcoind, then pretend that it is cached + // so we can re-use code in withFundedWalletBitcoindCached val resultF = for { bitcoind <- bitcoindF - outcome = withFundedWalletAndBitcoindCached(test = test, - bitcoind = bitcoind) + outcome = withFundedWalletAndBitcoindCached( + test = test, + bitcoind = bitcoind + ) f <- outcome.toFuture } yield f - //since we aren't actually caching the bitcoind, we need - //to shut it down now + // since we aren't actually caching the bitcoind, we need + // to shut it down now val stoppedBitcoind: Future[Outcome] = resultF.transformWith({ case Success(outcome) => stopBitcoind(bitcoindF) @@ -115,7 +123,8 @@ trait BitcoinSWalletTestCachedBitcoind /** Helper method to stop a Future[BitcoindRpcClient] */ private def stopBitcoind( - bitcoindF: Future[BitcoindRpcClient]): Future[Unit] = { + bitcoindF: Future[BitcoindRpcClient] + ): Future[Unit] = { for { bitcoind <- bitcoindF _ <- BitcoindRpcTestUtil.stopServer(bitcoind) @@ -135,7 +144,8 @@ trait BitcoinSWalletTestCachedBitcoindNewest val f: Future[Outcome] = for { bitcoind <- cachedBitcoindWithFundsF futOutcome = withFundedWalletAndBitcoindCached(test, bitcoind)( - getFreshWalletAppConfig) + getFreshWalletAppConfig + ) fut <- futOutcome.toFuture } yield fut new FutureOutcome(f) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala index 6572be0126..067214239b 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/DLCWalletUtil.scala @@ -81,20 +81,26 @@ object DLCWalletUtil extends BitcoinSLogger { } lazy val sampleOracleInfo: EnumSingleOracleInfo = - EnumSingleOracleInfo.dummyForKeys(oraclePrivKey, - rValue, - sampleOutcomes.map(_._1)) + EnumSingleOracleInfo.dummyForKeys( + oraclePrivKey, + rValue, + sampleOutcomes.map(_._1) + ) lazy val sampleOracleInfoNonWinnerTakeAll: EnumSingleOracleInfo = { - EnumSingleOracleInfo.dummyForKeys(oraclePrivKey, - rValue, - nonWinnerTakeAllOutcomes.map(_._1)) + EnumSingleOracleInfo.dummyForKeys( + oraclePrivKey, + rValue, + nonWinnerTakeAllOutcomes.map(_._1) + ) } lazy val invalidOracleInfo: EnumSingleOracleInfo = { - val info = EnumSingleOracleInfo.dummyForKeys(oraclePrivKey, - rValue, - sampleOutcomes.map(_._1)) + val info = EnumSingleOracleInfo.dummyForKeys( + oraclePrivKey, + rValue, + sampleOutcomes.map(_._1) + ) val announcement = info.announcement.asInstanceOf[OracleAnnouncementV0TLV] val invalidAnnouncement = announcement.copy(announcementSignature = SchnorrDigitalSignature.dummy) @@ -104,17 +110,22 @@ object DLCWalletUtil extends BitcoinSLogger { lazy val sampleContractOraclePair: ContractOraclePair.EnumPair = ContractOraclePair.EnumPair(sampleContractDescriptor, sampleOracleInfo) - lazy val sampleContractOraclePairNonWinnerTakeAll: ContractOraclePair.EnumPair = { - ContractOraclePair.EnumPair(sampleContractDescriptorNonWinnerTakeAll, - sampleOracleInfoNonWinnerTakeAll) + lazy val sampleContractOraclePairNonWinnerTakeAll + : ContractOraclePair.EnumPair = { + ContractOraclePair.EnumPair( + sampleContractDescriptorNonWinnerTakeAll, + sampleOracleInfoNonWinnerTakeAll + ) } lazy val invalidContractOraclePair: ContractOraclePair.EnumPair = ContractOraclePair.EnumPair(sampleContractDescriptor, invalidOracleInfo) lazy val sampleContractInfo: SingleContractInfo = - SingleContractInfo(totalCollateral = total, - contractOraclePair = sampleContractOraclePair) + SingleContractInfo( + totalCollateral = total, + contractOraclePair = sampleContractOraclePair + ) lazy val sampleContractInfoNonWinnerTakeAll: SingleContractInfo = { SingleContractInfo(total, sampleContractOraclePairNonWinnerTakeAll) @@ -143,12 +154,15 @@ object DLCWalletUtil extends BitcoinSLogger { val unsorted = rValues.take(numDigits).toVector val sorted = OrderedNonces.fromUnsorted(unsorted) NumericSingleOracleInfo( - OracleAnnouncementV0TLV.dummyForKeys(oraclePrivKey, sorted)) + OracleAnnouncementV0TLV.dummyForKeys(oraclePrivKey, sorted) + ) } lazy val multiNonceContractOraclePair: ContractOraclePair.NumericPair = { - ContractOraclePair.NumericPair(multiNonceContractDescriptor, - multiNonceOracleInfo) + ContractOraclePair.NumericPair( + multiNonceContractDescriptor, + multiNonceOracleInfo + ) } lazy val multiNonceContractInfo: ContractInfo = @@ -179,29 +193,36 @@ object DLCWalletUtil extends BitcoinSLogger { } lazy val dummyAddress: BitcoinAddress = BitcoinAddress( - "bc1quq29mutxkgxmjfdr7ayj3zd9ad0ld5mrhh89l2") + "bc1quq29mutxkgxmjfdr7ayj3zd9ad0ld5mrhh89l2" + ) lazy val dummyDLCKeys: DLCPublicKeys = DLCPublicKeys(dummyKey, dummyAddress) lazy val dummyBlockHash: DoubleSha256DigestBE = DoubleSha256DigestBE( - "00000000496dcc754fabd97f3e2df0a7337eab417d75537fecf97a7ebb0e7c75") + "00000000496dcc754fabd97f3e2df0a7337eab417d75537fecf97a7ebb0e7c75" + ) val dummyPrevTx: BaseTransaction = BaseTransaction( TransactionConstants.validLockVersion, Vector.empty, Vector.fill(2)(TransactionOutput(half, P2WPKHWitnessSPKV0(dummyKey))), - UInt32.zero) + UInt32.zero + ) val dummyFundingInputs = Vector( - DLCFundingInputP2WPKHV0(UInt64.zero, - dummyPrevTx, - UInt32.zero, - TransactionConstants.sequence), - DLCFundingInputP2WPKHV0(UInt64.one, - dummyPrevTx, - UInt32.one, - TransactionConstants.sequence) + DLCFundingInputP2WPKHV0( + UInt64.zero, + dummyPrevTx, + UInt32.zero, + TransactionConstants.sequence + ), + DLCFundingInputP2WPKHV0( + UInt64.one, + dummyPrevTx, + UInt32.one, + TransactionConstants.sequence + ) ) lazy val sampleOfferPayoutSerialId: UInt64 = DLCMessage.genSerialId() @@ -267,10 +288,12 @@ object DLCWalletUtil extends BitcoinSLogger { Vector( EnumOracleOutcome( Vector(sampleOracleInfo), - EnumOutcome(winStr)).sigPoint -> ECAdaptorSignature.dummy, + EnumOutcome(winStr) + ).sigPoint -> ECAdaptorSignature.dummy, EnumOracleOutcome( Vector(sampleOracleInfo), - EnumOutcome(loseStr)).sigPoint -> ECAdaptorSignature.dummy + EnumOutcome(loseStr) + ).sigPoint -> ECAdaptorSignature.dummy ) lazy val dummyCETSigs: CETSignatures = @@ -280,7 +303,8 @@ object DLCWalletUtil extends BitcoinSLogger { DLCMessage.genSerialId(Vector(sampleOfferPayoutSerialId)) lazy val sampleAcceptChangeSerialId: UInt64 = DLCMessage.genSerialId( - Vector(sampleOfferChangeSerialId, sampleFundOutputSerialId)) + Vector(sampleOfferChangeSerialId, sampleFundOutputSerialId) + ) lazy val sampleDLCAccept: DLCAccept = DLCAccept( collateral = half, @@ -297,17 +321,22 @@ object DLCWalletUtil extends BitcoinSLogger { lazy val dummyFundingSignatures: FundingSignatures = FundingSignatures( Vector( - (TransactionOutPoint(dummyBlockHash, UInt32.zero), dummyScriptWitness))) + (TransactionOutPoint(dummyBlockHash, UInt32.zero), dummyScriptWitness) + ) + ) lazy val sampleDLCSign: DLCSign = - DLCSign(dummyCETSigs, - dummyPartialSig, - dummyFundingSignatures, - ByteVector.empty) + DLCSign( + dummyCETSigs, + dummyPartialSig, + dummyFundingSignatures, + ByteVector.empty + ) lazy val sampleDLCDb: DLCDb = DLCDb( dlcId = Sha256Digest( - "9da9922b9067007f8d9c56c37f202a568f0cdb104e5ef9752ad6cbc1834f0334"), + "9da9922b9067007f8d9c56c37f202a568f0cdb104e5ef9752ad6cbc1834f0334" + ), tempContractId = sampleDLCOffer.tempContractId, contractIdOpt = None, protocolVersion = 0, @@ -345,9 +374,10 @@ object DLCWalletUtil extends BitcoinSLogger { payoutAddressAOpt: Option[BitcoinAddress] = None, changeAddressAOpt: Option[BitcoinAddress] = None, payoutAddressBOpt: Option[BitcoinAddress] = None, - changeAddressBOpt: Option[BitcoinAddress] = None)(implicit - ec: ExecutionContext): Future[ - (InitializedDLCWallet, InitializedDLCWallet)] = { + changeAddressBOpt: Option[BitcoinAddress] = None + )(implicit + ec: ExecutionContext + ): Future[(InitializedDLCWallet, InitializedDLCWallet)] = { val walletA = fundedWalletA.wallet val walletB = fundedWalletB.wallet for { @@ -361,17 +391,21 @@ object DLCWalletUtil extends BitcoinSLogger { externalPayoutAddressOpt = payoutAddressAOpt, externalChangeAddressOpt = changeAddressAOpt ) - accept <- walletB.acceptDLCOffer(offer, - None, - payoutAddressBOpt, - changeAddressBOpt) + accept <- walletB.acceptDLCOffer( + offer, + None, + payoutAddressBOpt, + changeAddressBOpt + ) sigs <- walletA.signDLC(accept) _ <- walletB.addDLCSigs(sigs) tx <- walletB.broadcastDLCFundingTx(sigs.contractId) _ <- walletA.processTransaction(tx, None) } yield { - (InitializedDLCWallet(FundedDLCWallet(walletA)), - InitializedDLCWallet(FundedDLCWallet(walletB))) + ( + InitializedDLCWallet(FundedDLCWallet(walletA)), + InitializedDLCWallet(FundedDLCWallet(walletB)) + ) } } @@ -379,8 +413,9 @@ object DLCWalletUtil extends BitcoinSLogger { val wallet: DLCWallet = funded.wallet } - def getDLCStatus(wallet: DLCWallet)(implicit - ec: ExecutionContext): Future[DLCStatus] = { + def getDLCStatus( + wallet: DLCWallet + )(implicit ec: ExecutionContext): Future[DLCStatus] = { for { dbs <- wallet.dlcDAO.findAll() _ = require(dbs.size == 1, "There should only be one dlc initialized") @@ -389,8 +424,9 @@ object DLCWalletUtil extends BitcoinSLogger { } yield status.get } - def getContractId(wallet: DLCWallet)(implicit - ec: ExecutionContext): Future[ByteVector] = { + def getContractId( + wallet: DLCWallet + )(implicit ec: ExecutionContext): Future[ByteVector] = { wallet.dlcDAO.findAll().map { all => require(all.size == 1, "There should only be one dlc initialized") all.head.contractIdOpt.get @@ -401,7 +437,8 @@ object DLCWalletUtil extends BitcoinSLogger { transaction: Transaction, inputIndex: Long, prevOut: TransactionOutput, - outputMap: PreviousOutputMap): Boolean = { + outputMap: PreviousOutputMap + ): Boolean = { val sigComponent = WitnessTxSigComponent( transaction.asInstanceOf[WitnessTransaction], UInt32(inputIndex), @@ -416,7 +453,8 @@ object DLCWalletUtil extends BitcoinSLogger { wallets: (InitializedDLCWallet, InitializedDLCWallet), asInitiator: Boolean, func: DLCWallet => Future[Transaction], - expectedOutputs: Int)(implicit ec: ExecutionContext): Future[Boolean] = { + expectedOutputs: Int + )(implicit ec: ExecutionContext): Future[Boolean] = { val dlcA = wallets._1.wallet val dlcB = wallets._2.wallet dlcExecutionTest(dlcA, dlcB, asInitiator, func, expectedOutputs) @@ -427,7 +465,8 @@ object DLCWalletUtil extends BitcoinSLogger { dlcB: DLCWallet, asInitiator: Boolean, func: DLCWallet => Future[Transaction], - expectedOutputs: Int)(implicit ec: ExecutionContext): Future[Boolean] = { + expectedOutputs: Int + )(implicit ec: ExecutionContext): Future[Boolean] = { for { contractId <- getContractId(dlcA) fundingTx <- dlcB.broadcastDLCFundingTx(contractId) @@ -462,8 +501,9 @@ object DLCWalletUtil extends BitcoinSLogger { } } - def verifyProperlySetTxIds(wallet: DLCWallet)(implicit - ec: ExecutionContext): Future[Unit] = { + def verifyProperlySetTxIds( + wallet: DLCWallet + )(implicit ec: ExecutionContext): Future[Unit] = { for { contractId <- getContractId(wallet) dlcDbOpt <- wallet.dlcDAO.findByContractId(contractId) @@ -477,9 +517,9 @@ object DLCWalletUtil extends BitcoinSLogger { } } - def getSigs(contractInfo: SingleContractInfo): ( - OracleAttestmentTLV, - OracleAttestmentTLV) = { + def getSigs( + contractInfo: SingleContractInfo + ): (OracleAttestmentTLV, OracleAttestmentTLV) = { val desc: EnumContractDescriptor = contractInfo.contractDescriptor match { case desc: EnumContractDescriptor => desc case _: NumericContractDescriptor => @@ -493,33 +533,43 @@ object DLCWalletUtil extends BitcoinSLogger { ._1 .outcome val initiatorWinSig = DLCWalletUtil.oraclePrivKey - .schnorrSignWithNonce(CryptoUtil - .sha256DLCAttestation(initiatorWinStr) - .bytes, - DLCWalletUtil.kValue) + .schnorrSignWithNonce( + CryptoUtil + .sha256DLCAttestation(initiatorWinStr) + .bytes, + DLCWalletUtil.kValue + ) // Get a hash that the recipient wins for val recipientWinStr = desc.find(_._2 == Satoshis.zero).get._1.outcome val recipientWinSig = DLCWalletUtil.oraclePrivKey - .schnorrSignWithNonce(CryptoUtil - .sha256DLCAttestation(recipientWinStr) - .bytes, - DLCWalletUtil.kValue) + .schnorrSignWithNonce( + CryptoUtil + .sha256DLCAttestation(recipientWinStr) + .bytes, + DLCWalletUtil.kValue + ) val publicKey = DLCWalletUtil.oraclePrivKey.schnorrPublicKey val eventId = DLCWalletUtil.sampleOracleInfo.announcement.eventTLV match { case v0: OracleEventV0TLV => v0.eventId } - (OracleAttestmentV0TLV(eventId, - publicKey, - Vector(initiatorWinSig), - Vector(initiatorWinStr)), - OracleAttestmentV0TLV(eventId, - publicKey, - Vector(recipientWinSig), - Vector(recipientWinStr))) + ( + OracleAttestmentV0TLV( + eventId, + publicKey, + Vector(initiatorWinSig), + Vector(initiatorWinStr) + ), + OracleAttestmentV0TLV( + eventId, + publicKey, + Vector(recipientWinSig), + Vector(recipientWinStr) + ) + ) } } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/DualWalletTestCachedBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/DualWalletTestCachedBitcoind.scala index 3c50e829f9..e15f76703a 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/DualWalletTestCachedBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/DualWalletTestCachedBitcoind.scala @@ -22,11 +22,12 @@ trait DualWalletTestCachedBitcoind implicit protected def config2: BitcoinSAppConfig = { val config = BitcoinSWalletTest.buildBip39PasswordWithExtraConfig( getBIP39PasswordOpt(), - Some(BaseWalletTest.segwitWalletConf)) + Some(BaseWalletTest.segwitWalletConf) + ) val randomHex = CryptoUtil.randomBytes(3).toHex - //with postgres, we need unique wallet names as postgres wallets - //share the same database. They have a unique schema with the database - //based on wallet name which is why we set this here. + // with postgres, we need unique wallet names as postgres wallets + // share the same database. They have a unique schema with the database + // based on wallet name which is why we set this here. val walletNameConfig = ConfigFactory.parseString(s"bitcoin-s.wallet.walletName=$randomHex") val extraConfig = config.withFallback(walletNameConfig) @@ -49,21 +50,21 @@ trait DualWalletTestCachedBitcoind super.beforeAll() } - /** Creates two segwit wallets that are funded with some bitcoin, these wallets are NOT - * peered with a bitcoind so the funds in the wallets are not tied to an - * underlying blockchain + /** Creates two segwit wallets that are funded with some bitcoin, these + * wallets are NOT peered with a bitcoind so the funds in the wallets are not + * tied to an underlying blockchain */ def withDualFundedDLCWallets(test: OneArgAsyncTest): FutureOutcome = { makeDependentFixture( - build = - () => - for { - bitcoind <- cachedBitcoindWithFundsF - walletA <- - FundWalletUtil.createFundedDLCWalletWithBitcoind(bitcoind) - walletB <- FundWalletUtil.createFundedDLCWalletWithBitcoind( - bitcoind)(config2, system) - } yield (walletA, walletB, bitcoind), + build = () => + for { + bitcoind <- cachedBitcoindWithFundsF + walletA <- + FundWalletUtil.createFundedDLCWalletWithBitcoind(bitcoind) + walletB <- FundWalletUtil.createFundedDLCWalletWithBitcoind( + bitcoind + )(config2, system) + } yield (walletA, walletB, bitcoind), destroy = { fundedWallets: (FundedDLCWallet, FundedDLCWallet, _) => for { _ <- destroyDLCWallet(fundedWallets._1.wallet) @@ -76,35 +77,36 @@ trait DualWalletTestCachedBitcoind /** Creates 2 funded segwit wallets that have a DLC initiated */ def withDualDLCWallets( test: OneArgAsyncTest, - contractOraclePair: ContractOraclePair): FutureOutcome = { + contractOraclePair: ContractOraclePair + ): FutureOutcome = { makeDependentFixture( - build = - () => { - val bitcoindF = cachedBitcoindWithFundsF + build = () => { + val bitcoindF = cachedBitcoindWithFundsF - val walletAF = bitcoindF.flatMap { bitcoind => - FundWalletUtil.createFundedDLCWalletWithBitcoind(bitcoind) - } - val walletBF = for { - bitcoind <- bitcoindF + val walletAF = bitcoindF.flatMap { bitcoind => + FundWalletUtil.createFundedDLCWalletWithBitcoind(bitcoind) + } + val walletBF = for { + bitcoind <- bitcoindF - //its important to map on this otherwise we generate blocks in parallel - //causing a reorg inside of createFundedDLCWallet - _ <- walletAF - walletB <- FundWalletUtil.createFundedDLCWalletWithBitcoind( - bitcoind)(config2, system) - } yield { walletB } + // its important to map on this otherwise we generate blocks in parallel + // causing a reorg inside of createFundedDLCWallet + _ <- walletAF + walletB <- FundWalletUtil.createFundedDLCWalletWithBitcoind( + bitcoind + )(config2, system) + } yield { walletB } - for { - walletA <- walletAF - walletB <- walletBF - amt = expectedDefaultAmt / Satoshis(2) - contractInfo = SingleContractInfo(amt.satoshis, contractOraclePair) - (dlcWalletA, dlcWalletB) <- - DLCWalletUtil.initDLC(walletA, walletB, contractInfo) - bitcoind <- bitcoindF - } yield (dlcWalletA, dlcWalletB, bitcoind) - }, + for { + walletA <- walletAF + walletB <- walletBF + amt = expectedDefaultAmt / Satoshis(2) + contractInfo = SingleContractInfo(amt.satoshis, contractOraclePair) + (dlcWalletA, dlcWalletB) <- + DLCWalletUtil.initDLC(walletA, walletB, contractInfo) + bitcoind <- bitcoindF + } yield (dlcWalletA, dlcWalletB, bitcoind) + }, destroy = { dlcWallets: (InitializedDLCWallet, InitializedDLCWallet, _) => for { _ <- destroyDLCWallet(dlcWallets._1.wallet) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/FundWalletUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/FundWalletUtil.scala index 64cd113467..3d55929cad 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/FundWalletUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/FundWalletUtil.scala @@ -31,7 +31,8 @@ trait FundWalletUtil extends BitcoinSLogger { /** Funds the given wallet with money from the given bitcoind */ def fundWalletWithBitcoind[T <: WalletWithBitcoind[_ <: BitcoindRpcClient]]( - pair: T)(implicit ec: ExecutionContext): Future[T] = { + pair: T + )(implicit ec: ExecutionContext): Future[T] = { val (wallet, bitcoind) = (pair.wallet, pair.bitcoind) val defaultAccount = pair.walletConfig.defaultAccount @@ -61,15 +62,16 @@ trait FundWalletUtil extends BitcoinSLogger { def fundAccountForWallet( amts: Vector[CurrencyUnit], account: HDAccount, - wallet: Wallet)(implicit ec: ExecutionContext): Future[Wallet] = { + wallet: Wallet + )(implicit ec: ExecutionContext): Future[Wallet] = { val addressesF: Future[Vector[BitcoinAddress]] = Future.sequence { Vector.fill(3)(wallet.getNewAddress(account)) } - //construct three txs that send money to these addresses - //these are "fictional" transactions in the sense that the - //outpoints do not exist on a blockchain anywhere + // construct three txs that send money to these addresses + // these are "fictional" transactions in the sense that the + // outpoints do not exist on a blockchain anywhere val txsF = for { addresses <- addressesF } yield { @@ -91,8 +93,8 @@ trait FundWalletUtil extends BitcoinSLogger { amts: Vector[CurrencyUnit], account: HDAccount, wallet: HDWalletApi, - bitcoind: BitcoindRpcClient)(implicit - ec: ExecutionContext): Future[HDWalletApi] = { + bitcoind: BitcoindRpcClient + )(implicit ec: ExecutionContext): Future[HDWalletApi] = { val addressesF: Future[Vector[BitcoinAddress]] = Future.sequence { Vector.fill(3)(wallet.getNewAddress(account)) @@ -110,9 +112,11 @@ trait FundWalletUtil extends BitcoinSLogger { txAndHashF.map(_ => wallet) } - /** Funds a bitcoin-s wallet with 3 utxos with 1, 2 and 3 bitcoin in the utxos */ - def fundWallet(wallet: Wallet)(implicit - ec: ExecutionContext): Future[FundedTestWallet] = { + /** Funds a bitcoin-s wallet with 3 utxos with 1, 2 and 3 bitcoin in the utxos + */ + def fundWallet( + wallet: Wallet + )(implicit ec: ExecutionContext): Future[FundedTestWallet] = { val defaultAccount = wallet.walletConfig.defaultAccount val fundedDefaultAccountWalletF = FundWalletUtil.fundAccountForWallet( @@ -131,7 +135,7 @@ trait FundWalletUtil extends BitcoinSLogger { ) } yield fundedAcct1 - //sanity check to make sure we have money + // sanity check to make sure we have money for { fundedWallet <- fundedAccount1WalletF balance <- fundedWallet.getBalance(defaultAccount) @@ -169,27 +173,29 @@ object FundWalletUtil extends FundWalletUtil { } } - /** This is a wallet that was two funded accounts - * Account 0 (default account) has utxos of 1,2,3 bitcoin in it (6 btc total) - * Account 1 has a utxos of 0.2,0.3,0.5 bitcoin in it (0.6 total) + /** This is a wallet that was two funded accounts Account 0 (default account) + * has utxos of 1,2,3 bitcoin in it (6 btc total) Account 1 has a utxos of + * 0.2,0.3,0.5 bitcoin in it (0.6 total) */ case class FundedWallet(wallet: Wallet) extends FundedTestWallet case class FundedDLCWallet(wallet: DLCWallet) extends FundedTestWallet - /** This creates a wallet that was two funded accounts - * Account 0 (default account) has utxos of 1,2,3 bitcoin in it (6 btc total) - * Account 1 has a utxos of 0.2,0.3,0.5 bitcoin in it (1 btc total) + /** This creates a wallet that was two funded accounts Account 0 (default + * account) has utxos of 1,2,3 bitcoin in it (6 btc total) Account 1 has a + * utxos of 0.2,0.3,0.5 bitcoin in it (1 btc total) */ def createFundedWallet(nodeApi: NodeApi, chainQueryApi: ChainQueryApi)( implicit config: WalletAppConfig, - system: ActorSystem): Future[FundedWallet] = { + system: ActorSystem + ): Future[FundedWallet] = { import system.dispatcher for { - wallet <- BitcoinSWalletTest.createWallet2Accounts(nodeApi = nodeApi, - chainQueryApi = - chainQueryApi) + wallet <- BitcoinSWalletTest.createWallet2Accounts( + nodeApi = nodeApi, + chainQueryApi = chainQueryApi + ) funded <- FundWalletUtil.fundWallet(wallet) } yield FundedWallet(funded.wallet) } @@ -197,12 +203,14 @@ object FundWalletUtil extends FundWalletUtil { def createFundedDLCWallet(nodeApi: NodeApi, chainQueryApi: ChainQueryApi)( implicit config: BitcoinSAppConfig, - system: ActorSystem): Future[FundedDLCWallet] = { + system: ActorSystem + ): Future[FundedDLCWallet] = { import system.dispatcher for { - wallet <- BitcoinSWalletTest.createDLCWallet2Accounts(nodeApi = nodeApi, - chainQueryApi = - chainQueryApi) + wallet <- BitcoinSWalletTest.createDLCWallet2Accounts( + nodeApi = nodeApi, + chainQueryApi = chainQueryApi + ) funded <- FundWalletUtil.fundWallet(wallet) } yield { FundedDLCWallet(funded.wallet.asInstanceOf[DLCWallet]) @@ -211,26 +219,32 @@ object FundWalletUtil extends FundWalletUtil { def createFundedDLCWalletWithBitcoind(bitcoind: BitcoindRpcClient)(implicit config: BitcoinSAppConfig, - system: ActorSystem): Future[FundedDLCWallet] = { + system: ActorSystem + ): Future[FundedDLCWallet] = { import system.dispatcher for { - tmp <- BitcoinSWalletTest.createDLCWallet2Accounts(nodeApi = bitcoind, - chainQueryApi = - bitcoind) + tmp <- BitcoinSWalletTest.createDLCWallet2Accounts( + nodeApi = bitcoind, + chainQueryApi = bitcoind + ) wallet = BitcoindRpcBackendUtil.createDLCWalletWithBitcoindCallbacks( bitcoind, tmp, - None)(system) + None + )(system) funded1 <- fundAccountForWalletWithBitcoind( BitcoinSWalletTest.defaultAcctAmts, wallet.walletConfig.defaultAccount, wallet, - bitcoind) + bitcoind + ) hdAccount1 = WalletTestUtil.getHdAccount1(wallet.walletConfig) - funded <- fundAccountForWalletWithBitcoind(BitcoinSWalletTest.account1Amt, - hdAccount1, - funded1, - bitcoind) + funded <- fundAccountForWalletWithBitcoind( + BitcoinSWalletTest.account1Amt, + hdAccount1, + funded1, + bitcoind + ) } yield { FundedDLCWallet(funded.asInstanceOf[DLCWallet]) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletAppConfigWithBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletAppConfigWithBitcoind.scala index 18f3819f16..2a71ba21aa 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletAppConfigWithBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletAppConfigWithBitcoind.scala @@ -10,4 +10,5 @@ sealed trait WalletAppConfigWithBitcoind { case class WalletAppConfigWithBitcoindRpc( walletAppConfig: WalletAppConfig, - bitcoind: BitcoindRpcClient) + bitcoind: BitcoindRpcClient +) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletAppConfigWithBitcoindFixtures.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletAppConfigWithBitcoindFixtures.scala index 09a8fa4f60..5b38925aa2 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletAppConfigWithBitcoindFixtures.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletAppConfigWithBitcoindFixtures.scala @@ -45,7 +45,8 @@ trait WalletAppConfigWithBitcoindNewestFixtures def withWalletAppConfigBitcoindCached( test: OneArgAsyncTest, - bitcoind: BitcoindRpcClient): FutureOutcome = { + bitcoind: BitcoindRpcClient + ): FutureOutcome = { makeDependentFixture[WalletAppConfigWithBitcoindRpc]( () => { val walletConfig = @@ -57,7 +58,8 @@ trait WalletAppConfigWithBitcoindNewestFixtures }, { case walletAppConfigWithBitcoindRpc => BitcoinSWalletTest.destroyWalletAppConfig( - walletAppConfigWithBitcoindRpc.walletAppConfig) + walletAppConfigWithBitcoindRpc.walletAppConfig + ) } )(test) } diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletTestUtil.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletTestUtil.scala index a8ef430676..00dba97932 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletTestUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletTestUtil.scala @@ -30,61 +30,76 @@ object WalletTestUtil { val hdCoinType: HDCoinType = HDCoinType.Testnet lazy val sampleTransaction: Transaction = Transaction( - "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000") + "020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000" + ) - /** Useful if you want wallet test runs - * To use the same key values each time + /** Useful if you want wallet test runs To use the same key values each time */ lazy val sampleMnemonic = MnemonicCode.fromWords( - Vector("portion", - "uniform", - "owner", - "crime", - "duty", - "floor", - "sketch", - "stumble", - "outer", - "south", - "relax", - "car")) + Vector( + "portion", + "uniform", + "owner", + "crime", + "duty", + "floor", + "sketch", + "stumble", + "outer", + "south", + "relax", + "car" + ) + ) lazy val sampleSegwitPath = - SegWitHDPath(hdCoinType, - accountIndex = 0, - HDChainType.External, - addressIndex = 0) + SegWitHDPath( + hdCoinType, + accountIndex = 0, + HDChainType.External, + addressIndex = 0 + ) /** Sample legacy HD path */ - lazy val sampleLegacyPath = LegacyHDPath(hdCoinType, - accountIndex = 0, - HDChainType.Change, - addressIndex = 0) + lazy val sampleLegacyPath = LegacyHDPath( + hdCoinType, + accountIndex = 0, + HDChainType.Change, + addressIndex = 0 + ) lazy val sampleNestedSegwitPath: NestedSegWitHDPath = - NestedSegWitHDPath(hdCoinType, - accountIndex = 0, - HDChainType.External, - addressIndex = 0) + NestedSegWitHDPath( + hdCoinType, + accountIndex = 0, + HDChainType.External, + addressIndex = 0 + ) private def freshXpub(): ExtPublicKey = CryptoGenerators.extPublicKey.sampleSome - /** Checks that the given values are the same-ish, save for fee-level deviations */ + /** Checks that the given values are the same-ish, save for fee-level + * deviations + */ def isCloseEnough( first: CurrencyUnit, second: CurrencyUnit, - delta: CurrencyUnit = 300.sats): Boolean = { + delta: CurrencyUnit = 300.sats + ): Boolean = { Math.abs( - first.satoshis.toLong - second.satoshis.toLong) <= delta.satoshis.toLong + first.satoshis.toLong - second.satoshis.toLong + ) <= delta.satoshis.toLong } def isFeeRateCloseEnough(outgoingTx: OutgoingTransactionDb): Boolean = { TxUtil - .isValidFeeRange(outgoingTx.expectedFee, - outgoingTx.actualFee, - outgoingTx.feeRate) + .isValidFeeRange( + outgoingTx.expectedFee, + outgoingTx.actualFee, + outgoingTx.feeRate + ) .isSuccess } @@ -100,8 +115,10 @@ object WalletTestUtil { AccountDb(freshXpub(), defaultHdAccount) def nestedSegWitAccountDb: AccountDb = - AccountDb(freshXpub(), - HDAccount(HDCoin(HDPurposes.NestedSegWit, hdCoinType), 0)) + AccountDb( + freshXpub(), + HDAccount(HDCoin(HDPurposes.NestedSegWit, hdCoinType), 0) + ) private def randomScriptWitness: ScriptWitness = P2WPKHWitnessV0(freshXpub().key) @@ -115,7 +132,8 @@ object WalletTestUtil { def sampleSegwitUTXO( spk: ScriptPubKey, - state: TxoState): SegwitV0SpendingInfo = { + state: TxoState + ): SegwitV0SpendingInfo = { val outpoint = TransactionOutPoint(randomTXID, randomVout) val output = TransactionOutput(1.bitcoin, spk) @@ -142,7 +160,8 @@ object WalletTestUtil { def sampleLegacyUTXO( spk: ScriptPubKey, - state: TxoState): LegacySpendingInfo = { + state: TxoState + ): LegacySpendingInfo = { val outpoint = TransactionOutPoint(randomTXID, randomVout) val output = @@ -156,16 +175,19 @@ object WalletTestUtil { } } - LegacySpendingInfo(state = state, - outPoint = outpoint, - output = output, - privKeyPath = privKeyPath, - spendingTxIdOpt = spendingTxIdOpt) + LegacySpendingInfo( + state = state, + outPoint = outpoint, + output = output, + privKeyPath = privKeyPath, + spendingTxIdOpt = spendingTxIdOpt + ) } def sampleNestedSegwitUTXO( ecPublicKey: ECPublicKey, - state: TxoState): NestedSegwitV0SpendingInfo = { + state: TxoState + ): NestedSegwitV0SpendingInfo = { val wpkh = P2WPKHWitnessSPKV0(ecPublicKey) val outpoint = TransactionOutPoint(randomTXID, randomVout) val output = @@ -194,29 +216,33 @@ object WalletTestUtil { /** Given an account returns a sample address */ def getAddressDb(account: AccountDb, addressIndex: Int = 0): AddressDb = { - val path = SegWitHDPath(WalletTestUtil.hdCoinType, - chainType = HDChainType.External, - accountIndex = account.hdAccount.index, - addressIndex = addressIndex) + val path = SegWitHDPath( + WalletTestUtil.hdCoinType, + chainType = HDChainType.External, + accountIndex = account.hdAccount.index, + addressIndex = addressIndex + ) val pubkey: ECPublicKey = ECPublicKey.freshPublicKey val hashedPubkey = CryptoUtil.sha256Hash160(pubkey.bytes) val wspk = P2WPKHWitnessSPKV0(pubkey) val scriptWitness = P2WPKHWitnessV0(pubkey) val address = Bech32Address.apply(wspk, WalletTestUtil.networkParam) - SegWitAddressDb(path = path, - ecPublicKey = pubkey, - hashedPubkey, - address, - scriptWitness, - scriptPubKey = wspk) + SegWitAddressDb( + path = path, + ecPublicKey = pubkey, + hashedPubkey, + address, + scriptWitness, + scriptPubKey = wspk + ) } def insertDummyIncomingTransaction( daos: WalletDAOs, utxo: SpendingInfoDb, - confirmed: Boolean = true)(implicit - ec: ExecutionContext): Future[IncomingTransactionDb] = { + confirmed: Boolean = true + )(implicit ec: ExecutionContext): Future[IncomingTransactionDb] = { val blockHashOpt = if (confirmed) Some(randomBlockHash) else None val txDb = TransactionDb( @@ -240,10 +266,12 @@ object WalletTestUtil { /** Given an account returns a sample address */ def getNestedSegwitAddressDb(account: AccountDb): AddressDb = { - val path = NestedSegWitHDPath(WalletTestUtil.hdCoinType, - chainType = HDChainType.External, - accountIndex = account.hdAccount.index, - addressIndex = 0) + val path = NestedSegWitHDPath( + WalletTestUtil.hdCoinType, + chainType = HDChainType.External, + accountIndex = account.hdAccount.index, + addressIndex = 0 + ) val pubkey: ECPublicKey = ECPublicKey.freshPublicKey val hashedPubkey = CryptoUtil.sha256Hash160(pubkey.bytes) val wpkh = P2WPKHWitnessSPKV0(pubkey) @@ -251,17 +279,20 @@ object WalletTestUtil { val spk = P2SHScriptPubKey(wpkh) val address = P2SHAddress.apply(spk, WalletTestUtil.networkParam) - NestedSegWitAddressDb(path = path, - ecPublicKey = pubkey, - hashedPubkey, - address, - witness, - scriptPubKey = spk) + NestedSegWitAddressDb( + path = path, + ecPublicKey = pubkey, + hashedPubkey, + address, + witness, + scriptPubKey = spk + ) } /** Inserts an account, address and finally a UTXO */ def insertLegacyUTXO(daos: WalletDAOs, state: TxoState)(implicit - ec: ExecutionContext): Future[LegacySpendingInfo] = { + ec: ExecutionContext + ): Future[LegacySpendingInfo] = { for { account <- daos.accountDAO.upsert(WalletTestUtil.firstAccountDb) addr <- daos.addressDAO.create(getAddressDb(account)) @@ -273,7 +304,8 @@ object WalletTestUtil { /** Inserts an account, address and finally a UTXO */ def insertSegWitUTXO(daos: WalletDAOs, state: TxoState)(implicit - ec: ExecutionContext): Future[SegwitV0SpendingInfo] = { + ec: ExecutionContext + ): Future[SegwitV0SpendingInfo] = { for { account <- daos.accountDAO.create(WalletTestUtil.firstAccountDb) addr <- daos.addressDAO.create(getAddressDb(account)) @@ -285,7 +317,8 @@ object WalletTestUtil { /** Inserts an account, address and finally a UTXO */ def insertNestedSegWitUTXO(daos: WalletDAOs, state: TxoState)(implicit - ec: ExecutionContext): Future[NestedSegwitV0SpendingInfo] = { + ec: ExecutionContext + ): Future[NestedSegwitV0SpendingInfo] = { for { account <- daos.accountDAO.create(WalletTestUtil.nestedSegWitAccountDb) addr <- daos.addressDAO.create(getNestedSegwitAddressDb(account)) diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletWithBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletWithBitcoind.scala index 5e3f6f2881..6dca891366 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletWithBitcoind.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/WalletWithBitcoind.scala @@ -11,11 +11,11 @@ sealed trait WalletWithBitcoind[T <: BitcoindRpcClient] { def walletConfig: WalletAppConfig } -/** General pairing of a wallet with a bitcoind rpc. If you don't care about - * the version of bitcoind, you should use this. +/** General pairing of a wallet with a bitcoind rpc. If you don't care about the + * version of bitcoind, you should use this. */ case class WalletWithBitcoindRpc( wallet: NeutrinoHDWalletApi, bitcoind: BitcoindRpcClient, - walletConfig: WalletAppConfig) - extends WalletWithBitcoind[BitcoindRpcClient] + walletConfig: WalletAppConfig +) extends WalletWithBitcoind[BitcoindRpcClient] diff --git a/testkit/src/main/scala/org/bitcoins/util/ListUtil.scala b/testkit/src/main/scala/org/bitcoins/util/ListUtil.scala index 040d63c0d6..3b78c34e64 100644 --- a/testkit/src/main/scala/org/bitcoins/util/ListUtil.scala +++ b/testkit/src/main/scala/org/bitcoins/util/ListUtil.scala @@ -10,8 +10,7 @@ object ListUtil { (y, idxY) <- xs.zipWithIndex if idxX < idxY } yield (x, y) - /** Generates a vector of vectors "rotating" the head element - * over `xs`. + /** Generates a vector of vectors "rotating" the head element over `xs`. * * {{{ * > slideFirst(Vector(1, 2, 3)) diff --git a/testkit/src/test/scala/org/bitcoins/testkit/util/ScalaTestUtilTest.scala b/testkit/src/test/scala/org/bitcoins/testkit/util/ScalaTestUtilTest.scala index cfeaa1d80e..9476f88b91 100644 --- a/testkit/src/test/scala/org/bitcoins/testkit/util/ScalaTestUtilTest.scala +++ b/testkit/src/test/scala/org/bitcoins/testkit/util/ScalaTestUtilTest.scala @@ -19,7 +19,7 @@ class ScalaTestUtilTest extends BitcoinSUnitTest { def futureFail = Future { - //sleep for awhile and then eventually fail + // sleep for awhile and then eventually fail Thread.sleep(1000) f } diff --git a/tor-test/src/test/scala/org/bitcoins/tor/Socks5ClientTransportSpec.scala b/tor-test/src/test/scala/org/bitcoins/tor/Socks5ClientTransportSpec.scala index 205f81be2c..9f570e77ac 100644 --- a/tor-test/src/test/scala/org/bitcoins/tor/Socks5ClientTransportSpec.scala +++ b/tor-test/src/test/scala/org/bitcoins/tor/Socks5ClientTransportSpec.scala @@ -24,14 +24,16 @@ class Socks5ClientTransportSpec extends BitcoinSAsyncTest with CachedTor { ClientConnectionSettings(system).withTransport(socks5ClientTransport) val settings = ConnectionPoolSettings(system).withConnectionSettings( - clientConnectionSettings) + clientConnectionSettings + ) it should "handle clear net addresses" in { assume(TorUtil.torEnabled, "TOR environment variable is not set") for { response <- Http().singleRequest( HttpRequest(uri = "http://blockstream.info/"), - settings = settings) + settings = settings + ) } yield { // should redirect to the HTTPS endpoint assert(response.status.intValue() == 301) @@ -39,7 +41,8 @@ class Socks5ClientTransportSpec extends BitcoinSAsyncTest with CachedTor { response.headers .find(_.lowercaseName() == "location") .map(_.value()) - .contains("https://blockstream.info/")) + .contains("https://blockstream.info/") + ) } } @@ -49,7 +52,8 @@ class Socks5ClientTransportSpec extends BitcoinSAsyncTest with CachedTor { response <- Http().singleRequest( HttpRequest(uri = "http://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion/"), - settings = settings) + settings = settings + ) html <- response.entity.dataBytes .runFold(ByteString(""))(_ ++ _) .map(x => x.utf8String) diff --git a/tor-test/src/test/scala/org/bitcoins/tor/TorProtocolHandlerSpec.scala b/tor-test/src/test/scala/org/bitcoins/tor/TorProtocolHandlerSpec.scala index 08d25082c8..3b2f7c4fc2 100644 --- a/tor-test/src/test/scala/org/bitcoins/tor/TorProtocolHandlerSpec.scala +++ b/tor-test/src/test/scala/org/bitcoins/tor/TorProtocolHandlerSpec.scala @@ -67,10 +67,13 @@ class TorProtocolHandlerSpec val promiseOnionAddress = Promise[InetSocketAddress]() val protocolHandler = TestActorRef( - props(authentication = Password(PASSWORD), - privateKeyPath = PkFilePath, - virtualPort = 9999, - onionAdded = Some(promiseOnionAddress))) + props( + authentication = Password(PASSWORD), + privateKeyPath = PkFilePath, + virtualPort = 9999, + onionAdded = Some(promiseOnionAddress) + ) + ) protocolHandler ! Connected(LocalHost, LocalHost) @@ -103,14 +106,18 @@ class TorProtocolHandlerSpec addr.get, InetSocketAddress.createUnresolved( "mrl2d3ilhctt2vw4qzvmz3etzjvpnc6dczliq5chrxetthgbuczuggyd.onion", - 9999)) + 9999 + ) + ) val address = Await.result(promiseOnionAddress.future, 3.seconds) assertAddressesEqual( address, InetSocketAddress.createUnresolved( "mrl2d3ilhctt2vw4qzvmz3etzjvpnc6dczliq5chrxetthgbuczuggyd.onion", - 9999)) + 9999 + ) + ) assert(readString(PkFilePath) === "ED25519-V3:private-key") } @@ -128,10 +135,13 @@ class TorProtocolHandlerSpec val promiseOnionAddress = Promise[InetSocketAddress]() val protocolHandler = TestActorRef( - props(authentication = Password(PASSWORD), - privateKeyPath = PkFilePath, - virtualPort = 9999, - onionAdded = Some(promiseOnionAddress))) + props( + authentication = Password(PASSWORD), + privateKeyPath = PkFilePath, + virtualPort = 9999, + onionAdded = Some(promiseOnionAddress) + ) + ) protocolHandler ! Connected(LocalHost, LocalHost) @@ -152,10 +162,13 @@ class TorProtocolHandlerSpec val promiseOnionAddress = Promise[InetSocketAddress]() val protocolHandler = TestActorRef( - props(authentication = Password(PASSWORD), - privateKeyPath = PkFilePath, - virtualPort = 9999, - onionAdded = Some(promiseOnionAddress))) + props( + authentication = Password(PASSWORD), + privateKeyPath = PkFilePath, + virtualPort = 9999, + onionAdded = Some(promiseOnionAddress) + ) + ) protocolHandler ! Connected(LocalHost, LocalHost) @@ -167,10 +180,13 @@ class TorProtocolHandlerSpec "250 OK\r\n" ) - assert(intercept[TorException] { - Await.result(promiseOnionAddress.future, 3.seconds) - } === TorException( - "cannot use authentication 'password', supported methods are 'COOKIE,SAFECOOKIE'")) + assert( + intercept[TorException] { + Await.result(promiseOnionAddress.future, 3.seconds) + } === TorException( + "cannot use authentication 'password', supported methods are 'COOKIE,SAFECOOKIE'" + ) + ) } test("invalid server hash") { @@ -179,10 +195,13 @@ class TorProtocolHandlerSpec Files.write(CookieFilePath, CryptoUtil.randomBytes(32).toArray) val protocolHandler = TestActorRef( - props(authentication = SafeCookie(ClientNonce), - privateKeyPath = PkFilePath, - virtualPort = 9999, - onionAdded = Some(promiseOnionAddress))) + props( + authentication = SafeCookie(ClientNonce), + privateKeyPath = PkFilePath, + virtualPort = 9999, + onionAdded = Some(promiseOnionAddress) + ) + ) protocolHandler ! Connected(LocalHost, LocalHost) @@ -194,8 +213,11 @@ class TorProtocolHandlerSpec "250 OK\r\n" ) - expectMsg(ByteString( - "AUTHCHALLENGE SAFECOOKIE 8969a7f3c03cd21bfd1cc49dbbd8f398345261b5b66319df76bb2fdd8d96bcca\r\n")) + expectMsg( + ByteString( + "AUTHCHALLENGE SAFECOOKIE 8969a7f3c03cd21bfd1cc49dbbd8f398345261b5b66319df76bb2fdd8d96bcca\r\n" + ) + ) protocolHandler ! ByteString( "250 AUTHCHALLENGE SERVERHASH=6828e74049924f37cbc61f2aad4dd78d8dc09bef1b4c3bf6ff454016ed9d50df SERVERNONCE=b4aa04b6e7e2df60dcb0f62c264903346e05d1675e77795529e22ca90918dee7\r\n" ) @@ -216,7 +238,8 @@ class TorProtocolHandlerSpec privateKeyPath = PkFilePath, virtualPort = 9999, onionAdded = Some(promiseOnionAddress) - )) + ) + ) protocolHandler ! Connected(LocalHost, LocalHost) @@ -228,22 +251,31 @@ class TorProtocolHandlerSpec "250 OK\r\n" ) - expectMsg(ByteString( - "AUTHCHALLENGE SAFECOOKIE 8969a7f3c03cd21bfd1cc49dbbd8f398345261b5b66319df76bb2fdd8d96bcca\r\n")) + expectMsg( + ByteString( + "AUTHCHALLENGE SAFECOOKIE 8969a7f3c03cd21bfd1cc49dbbd8f398345261b5b66319df76bb2fdd8d96bcca\r\n" + ) + ) protocolHandler ! ByteString( "250 AUTHCHALLENGE SERVERHASH=6828e74049924f37cbc61f2aad4dd78d8dc09bef1b4c3bf6ff454016ed9d50df SERVERNONCE=b4aa04b6e7e2df60dcb0f62c264903346e05d1675e77795529e22ca90918dee7\r\n" ) - expectMsg(ByteString( - "AUTHENTICATE 0ddcab5deb39876cdef7af7860a1c738953395349f43b99f4e5e0f131b0515df\r\n")) + expectMsg( + ByteString( + "AUTHENTICATE 0ddcab5deb39876cdef7af7860a1c738953395349f43b99f4e5e0f131b0515df\r\n" + ) + ) protocolHandler ! ByteString( "515 Authentication failed: Safe cookie response did not match expected value.\r\n" ) - assert(intercept[TorException] { - Await.result(promiseOnionAddress.future, 3.seconds) - } === TorException( - "server returned error: 515 Authentication failed: Safe cookie response did not match expected value.")) + assert( + intercept[TorException] { + Await.result(promiseOnionAddress.future, 3.seconds) + } === TorException( + "server returned error: 515 Authentication failed: Safe cookie response did not match expected value." + ) + ) } test("ADD_ONION failure") { @@ -257,7 +289,8 @@ class TorProtocolHandlerSpec privateKeyPath = PkFilePath, virtualPort = 9999, onionAdded = Some(promiseOnionAddress) - )) + ) + ) protocolHandler ! Connected(LocalHost, LocalHost) @@ -269,14 +302,20 @@ class TorProtocolHandlerSpec "250 OK\r\n" ) - expectMsg(ByteString( - "AUTHCHALLENGE SAFECOOKIE 8969a7f3c03cd21bfd1cc49dbbd8f398345261b5b66319df76bb2fdd8d96bcca\r\n")) + expectMsg( + ByteString( + "AUTHCHALLENGE SAFECOOKIE 8969a7f3c03cd21bfd1cc49dbbd8f398345261b5b66319df76bb2fdd8d96bcca\r\n" + ) + ) protocolHandler ! ByteString( "250 AUTHCHALLENGE SERVERHASH=6828e74049924f37cbc61f2aad4dd78d8dc09bef1b4c3bf6ff454016ed9d50df SERVERNONCE=b4aa04b6e7e2df60dcb0f62c264903346e05d1675e77795529e22ca90918dee7\r\n" ) - expectMsg(ByteString( - "AUTHENTICATE 0ddcab5deb39876cdef7af7860a1c738953395349f43b99f4e5e0f131b0515df\r\n")) + expectMsg( + ByteString( + "AUTHENTICATE 0ddcab5deb39876cdef7af7860a1c738953395349f43b99f4e5e0f131b0515df\r\n" + ) + ) protocolHandler ! ByteString( "250 OK\r\n" ) @@ -297,9 +336,11 @@ class TorProtocolHandlerSpec private def assertAddressesEqual( actual: InetSocketAddress, - expected: InetSocketAddress) = { + expected: InetSocketAddress + ) = { assert( - actual.getHostString == expected.getHostString && actual.getPort == expected.getPort) + actual.getHostString == expected.getHostString && actual.getPort == expected.getPort + ) } } diff --git a/tor/src/main/scala/org/bitcoins/tor/Socks5ClientTransport.scala b/tor/src/main/scala/org/bitcoins/tor/Socks5ClientTransport.scala index 565e932971..ee28d75b84 100644 --- a/tor/src/main/scala/org/bitcoins/tor/Socks5ClientTransport.scala +++ b/tor/src/main/scala/org/bitcoins/tor/Socks5ClientTransport.scala @@ -31,17 +31,23 @@ class Socks5ClientTransport(proxyParams: Socks5ProxyParams) override def connectTo( host: String, port: Int, - settings: ClientConnectionSettings)(implicit system: ActorSystem): Flow[ - ByteString, - ByteString, - Future[Http.OutgoingConnection]] = { + settings: ClientConnectionSettings + )(implicit + system: ActorSystem + ): Flow[ByteString, ByteString, Future[Http.OutgoingConnection]] = { Socks5ProxyGraphStage(host, port, proxyParams) .joinMat( - TCP.connectTo(proxyParams.address.getHostString, - proxyParams.address.getPort, - settings))(Keep.right) - .mapMaterializedValue(_.map(_.copy(remoteAddress = - InetSocketAddress.createUnresolved(host, port)))(system.dispatcher)) + TCP.connectTo( + proxyParams.address.getHostString, + proxyParams.address.getPort, + settings + ) + )(Keep.right) + .mapMaterializedValue( + _.map( + _.copy(remoteAddress = InetSocketAddress.createUnresolved(host, port)) + )(system.dispatcher) + ) } } @@ -49,44 +55,50 @@ object Socks5ClientTransport { /** Creates [[ConnectionPoolSettings]] for the provided proxy parameters. */ - def createConnectionPoolSettings(proxyParams: Socks5ProxyParams)(implicit - system: ActorSystem): ConnectionPoolSettings = { + def createConnectionPoolSettings( + proxyParams: Socks5ProxyParams + )(implicit system: ActorSystem): ConnectionPoolSettings = { val socks5ClientTransport = new Socks5ClientTransport(proxyParams) val clientConnectionSettings = ClientConnectionSettings(system).withTransport(socks5ClientTransport) ConnectionPoolSettings(system).withConnectionSettings( - clientConnectionSettings) + clientConnectionSettings + ) } /** Creates [[ConnectionPoolSettings]] for the provided proxy parameters. */ - def createConnectionPoolSettings(proxyParamsOpt: Option[Socks5ProxyParams])( - implicit system: ActorSystem): ConnectionPoolSettings = + def createConnectionPoolSettings( + proxyParamsOpt: Option[Socks5ProxyParams] + )(implicit system: ActorSystem): ConnectionPoolSettings = proxyParamsOpt match { case Some(proxyParams) => createConnectionPoolSettings(proxyParams) case None => ConnectionPoolSettings(system) } - /** Creates [[ConnectionPoolSettings]] for the provided proxy parameters. - * If the URI points to the loopback interface returns the default [[ConnectionPoolSettings]] without SOCKS5 proxy + /** Creates [[ConnectionPoolSettings]] for the provided proxy parameters. If + * the URI points to the loopback interface returns the default + * [[ConnectionPoolSettings]] without SOCKS5 proxy */ def createConnectionPoolSettings(uri: URI, proxyParams: Socks5ProxyParams)( - implicit system: ActorSystem): ConnectionPoolSettings = { + implicit system: ActorSystem + ): ConnectionPoolSettings = { if (!NetworkUtil.isLocalhost(uri.getHost)) { createConnectionPoolSettings(proxyParams) } else ConnectionPoolSettings(system) } - /** Creates [[ConnectionPoolSettings]] for the provided proxy parameters. - * If the URI points to the loopback interface returns the default [[ConnectionPoolSettings]] without SOCKS5 proxy + /** Creates [[ConnectionPoolSettings]] for the provided proxy parameters. If + * the URI points to the loopback interface returns the default + * [[ConnectionPoolSettings]] without SOCKS5 proxy */ def createConnectionPoolSettings( uri: URI, - proxyParams: Option[Socks5ProxyParams])(implicit - system: ActorSystem): ConnectionPoolSettings = { + proxyParams: Option[Socks5ProxyParams] + )(implicit system: ActorSystem): ConnectionPoolSettings = { if (!NetworkUtil.isLocalhost(uri.getHost)) { createConnectionPoolSettings(proxyParams) } else ConnectionPoolSettings(system) @@ -104,23 +116,19 @@ object Socks5ProxyGraphStage { def apply( targetHostName: String, targetPort: Int, - proxyParams: Socks5ProxyParams): BidiFlow[ - ByteString, - ByteString, - ByteString, - ByteString, - NotUsed] = + proxyParams: Socks5ProxyParams + ): BidiFlow[ByteString, ByteString, ByteString, ByteString, NotUsed] = BidiFlow.fromGraph( - new Socks5ProxyGraphStage(targetHostName, targetPort, proxyParams)) + new Socks5ProxyGraphStage(targetHostName, targetPort, proxyParams) + ) } class Socks5ProxyGraphStage( targetHostName: String, targetPort: Int, - proxyParams: Socks5ProxyParams) - extends GraphStage[ - BidiShape[ByteString, ByteString, ByteString, ByteString]] + proxyParams: Socks5ProxyParams +) extends GraphStage[BidiShape[ByteString, ByteString, ByteString, ByteString]] with BitcoinSLogger { val bytesIn: Inlet[ByteString] = Inlet("OutgoingTCP.in") @@ -132,11 +140,9 @@ class Socks5ProxyGraphStage( import Socks5Connection._ import Socks5ProxyGraphStage._ - override def shape: BidiShape[ - ByteString, - ByteString, - ByteString, - ByteString] = BidiShape.apply(socks5In, bytesOut, bytesIn, socks5Out) + override def shape + : BidiShape[ByteString, ByteString, ByteString, ByteString] = + BidiShape.apply(socks5In, bytesOut, bytesIn, socks5Out) private val credentialsOpt = Socks5ProxyParams.proxyCredentials(proxyParams) @@ -146,7 +152,8 @@ class Socks5ProxyGraphStage( socks5PasswordAuthenticationRequest(c.username, c.password)) private val connectMessage = socks5ConnectionRequest( - InetSocketAddress.createUnresolved(targetHostName, targetPort)) + InetSocketAddress.createUnresolved(targetHostName, targetPort) + ) override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = { new GraphStageLogic(shape) with StageLogging { @@ -168,7 +175,9 @@ class Socks5ProxyGraphStage( case None => failStage( new IllegalStateException( - "Cannot send AUTH message: undefined credentials")) + "Cannot send AUTH message: undefined credentials" + ) + ) } } @@ -211,7 +220,8 @@ class Socks5ProxyGraphStage( case Failure(ex) => logger.error( s"Failed to connect $targetHostName:$targetPort via tor", - ex) + ex + ) failStage(ex) } case _ => @@ -224,13 +234,15 @@ class Socks5ProxyGraphStage( sendGreeting() } - setHandler(bytesIn, - new InHandler { + setHandler( + bytesIn, + new InHandler { - override def onPush(): Unit = { - parseResponse(grab(bytesIn)) - } - }) + override def onPush(): Unit = { + parseResponse(grab(bytesIn)) + } + } + ) setHandler(socks5In, eagerTerminateInput) setHandler(bytesOut, eagerTerminateOutput) diff --git a/tor/src/main/scala/org/bitcoins/tor/Socks5Connection.scala b/tor/src/main/scala/org/bitcoins/tor/Socks5Connection.scala index 197a6b7720..ea81c671ab 100644 --- a/tor/src/main/scala/org/bitcoins/tor/Socks5Connection.scala +++ b/tor/src/main/scala/org/bitcoins/tor/Socks5Connection.scala @@ -18,14 +18,16 @@ import scala.util.{Failure, Success, Try} * * Created by rorp * - * @param connection underlying TcpConnection - * @param credentialsOpt optional username/password for authentication + * @param connection + * underlying TcpConnection + * @param credentialsOpt + * optional username/password for authentication */ class Socks5Connection( connection: ActorRef, credentialsOpt: Option[Credentials], - target: Socks5Connect) - extends Actor + target: Socks5Connect +) extends Actor with ActorLogging with BitcoinSLogger { @@ -47,10 +49,14 @@ class Socks5Connection( if (parseGreetings(data, passwordAuth) == PasswordAuth) { context become authenticate val credentials = credentialsOpt.getOrElse( - throw Socks5Error("Credentials are not defined")) + throw Socks5Error("Credentials are not defined") + ) connection ! Tcp.Write( - socks5PasswordAuthenticationRequest(credentials.username, - credentials.password)) + socks5PasswordAuthenticationRequest( + credentials.username, + credentials.password + ) + ) connection ! Tcp.ResumeReading } else { context become connectionRequest @@ -72,13 +78,15 @@ class Socks5Connection( connectedAddressT match { case Success(connectedAddress) => logger.info( - s"Tor connection request succeeded. target=$target connectedAddress=$connectedAddress") + s"Tor connection request succeeded. target=$target connectedAddress=$connectedAddress" + ) context become connected context.parent ! Socks5Connected(connectedAddress) isConnected = true case Failure(err) => logger.error( - s"Tor connection request failed to $target errMsg=${err.toString}") + s"Tor connection request failed to $target errMsg=${err.toString}" + ) } } @@ -95,7 +103,7 @@ class Socks5Connection( override def unhandled(message: Any): Unit = message match { case Terminated(actor) if actor == connection => context stop self case _: Tcp.ConnectionClosed => context stop self - case _ => log.warning(s"unhandled message=$message") + case _ => log.warning(s"unhandled message=$message") } override def postStop(): Unit = { @@ -113,8 +121,10 @@ object Socks5Connection extends BitcoinSLogger { def props( tcpConnection: ActorRef, credentials_opt: Option[Credentials], - command: Socks5Connect): Props = Props( - new Socks5Connection(tcpConnection, credentials_opt, command)) + command: Socks5Connect + ): Props = Props( + new Socks5Connection(tcpConnection, credentials_opt, command) + ) case class Socks5Connect(address: InetSocketAddress) extends Tcp.Command @@ -133,20 +143,25 @@ object Socks5Connection extends BitcoinSLogger { def socks5PasswordAuthenticationRequest( username: String, - password: String): ByteString = { + password: String + ): ByteString = { val usernameBytes = ByteString(username) val passwordBytes = ByteString(password) - ByteString(0x01, // version of username/password authentication - usernameBytes.length.toByte) ++ + ByteString( + 0x01, // version of username/password authentication + usernameBytes.length.toByte + ) ++ usernameBytes ++ ByteString(passwordBytes.length.toByte) ++ passwordBytes } def socks5ConnectionRequest(address: InetSocketAddress): ByteString = { - ByteString(0x05, // SOCKS version - 0x01, // establish a TCP/IP stream connection - 0x00) ++ // reserved + ByteString( + 0x05, // SOCKS version + 0x01, // establish a TCP/IP stream connection + 0x00 + ) ++ // reserved addressToByteString(address) ++ portToByteString(address.getPort) } @@ -164,12 +179,15 @@ object Socks5Connection extends BitcoinSLogger { } def addressToByteString(address: InetSocketAddress): ByteString = Option( - address.getAddress) match { + address.getAddress + ) match { case None => // unresolved address, use SOCKS5 resolver val host = address.getHostString - ByteString(0x03, // Domain name - host.length.toByte) ++ + ByteString( + 0x03, // Domain name + host.length.toByte + ) ++ ByteString(host) case Some(inetAddress) => inetAddressToByteString(inetAddress) @@ -183,7 +201,8 @@ object Socks5Connection extends BitcoinSLogger { throw Socks5Error("Invalid SOCKS5 version") } else if ( (!passwordAuth && data(1) != NoAuth) || (passwordAuth && data( - 1) != PasswordAuth) + 1 + ) != PasswordAuth) ) { throw Socks5Error("Unsupported SOCKS5 auth method") } else { @@ -243,15 +262,26 @@ object Socks5Connection extends BitcoinSLogger { def tryParseAuth(data: ByteString): Try[Boolean] = Try(parseAuth(data)) - /** @param socket the peer we are connecting to - * @param source the source that produces ByteStrings we need to send to our peer - * @param sink the sink that receives messages from our peer and performs application specific logic - * @param mergeHubSink a way for socks5Handler to send messages to the socks5 proxy to complete the handshake - * @param credentialsOpt the credentials to authenticate the socks5 proxy. + /** @param socket + * the peer we are connecting to + * @param source + * the source that produces ByteStrings we need to send to our peer + * @param sink + * the sink that receives messages from our peer and performs application + * specific logic + * @param mergeHubSink + * a way for socks5Handler to send messages to the socks5 proxy to complete + * the handshake + * @param credentialsOpt + * the credentials to authenticate the socks5 proxy. * @param mat - * @tparam MatSource the materialized value of the source given to us - * @tparam MatSink the materialized value of the sink given to us - * @return a running tcp connection along with the results of the materialize source and sink + * @tparam MatSource + * the materialized value of the source given to us + * @tparam MatSink + * the materialized value of the sink given to us + * @return + * a running tcp connection along with the results of the materialize + * source and sink */ def socks5Handler[MatSource, MatSink]( socket: InetSocketAddress, @@ -259,41 +289,56 @@ object Socks5Connection extends BitcoinSLogger { ByteString, ( Future[org.apache.pekko.stream.scaladsl.Tcp.OutgoingConnection], - MatSource)], + MatSource + ) + ], sink: Sink[Either[ByteString, Socks5ConnectionState], MatSink], mergeHubSink: Sink[ByteString, NotUsed], - credentialsOpt: Option[Credentials])(implicit mat: Materializer): Future[( - (org.apache.pekko.stream.scaladsl.Tcp.OutgoingConnection, MatSource), - MatSink)] = { + credentialsOpt: Option[Credentials] + )(implicit mat: Materializer): Future[ + ( + (org.apache.pekko.stream.scaladsl.Tcp.OutgoingConnection, MatSource), + MatSink + ) + ] = { - val flowState: Flow[ - ByteString, - Either[ByteString, Socks5ConnectionState], - NotUsed] = { + val flowState: Flow[ByteString, + Either[ + ByteString, + Socks5ConnectionState + ], + NotUsed] = { Flow[ByteString] .statefulMap[Socks5ConnectionState, - Either[ByteString, Socks5ConnectionState]](() => - Socks5ConnectionState.Disconnected)( + Either[ + ByteString, + Socks5ConnectionState + ]](() => Socks5ConnectionState.Disconnected)( { case (state, bytes) => state match { case Socks5ConnectionState.Disconnected => if ( - parseGreetings(bytes, - credentialsOpt.isDefined) == PasswordAuth + parseGreetings( + bytes, + credentialsOpt.isDefined + ) == PasswordAuth ) { logger.debug(s"Authenticating socks5 proxy...") credentialsOpt match { case Some(c) => val authBytes = - socks5PasswordAuthenticationRequest(c.username, - c.password) + socks5PasswordAuthenticationRequest( + c.username, + c.password + ) Source.single(authBytes).runWith(mergeHubSink) val state = Socks5ConnectionState.Authenticating (state, Right(state)) case None => sys.error( - s"Authentication required by socks5Proxy but we have no credentials") + s"Authentication required by socks5Proxy but we have no credentials" + ) } } else { @@ -311,7 +356,8 @@ object Socks5Connection extends BitcoinSLogger { val connRequestBytes = Socks5Connection.socks5ConnectionRequest(socket) logger.debug( - s"Writing socks5 connection request after auth") + s"Writing socks5 connection request after auth" + ) Source.single(connRequestBytes).runWith(mergeHubSink) val state = Socks5ConnectionState.Greeted (state, Right(state)) @@ -325,12 +371,14 @@ object Socks5Connection extends BitcoinSLogger { connectedAddressT match { case scala.util.Success(connectedAddress) => logger.info( - s"Tor connection request succeeded. target=${socket} connectedAddress=$connectedAddress") + s"Tor connection request succeeded. target=${socket} connectedAddress=$connectedAddress" + ) val state = Socks5ConnectionState.Connected (state, Right(state)) case scala.util.Failure(err) => sys.error( - s"Tor connection request failed to target=${socket} errMsg=${err.toString}") + s"Tor connection request failed to target=${socket} errMsg=${err.toString}" + ) } case Socks5ConnectionState.Connected => (Socks5ConnectionState.Connected, Left(bytes)) @@ -346,7 +394,7 @@ object Socks5Connection extends BitcoinSLogger { .toMat(sink)(Keep.both) .run() - //send greeting to kick off stream + // send greeting to kick off stream tcpConnectionF.map { conn => val passwordAuth = credentialsOpt.isDefined val greetingSource: Source[ByteString, NotUsed] = { diff --git a/tor/src/main/scala/org/bitcoins/tor/TorCallbacks.scala b/tor/src/main/scala/org/bitcoins/tor/TorCallbacks.scala index 5ec605c280..c845e4ceaf 100644 --- a/tor/src/main/scala/org/bitcoins/tor/TorCallbacks.scala +++ b/tor/src/main/scala/org/bitcoins/tor/TorCallbacks.scala @@ -15,7 +15,8 @@ trait TorCallbacks extends ModuleCallbacks[TorCallbacks] with BitcoinSLogger { onTorStarted.execute( (), (err: Throwable) => - logger.error(s"${onTorStarted.name} Callback failed with", err)) + logger.error(s"${onTorStarted.name} Callback failed with", err) + ) } def +(other: TorCallbacks): TorCallbacks diff --git a/tor/src/main/scala/org/bitcoins/tor/TorController.scala b/tor/src/main/scala/org/bitcoins/tor/TorController.scala index 655d4eced4..f4cc5b2b01 100644 --- a/tor/src/main/scala/org/bitcoins/tor/TorController.scala +++ b/tor/src/main/scala/org/bitcoins/tor/TorController.scala @@ -22,15 +22,18 @@ import scala.concurrent.{Future, Promise} /** Created by rorp * - * @param address Tor control address - * @param protocolHandlerProps Tor protocol handler props - * @param ec execution context + * @param address + * Tor control address + * @param protocolHandlerProps + * Tor protocol handler props + * @param ec + * execution context */ class TorController( address: InetSocketAddress, protocolHandlerProps: Props, - connectedPromiseOpt: Option[Promise[Done]]) - extends Actor + connectedPromiseOpt: Option[Promise[Done]] +) extends Actor with ActorLogging { import Tcp._ @@ -65,8 +68,10 @@ class TorController( case c @ CommandFailed(_: Write) => // O/S buffer was full protocolHandler ! SendFailed - log.error("Tor command failed", - c.cause.getOrElse(new RuntimeException("Unknown error"))) + log.error( + "Tor command failed", + c.cause.getOrElse(new RuntimeException("Unknown error")) + ) case Received(data) => protocolHandler ! data case _: ConnectionClosed => @@ -90,7 +95,8 @@ object TorController extends BitcoinSLogger { def props( address: InetSocketAddress, protocolHandlerProps: Props, - connectedPromiseOpt: Option[Promise[Done]]) = + connectedPromiseOpt: Option[Promise[Done]] + ) = Props(new TorController(address, protocolHandlerProps, connectedPromiseOpt)) case object SendFailed @@ -100,19 +106,25 @@ object TorController extends BitcoinSLogger { * * Note: only Tor protocol v3 is supported * - * @param controlAddress Tor control address - * @param authentication Tor controller auth mechanism (password or safecookie) - * @param privateKeyPath path to a file that contains a Tor private key - * @param virtualPort port for the public hidden service (typically 9735) - * @param targets address of our protected server (format [host:]port), 127.0.0.1:[[virtualPort]] if empty + * @param controlAddress + * Tor control address + * @param authentication + * Tor controller auth mechanism (password or safecookie) + * @param privateKeyPath + * path to a file that contains a Tor private key + * @param virtualPort + * port for the public hidden service (typically 9735) + * @param targets + * address of our protected server (format [host:]port), + * 127.0.0.1:[[virtualPort]] if empty */ def setUpHiddenService( controlAddress: InetSocketAddress, authentication: Authentication, privateKeyPath: Path, virtualPort: Int, - targets: Seq[String] = Seq.empty)(implicit - system: ActorSystem): Future[InetSocketAddress] = { + targets: Seq[String] = Seq.empty + )(implicit system: ActorSystem): Future[InetSocketAddress] = { import system.dispatcher val promiseTorAddress = Promise[InetSocketAddress]() val promiseConnected = Promise[Done]() @@ -126,9 +138,11 @@ object TorController extends BitcoinSLogger { ) val _ = system.actorOf( - TorController.props(address = controlAddress, - protocolHandlerProps = protocolHandlerProps, - connectedPromiseOpt = Some(promiseConnected)), + TorController.props( + address = controlAddress, + protocolHandlerProps = protocolHandlerProps, + connectedPromiseOpt = Some(promiseConnected) + ), s"tor-${System.currentTimeMillis()}" ) diff --git a/tor/src/main/scala/org/bitcoins/tor/TorProtocolHandler.scala b/tor/src/main/scala/org/bitcoins/tor/TorProtocolHandler.scala index ead66f860d..0f3e655543 100644 --- a/tor/src/main/scala/org/bitcoins/tor/TorProtocolHandler.scala +++ b/tor/src/main/scala/org/bitcoins/tor/TorProtocolHandler.scala @@ -21,21 +21,28 @@ case class TorException(private val msg: String) /** Created by rorp * - * Specification: https://gitweb.torproject.org/torspec.git/tree/control-spec.txt + * Specification: + * https://gitweb.torproject.org/torspec.git/tree/control-spec.txt * - * @param authentication Tor controller auth mechanism (password or safecookie) - * @param privateKeyPath path to a file that contains a Tor private key - * @param virtualPort port for the public hidden service (typically 9735) - * @param targets address of our protected server (format [host:]port), 127.0.0.1:[[virtualPort]] if empty - * @param onionAdded a Promise to track creation of the endpoint + * @param authentication + * Tor controller auth mechanism (password or safecookie) + * @param privateKeyPath + * path to a file that contains a Tor private key + * @param virtualPort + * port for the public hidden service (typically 9735) + * @param targets + * address of our protected server (format [host:]port), + * 127.0.0.1:[[virtualPort]] if empty + * @param onionAdded + * a Promise to track creation of the endpoint */ class TorProtocolHandler( authentication: Authentication, privateKeyPath: Path, virtualPort: Int, targets: Seq[String], - onionAdded: Option[Promise[InetSocketAddress]]) - extends Actor + onionAdded: Option[Promise[InetSocketAddress]] +) extends Actor with Stash with ActorLogging { @@ -56,14 +63,16 @@ class TorProtocolHandler( val methods: String = res.getOrElse("METHODS", throw TorException("auth methods not found")) val torVersion = unquote( - res.getOrElse("Tor", throw TorException("version not found"))) + res.getOrElse("Tor", throw TorException("version not found")) + ) log.info(s"Tor version $torVersion") if (!OnionServiceVersion.isCompatible(torVersion)) { throw TorException(s"Tor version $torVersion is not supported") } if (!Authentication.isCompatible(authentication, methods)) { throw TorException( - s"cannot use authentication '$authentication', supported methods are '$methods'") + s"cannot use authentication '$authentication', supported methods are '$methods'" + ) } authentication match { case Password(password) => @@ -72,8 +81,12 @@ class TorProtocolHandler( case SafeCookie(nonce) => val cookieFile = Paths.get( unquote( - res.getOrElse("COOKIEFILE", - throw TorException("cookie file not found")))) + res.getOrElse( + "COOKIEFILE", + throw TorException("cookie file not found") + ) + ) + ) sendCommand(s"AUTHCHALLENGE SAFECOOKIE ${nonce.toHex}") context.become(cookieChallenge(cookieFile, nonce)) } @@ -83,14 +96,22 @@ class TorProtocolHandler( case data: ByteString => val res = parseResponse(readResponse(data)) val clientHash = computeClientHash( - ByteVector.fromValidHex(res - .getOrElse("SERVERHASH", throw TorException("server hash not found")) - .toLowerCase), ByteVector.fromValidHex( res - .getOrElse("SERVERNONCE", - throw TorException("server nonce not found")) - .toLowerCase), + .getOrElse( + "SERVERHASH", + throw TorException("server hash not found") + ) + .toLowerCase + ), + ByteVector.fromValidHex( + res + .getOrElse( + "SERVERNONCE", + throw TorException("server nonce not found") + ) + .toLowerCase + ), clientNonce, cookieFile ) @@ -109,7 +130,8 @@ class TorProtocolHandler( if (ok(res)) { val serviceId = processOnionResponse(parseResponse(res)) address = Some( - InetSocketAddress.createUnresolved(s"$serviceId.onion", virtualPort)) + InetSocketAddress.createUnresolved(s"$serviceId.onion", virtualPort) + ) onionAdded.foreach(_.success(address.get)) log.debug("Onion address: {}", address.get) } @@ -160,7 +182,8 @@ class TorProtocolHandler( serverHash: ByteVector, serverNonce: ByteVector, clientNonce: ByteVector, - cookieFile: Path): ByteVector = { + cookieFile: Path + ): ByteVector = { if (serverHash.length != 32) throw TorException("invalid server hash length") if (serverNonce.length != 32) @@ -190,20 +213,26 @@ object TorProtocolHandler { privateKeyPath: Path, virtualPort: Int, targets: Seq[String] = Seq(), - onionAdded: Option[Promise[InetSocketAddress]] = None): Props = + onionAdded: Option[Promise[InetSocketAddress]] = None + ): Props = Props( - new TorProtocolHandler(authentication, - privateKeyPath, - virtualPort, - targets, - onionAdded)) + new TorProtocolHandler( + authentication, + privateKeyPath, + virtualPort, + targets, + onionAdded + ) + ) // those are defined in the spec private val ServerKey = ByteVector.view( - "Tor safe cookie authentication server-to-controller hash".getBytes()) + "Tor safe cookie authentication server-to-controller hash".getBytes() + ) private val ClientKey = ByteVector.view( - "Tor safe cookie authentication controller-to-server hash".getBytes()) + "Tor safe cookie authentication controller-to-server hash".getBytes() + ) object OnionServiceVersion { @@ -262,7 +291,8 @@ object TorProtocolHandler { try { Files.setPosixFilePermissions( path, - PosixFilePermissions.fromString(permissionString)) + PosixFilePermissions.fromString(permissionString) + ) () } catch { case _: UnsupportedOperationException => () // we are on windows @@ -285,12 +315,13 @@ object TorProtocolHandler { .map { case r1(c, msg) => (c.toInt, msg) case r2(c, msg) => (c.toInt, msg) - case x @ _ => throw TorException(s"unknown response line format: `$x`") + case x @ _ => throw TorException(s"unknown response line format: `$x`") } .toSeq if (!ok(lines)) { throw TorException( - s"server returned error: ${status(lines)} ${reason(lines)}") + s"server returned error: ${status(lines)} ${reason(lines)}" + ) } lines } diff --git a/tor/src/main/scala/org/bitcoins/tor/client/TorClient.scala b/tor/src/main/scala/org/bitcoins/tor/client/TorClient.scala index c5421ec411..ab8779fc22 100644 --- a/tor/src/main/scala/org/bitcoins/tor/client/TorClient.scala +++ b/tor/src/main/scala/org/bitcoins/tor/client/TorClient.scala @@ -16,15 +16,17 @@ import scala.util.{Failure, Success, Try} /** A trait that helps start bitcoind/eclair when it is started via bitcoin-s */ class TorClient()(implicit val executionContext: ExecutionContext, - conf: TorAppConfig) - extends NativeProcessFactory + conf: TorAppConfig +) extends NativeProcessFactory with BitcoinSLogger { lazy val socks5ProxyParams: Socks5ProxyParams = conf.socks5ProxyParams match { case Some(params) => params case None => - val addr = new InetSocketAddress(InetAddress.getLoopbackAddress, - Socks5ProxyParams.DefaultPort) + val addr = new InetSocketAddress( + InetAddress.getLoopbackAddress, + Socks5ProxyParams.DefaultPort + ) Socks5ProxyParams( address = addr, credentialsOpt = None, @@ -35,8 +37,10 @@ class TorClient()(implicit lazy val torParams: TorParams = conf.torParams match { case Some(params) => params case None => - val control = new InetSocketAddress(InetAddress.getLoopbackAddress, - TorParams.DefaultControlPort) + val control = new InetSocketAddress( + InetAddress.getLoopbackAddress, + TorParams.DefaultControlPort + ) val auth = SafeCookie() val privKeyPath = conf.datadir.resolve("tor_priv_key") @@ -88,10 +92,12 @@ object TorClient extends BitcoinSLogger { } } - /** Copies the tor executable and needed files to the given datadir - * Returns the tor executable file - * @param datadir Directory where to write files - * @return Tor executable file + /** Copies the tor executable and needed files to the given datadir Returns + * the tor executable file + * @param datadir + * Directory where to write files + * @return + * Tor executable file */ private def torBinaryFromResource(datadir: Path): File = { val torBundle = if (EnvUtil.isLinux) { @@ -106,11 +112,13 @@ object TorClient extends BitcoinSLogger { if (existsAndIsExecutable(datadir, torBundle)) { logger.info( - s"Using tor daemon already written to datadir=${datadir.toAbsolutePath}") + s"Using tor daemon already written to datadir=${datadir.toAbsolutePath}" + ) executableFileName } else { logger.info( - s"Tor executable is not written to datadir $datadir, creating...") + s"Tor executable is not written to datadir $datadir, creating..." + ) torBundle.allFilesNames.foreach { fileName => val writePath = datadir.resolve(fileName) @@ -124,13 +132,14 @@ object TorClient extends BitcoinSLogger { writeFileFromResource(fileName, writePath) } - //set files as executable + // set files as executable torBundle.executables.foreach { f => val executable = datadir.resolve(f) val isExecutable = executable.toFile.setExecutable(true) if (!isExecutable) { sys.error( - s"Could not make file=${executable.toAbsolutePath} executable") + s"Could not make file=${executable.toAbsolutePath} executable" + ) } } @@ -142,14 +151,16 @@ object TorClient extends BitcoinSLogger { Files.write(datadir.resolve(versionFileName), TOR_VERSION.getBytes) logger.info( - s"Using prepackaged Tor from bitcoin-s resources, $executableFileName") + s"Using prepackaged Tor from bitcoin-s resources, $executableFileName" + ) executableFileName } } private def writeFileFromResource( resourceName: String, - writePath: Path): Long = { + writePath: Path + ): Long = { val stream = Try(getClass.getResource("/" + resourceName).openStream()) match { case Failure(_) => throw new FileNotFoundException(resourceName) @@ -158,18 +169,23 @@ object TorClient extends BitcoinSLogger { Files.copy(stream, writePath, StandardCopyOption.REPLACE_EXISTING) } - /** The executables and lists of library files needed to run tor on a specific platform + /** The executables and lists of library files needed to run tor on a specific + * platform * - * @param executables the files that need to be set to executable - * @param fileList shared object files or library files for tor to operate + * @param executables + * the files that need to be set to executable + * @param fileList + * shared object files or library files for tor to operate */ private case class TorFileBundle( executables: Vector[String], - fileList: Vector[String]) { + fileList: Vector[String] + ) { val allFilesNames: Vector[String] = executables ++ fileList - /** By convention, make the primary executable the first element passed into executables - * This is needed because some platforms like osx require two tor executables (tor, tor.real) + /** By convention, make the primary executable the first element passed into + * executables This is needed because some platforms like osx require two + * tor executables (tor, tor.real) */ def primaryExecutable: String = executables.head } @@ -218,10 +234,13 @@ object TorClient extends BitcoinSLogger { ) } - /** Checks if the executable files exists in the given datadir and are executable */ + /** Checks if the executable files exists in the given datadir and are + * executable + */ private def existsAndIsExecutable( datadir: Path, - bundle: TorFileBundle): Boolean = { + bundle: TorFileBundle + ): Boolean = { val versionFile = datadir.resolve(versionFileName) diff --git a/tor/src/main/scala/org/bitcoins/tor/config/TorAppConfig.scala b/tor/src/main/scala/org/bitcoins/tor/config/TorAppConfig.scala index 2fe0200fb3..9155616302 100644 --- a/tor/src/main/scala/org/bitcoins/tor/config/TorAppConfig.scala +++ b/tor/src/main/scala/org/bitcoins/tor/config/TorAppConfig.scala @@ -18,13 +18,16 @@ import scala.concurrent.duration.DurationInt import scala.concurrent.{Await, ExecutionContext, Future} /** Configuration for the Bitcoin-S node - * @param directory The data directory of the node - * @param confs Optional sequence of configuration overrides + * @param directory + * The data directory of the node + * @param confs + * Optional sequence of configuration overrides */ case class TorAppConfig( baseDatadir: Path, private val subModuleNameOpt: Option[String], - configOverrides: Vector[Config])(implicit ec: ExecutionContext) + configOverrides: Vector[Config] +)(implicit ec: ExecutionContext) extends AppConfig with CallbackConfig[TorCallbacks] { @@ -32,7 +35,8 @@ case class TorAppConfig( override protected[bitcoins] type ConfigType = TorAppConfig override protected[bitcoins] def newConfigOfType( - configs: Vector[Config]): TorAppConfig = + configs: Vector[Config] + ): TorAppConfig = TorAppConfig(baseDatadir, subModuleNameOpt, configs) override lazy val callbackFactory: TorCallbacks.type = TorCallbacks @@ -52,13 +56,17 @@ case class TorAppConfig( lazy val socks5ProxyParams: Option[Socks5ProxyParams] = { if (getBoolean("proxy.enabled")) { val address = if (torProvided) { - NetworkUtil.parseInetSocketAddress(getString("proxy.socks5"), - TorParams.DefaultProxyPort) + NetworkUtil.parseInetSocketAddress( + getString("proxy.socks5"), + TorParams.DefaultProxyPort + ) } else { - new InetSocketAddress(InetAddress.getLoopbackAddress, - if (useRandomPorts) - TorAppConfig.randomSocks5Port - else TorParams.DefaultProxyPort) + new InetSocketAddress( + InetAddress.getLoopbackAddress, + if (useRandomPorts) + TorAppConfig.randomSocks5Port + else TorParams.DefaultProxyPort + ) } Some( Socks5ProxyParams( @@ -75,13 +83,17 @@ case class TorAppConfig( lazy val torParams: Option[TorParams] = { if (getBoolean("tor.enabled")) { val address = if (torProvided) { - NetworkUtil.parseInetSocketAddress(getString("tor.control"), - TorParams.DefaultControlPort) + NetworkUtil.parseInetSocketAddress( + getString("tor.control"), + TorParams.DefaultControlPort + ) } else { - new InetSocketAddress(InetAddress.getLoopbackAddress, - if (useRandomPorts) - TorAppConfig.randomControlPort - else TorParams.DefaultControlPort) + new InetSocketAddress( + InetAddress.getLoopbackAddress, + if (useRandomPorts) + TorAppConfig.randomControlPort + else TorParams.DefaultControlPort + ) } val auth = getStringOrNone("tor.password") match { @@ -109,8 +121,8 @@ case class TorAppConfig( new TorClient()(ec, this) } - /** Ensures correct tables and other required information is in - * place for our node. + /** Ensures correct tables and other required information is in place for our + * node. */ override def start(): Future[Unit] = { val f = if (torProvided) { @@ -122,9 +134,9 @@ case class TorAppConfig( isStarted.set(true) logger.info(s"Starting Tor daemon") val start = System.currentTimeMillis() - //remove old tor log file so we accurately tell when - //the binary is started, if we don't remove this - //we could have that log line appear from previous runs + // remove old tor log file so we accurately tell when + // the binary is started, if we don't remove this + // we could have that log line appear from previous runs if (torLogFile.toFile.exists()) { torLogFile.toFile.delete() } @@ -141,18 +153,21 @@ case class TorAppConfig( _ <- isBinaryFullyStarted() } yield { logger.info( - s"Tor daemon is fully started, it took=${System.currentTimeMillis() - start}ms") + s"Tor daemon is fully started, it took=${System.currentTimeMillis() - start}ms" + ) } } else if (isStarted.get) { logger.debug(s"Tor daemon already started") Future.unit } else if (torRunning) { logger.warn( - s"Tor daemon was requested to start, but it is already running. Not starting tor") + s"Tor daemon was requested to start, but it is already running. Not starting tor" + ) Future.unit } else { logger.warn( - s"Tor daemon was requested to start, but it is disabled in the configuration file. Not starting tor") + s"Tor daemon was requested to start, but it is disabled in the configuration file. Not starting tor" + ) Future.unit } } @@ -169,22 +184,23 @@ case class TorAppConfig( } } - /** Checks if the tor binary is started by looking for a log in the [[torLogFile]] - * The log line we are looking or is + /** Checks if the tor binary is started by looking for a log in the + * [[torLogFile]] The log line we are looking or is * {{{ * Bootstrapped 100% (done): Done - * }}} + * }}} */ private def isBinaryFullyStarted(): Future[Unit] = { - //tor can take at least 25 seconds to start at times - //see: https://github.com/bitcoin-s/bitcoin-s/pull/3558#issuecomment-899819698 + // tor can take at least 25 seconds to start at times + // see: https://github.com/bitcoin-s/bitcoin-s/pull/3558#issuecomment-899819698 AsyncUtil .retryUntilSatisfied(checkIfLogExists, 1.second, 120) - //execute started callbacks + // execute started callbacks .flatMap(_ => callBacks.executeOnTorStarted()) .recover { case _: AsyncUtil.RpcRetryException => throw new RuntimeException( - s"Could not start tor, please try again in a few minutes") + s"Could not start tor, please try again in a few minutes" + ) } } @@ -209,8 +225,10 @@ case class TorAppConfig( torParams match { case Some(params) => params.controlAddress case None => - new InetSocketAddress(InetAddress.getLoopbackAddress, - TorParams.DefaultProxyPort) + new InetSocketAddress( + InetAddress.getLoopbackAddress, + TorParams.DefaultProxyPort + ) } } @@ -254,11 +272,12 @@ object TorAppConfig extends AppConfigFactory[TorAppConfig] { override val moduleName: String = "tor" - /** Constructs a tor configuration from the default Bitcoin-S - * data directory and given list of configuration overrides. + /** Constructs a tor configuration from the default Bitcoin-S data directory + * and given list of configuration overrides. */ override def fromDatadir(datadir: Path, confs: Vector[Config])(implicit - ec: ExecutionContext): TorAppConfig = + ec: ExecutionContext + ): TorAppConfig = TorAppConfig(datadir, None, confs) lazy val randomSocks5Port: Int = ports.proxyPort diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/AddressHandlingTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/AddressHandlingTest.scala index 265a18989b..be6665af74 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/AddressHandlingTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/AddressHandlingTest.scala @@ -50,11 +50,14 @@ class AddressHandlingTest extends BitcoinSWalletTest { } yield { assert(listAddressesForAcct.nonEmpty) assert(listAddressesForAcct.map(_.address).contains(address)) - assert(exists, - s"Wallet must contain address in specific after generating it") + assert( + exists, + s"Wallet must contain address in specific after generating it" + ) assert( doesNotExist, - s"Wallet must NOT contain address in default account when address is specified") + s"Wallet must NOT contain address in default account when address is specified" + ) } } @@ -87,8 +90,10 @@ class AddressHandlingTest extends BitcoinSWalletTest { addresses <- addressesF } yield { assert(addresses.size == 10) - assert(addresses.distinct.length == addresses.length, - s"We receive an identical address!") + assert( + addresses.distinct.length == addresses.length, + s"We receive an identical address!" + ) } } @@ -100,7 +105,8 @@ class AddressHandlingTest extends BitcoinSWalletTest { emptySpentAddresses <- wallet.listSpentAddresses() _ = assert( emptySpentAddresses.isEmpty, - s"Wallet did not start with empty spent addresses, got $emptySpentAddresses") + s"Wallet did not start with empty spent addresses, got $emptySpentAddresses" + ) tempAddress <- wallet.getNewAddress() tx <- wallet.sendToAddress(tempAddress, Bitcoins(1), None) @@ -123,8 +129,10 @@ class AddressHandlingTest extends BitcoinSWalletTest { } yield { val diff = unspentDbs .map(_.output) - .diff(fundedAddresses.map(tuple => - TransactionOutput(tuple._2, tuple._1.scriptPubKey))) + .diff( + fundedAddresses.map(tuple => + TransactionOutput(tuple._2, tuple._1.scriptPubKey)) + ) assert(diff.isEmpty, s"Extra funded addresses $diff") } } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/AddressLabelTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/AddressLabelTest.scala index 9b872ca1ed..f54f723d2a 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/AddressLabelTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/AddressLabelTest.scala @@ -22,7 +22,7 @@ class AddressLabelTest extends BitcoinSWalletTest { val tag2 = UnknownAddressTag("test_tag_name_2", "test_tag_type_2") val addressF = for { address <- wallet.getNewAddress(Vector(tag1)) - //add another tag to address + // add another tag to address tagDb1 <- wallet.getAddressTags(address) tagDb2 <- wallet.tagAddress(address, tag2) } yield { @@ -39,13 +39,17 @@ class AddressLabelTest extends BitcoinSWalletTest { it must "fail if we tag the address with the same tag twice" in { fundedWallet => val wallet = fundedWallet.wallet - val tag1 = UnknownAddressTag(tagName = "test_tag_name_1", - tagType = "test_tag_type_1") - val tag2 = UnknownAddressTag(tagName = "test_tag_name_1", - tagType = "test_tag_type_2") + val tag1 = UnknownAddressTag( + tagName = "test_tag_name_1", + tagType = "test_tag_type_1" + ) + val tag2 = UnknownAddressTag( + tagName = "test_tag_name_1", + tagType = "test_tag_type_2" + ) val resultF = for { address <- wallet.getNewAddress() - //add another tag to address + // add another tag to address _ <- wallet.tagAddress(address, tag1) _ <- wallet.tagAddress(address, tag2) } yield () diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/AddressTagIntegrationTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/AddressTagIntegrationTest.scala index d470b127f9..919178004a 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/AddressTagIntegrationTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/AddressTagIntegrationTest.scala @@ -43,7 +43,8 @@ class AddressTagIntegrationTest extends BitcoinSWalletTest { addr <- wallet.getNewAddress() taggedAddr <- wallet.getNewAddress(Vector(exampleTag)) txId <- bitcoind.sendMany( - Map(addr -> valueFromBitcoind, taggedAddr -> valueFromBitcoind)) + Map(addr -> valueFromBitcoind, taggedAddr -> valueFromBitcoind) + ) tx <- bitcoind.getRawTransactionRaw(txId) // before processing TX, wallet should be completely empty @@ -84,10 +85,12 @@ class AddressTagIntegrationTest extends BitcoinSWalletTest { rawTxHelper <- bitcoind.getNewAddress.flatMap { addr => val output = TransactionOutput(valueToBitcoind, addr.scriptPubKey) wallet - .fundRawTransaction(destinations = Vector(output), - feeRate = feeRate, - fromTagOpt = Some(exampleTag), - markAsReserved = true) + .fundRawTransaction( + destinations = Vector(output), + feeRate = feeRate, + fromTagOpt = Some(exampleTag), + markAsReserved = true + ) } signedTx = rawTxHelper.signedTx _ <- wallet.processTransaction(signedTx, None) @@ -99,7 +102,8 @@ class AddressTagIntegrationTest extends BitcoinSWalletTest { // One change one external assert(utxos.size == 2) assert( - utxos.exists(_.privKeyPath.chain.chainType == HDChainType.External)) + utxos.exists(_.privKeyPath.chain.chainType == HDChainType.External) + ) assert(utxos.exists(_.privKeyPath.chain.chainType == HDChainType.Change)) // untagged balance should be untouched @@ -112,15 +116,18 @@ class AddressTagIntegrationTest extends BitcoinSWalletTest { val feePaid = utxoInfos.map(_.output.value).sum - signedTx.outputs.map(_.value).sum assert( - WalletTestUtil.isCloseEnough(tagBalancePostSend, - valueFromBitcoind - valueToBitcoind, - delta = feePaid)) + WalletTestUtil.isCloseEnough( + tagBalancePostSend, + valueFromBitcoind - valueToBitcoind, + delta = feePaid + ) + ) } } it must "process a tagged tx correctly when we broadcast it and receive it in a block" in { walletWithBitcoind => - //see: https://github.com/bitcoin-s/bitcoin-s/issues/4238 + // see: https://github.com/bitcoin-s/bitcoin-s/issues/4238 val WalletWithBitcoindRpc(wallet, bitcoind, _) = walletWithBitcoind val bitcoindAddrF = bitcoind.getNewAddress @@ -132,10 +139,12 @@ class AddressTagIntegrationTest extends BitcoinSWalletTest { tx <- bitcoind.getRawTransaction(txid) _ <- wallet.processTransaction(tx.hex, None) taggedAddress <- taggedAddrF - tx <- wallet.sendToAddress(taggedAddress, - Satoshis(100000), - SatoshisPerVirtualByte.one, - Vector(exampleTag)) + tx <- wallet.sendToAddress( + taggedAddress, + Satoshis(100000), + SatoshisPerVirtualByte.one, + Vector(exampleTag) + ) _ <- wallet.processTransaction(tx, None) _ <- bitcoind.sendRawTransaction(tx) bitcoindAddr <- bitcoindAddrF diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindBackendTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindBackendTest.scala index 64437b3434..ec5fea5fe0 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindBackendTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindBackendTest.scala @@ -53,9 +53,11 @@ class BitcoindBackendTest extends WalletAppConfigWithBitcoindNewestFixtures { syncing <- bitcoind.isSyncing() _ = assert(!syncing) - _ <- BitcoindRpcBackendUtil.syncWalletToBitcoind(bitcoind, - wallet, - Some(callbacks)) + _ <- BitcoindRpcBackendUtil.syncWalletToBitcoind( + bitcoind, + wallet, + Some(callbacks) + ) _ <- AsyncUtil.awaitConditionF { () => bitcoind.isSyncing().map(!_) } balance <- wallet.getBalance() @@ -90,16 +92,20 @@ class BitcoindBackendTest extends WalletAppConfigWithBitcoindNewestFixtures { addr <- wallet.getNewAddress() _ <- bitcoind.sendToAddress(addr, amountToSend) bitcoindAddr <- bitcoind.getNewAddress - _ <- bitcoind.generateToAddress(wallet.walletConfig.requiredConfirmations, - bitcoindAddr) + _ <- bitcoind.generateToAddress( + wallet.walletConfig.requiredConfirmations, + bitcoindAddr + ) // assert wallet hasn't seen it yet firstBalance <- wallet.getBalance() _ = assert(firstBalance == Satoshis.zero) // Set sync height - _ <- wallet.stateDescriptorDAO.updateSyncHeight(header.hashBE, - header.height) + _ <- wallet.stateDescriptorDAO.updateSyncHeight( + header.hashBE, + header.height + ) _ <- BitcoindRpcBackendUtil.syncWalletToBitcoind(bitcoind, wallet, None) @@ -185,7 +191,8 @@ class BitcoindBackendTest extends WalletAppConfigWithBitcoindNewestFixtures { // confirm utxos _ <- bitcoind.generateToAddress( wallet.walletConfig.requiredConfirmations, - bitcoindAddr) + bitcoindAddr + ) // sync wallet _ <- BitcoindRpcBackendUtil.syncWalletToBitcoind(bitcoind, wallet, None) @@ -199,18 +206,22 @@ class BitcoindBackendTest extends WalletAppConfigWithBitcoindNewestFixtures { } private def createWallet( - params: WalletAppConfigWithBitcoindRpc): Future[Wallet] = { + params: WalletAppConfigWithBitcoindRpc + ): Future[Wallet] = { val bitcoind = params.bitcoind implicit val walletAppConfig: WalletAppConfig = params.walletAppConfig for { - tmpWallet <- BitcoinSWalletTest.createDefaultWallet(nodeApi = bitcoind, - chainQueryApi = - bitcoind) + tmpWallet <- BitcoinSWalletTest.createDefaultWallet( + nodeApi = bitcoind, + chainQueryApi = bitcoind + ) } yield { - BitcoindRpcBackendUtil.createWalletWithBitcoindCallbacks(bitcoind, - tmpWallet, - None) + BitcoindRpcBackendUtil.createWalletWithBitcoindCallbacks( + bitcoind, + tmpWallet, + None + ) } } } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindBlockPollingTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindBlockPollingTest.scala index dd88025734..68a25d262c 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindBlockPollingTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindBlockPollingTest.scala @@ -29,9 +29,11 @@ class BitcoindBlockPollingTest tmpWallet <- BitcoinSWalletTest.createDefaultWallet(bitcoind, bitcoind) wallet = - BitcoindRpcBackendUtil.createWalletWithBitcoindCallbacks(bitcoind, - tmpWallet, - None) + BitcoindRpcBackendUtil.createWalletWithBitcoindCallbacks( + bitcoind, + tmpWallet, + None + ) // Assert wallet is empty isEmpty <- wallet.isEmpty() _ = assert(isEmpty) @@ -45,16 +47,19 @@ class BitcoindBlockPollingTest _ = assert(firstBalance == Satoshis.zero) // Setup block polling - cancellable = BitcoindRpcBackendUtil.startBitcoindBlockPolling(wallet, - bitcoind, - None, - 1.second) + cancellable = BitcoindRpcBackendUtil.startBitcoindBlockPolling( + wallet, + bitcoind, + None, + 1.second + ) _ <- bitcoind.generateToAddress(6, bech32Address) // Wait for it to process _ <- AsyncUtil.awaitConditionF( () => wallet.getBalance().map(_ > Satoshis.zero), - 1.second) + 1.second + ) balance <- wallet.getConfirmedBalance() _ = cancellable.cancel() @@ -75,9 +80,11 @@ class BitcoindBlockPollingTest tmpWallet <- BitcoinSWalletTest.createDefaultWallet(bitcoind, bitcoind) wallet = - BitcoindRpcBackendUtil.createWalletWithBitcoindCallbacks(bitcoind, - tmpWallet, - None) + BitcoindRpcBackendUtil.createWalletWithBitcoindCallbacks( + bitcoind, + tmpWallet, + None + ) // populate initial mempool addr <- wallet.getNewAddress() @@ -87,7 +94,8 @@ class BitcoindBlockPollingTest cancellable = BitcoindRpcBackendUtil.startBitcoindMempoolPolling( wallet, bitcoind, - 1.second) { tx => + 1.second + ) { tx => mempoolTxs += tx FutureUtil.unit } @@ -100,9 +108,11 @@ class BitcoindBlockPollingTest _ <- AsyncUtil.awaitCondition( () => { mempoolTxs.exists(_.txIdBE == txid1) && mempoolTxs.exists( - _.txIdBE == txid2) + _.txIdBE == txid2 + ) }, - 1.second) + 1.second + ) _ = cancellable.cancel() } yield succeed } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindZMQBackendTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindZMQBackendTest.scala index 483883bbc0..89f1083172 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindZMQBackendTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/BitcoindZMQBackendTest.scala @@ -28,7 +28,8 @@ class BitcoindZMQBackendTest extends WalletAppConfigWithBitcoindNewestFixtures { _ <- TestAsyncUtil.awaitConditionF( () => wallet.getUnconfirmedBalance().map(_ > Satoshis.zero), interval = 1.second, - maxTries = 120) + maxTries = 120 + ) } yield () } @@ -39,7 +40,8 @@ class BitcoindZMQBackendTest extends WalletAppConfigWithBitcoindNewestFixtures { _ <- TestAsyncUtil.awaitConditionF( () => wallet.getConfirmedBalance().map(_ > Satoshis.zero), interval = 1.second, - maxTries = 120) + maxTries = 120 + ) } yield () } @@ -51,7 +53,8 @@ class BitcoindZMQBackendTest extends WalletAppConfigWithBitcoindNewestFixtures { BitcoindRpcBackendUtil.createWalletWithBitcoindCallbacks( bitcoind = bitcoind, wallet = tmpWallet, - chainCallbacksOpt = None) + chainCallbacksOpt = None + ) // Assert wallet is empty isEmpty <- wallet.isEmpty() _ = assert(isEmpty) @@ -64,7 +67,8 @@ class BitcoindZMQBackendTest extends WalletAppConfigWithBitcoindNewestFixtures { // Setup zmq subscribers zmqSubs = BitcoindRpcBackendUtil.startZMQWalletCallbacks( wallet, - bitcoind.instance.zmqConfig) + bitcoind.instance.zmqConfig + ) _ <- AsyncUtil.nonBlockingSleep(5.seconds) _ <- attemptZMQTx(addr, wallet) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/CoinSelectorTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/CoinSelectorTest.scala index 86f68a3ea0..527530bd34 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/CoinSelectorTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/CoinSelectorTest.scala @@ -17,7 +17,8 @@ class CoinSelectorTest extends BitcoinSWalletTest { feeRate: FeeUnit, utxo1: CoinSelectorUtxo, utxo2: CoinSelectorUtxo, - utxo3: CoinSelectorUtxo) { + utxo3: CoinSelectorUtxo + ) { val utxoSet: Vector[CoinSelectorUtxo] = Vector(utxo1, utxo2, utxo3) @@ -59,39 +60,50 @@ class CoinSelectorTest extends BitcoinSWalletTest { it must "accumulate largest outputs" in { fixture => val selection = - CoinSelector.accumulateLargest(walletUtxos = fixture.utxoSet, - outputs = Vector(fixture.output), - feeRate = fixture.feeRate) + CoinSelector.accumulateLargest( + walletUtxos = fixture.utxoSet, + outputs = Vector(fixture.output), + feeRate = fixture.feeRate + ) assert(selection == Vector(fixture.utxo2, fixture.utxo3)) } it must "accumulate smallest outputs" in { fixture => val selection = - CoinSelector.accumulateSmallestViable(walletUtxos = fixture.utxoSet, - outputs = Vector(fixture.output), - feeRate = fixture.feeRate) + CoinSelector.accumulateSmallestViable( + walletUtxos = fixture.utxoSet, + outputs = Vector(fixture.output), + feeRate = fixture.feeRate + ) assert(selection == Vector(fixture.utxo1, fixture.utxo3, fixture.utxo2)) } it must "accumulate outputs in order" in { fixture => - val selection = CoinSelector.accumulate(walletUtxos = fixture.utxoSet, - outputs = Vector(fixture.output), - feeRate = fixture.feeRate) + val selection = CoinSelector.accumulate( + walletUtxos = fixture.utxoSet, + outputs = Vector(fixture.output), + feeRate = fixture.feeRate + ) assert(selection == Vector(fixture.utxo1, fixture.utxo2)) } it must "accumulate random outputs" in { fixture => - val first = CoinSelector.randomSelection(walletUtxos = fixture.utxoSet, - outputs = Vector(fixture.output), - feeRate = fixture.feeRate) + val first = CoinSelector.randomSelection( + walletUtxos = fixture.utxoSet, + outputs = Vector(fixture.output), + feeRate = fixture.feeRate + ) val selections = Vector.fill(20)( - CoinSelector.randomSelection(walletUtxos = fixture.utxoSet, - outputs = Vector(fixture.output), - feeRate = fixture.feeRate)) + CoinSelector.randomSelection( + walletUtxos = fixture.utxoSet, + outputs = Vector(fixture.output), + feeRate = fixture.feeRate + ) + ) // it should not get the same thing every time assert(selections.exists(_ != first)) @@ -99,11 +111,12 @@ class CoinSelectorTest extends BitcoinSWalletTest { it must "select the least wasteful outputs" in { fixture => val selection = - CoinSelector.selectByLeastWaste(walletUtxos = fixture.utxoSet, - outputs = Vector(fixture.output), - feeRate = fixture.feeRate, - longTermFeeRate = - SatoshisPerByte.fromLong(10)) + CoinSelector.selectByLeastWaste( + walletUtxos = fixture.utxoSet, + outputs = Vector(fixture.output), + feeRate = fixture.feeRate, + longTermFeeRate = SatoshisPerByte.fromLong(10) + ) // Need to sort as ordering will be different sometimes val sortedSelection = selection.sortBy(_.outPoint.hex) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/ComputeContractIdTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/ComputeContractIdTest.scala index 1ae833f6ca..25ace32b4b 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/ComputeContractIdTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/ComputeContractIdTest.scala @@ -28,7 +28,8 @@ class ComputeContractIdTest extends BitcoinSWalletTest with EmptyFixture { fundTxId: DoubleSha256DigestBE, fundOutputIndex: Int, temporaryContractId: Sha256Digest, - contractId: ByteVector) + contractId: ByteVector + ) object ContractIdTestVector { @@ -48,7 +49,9 @@ class ComputeContractIdTest extends BitcoinSWalletTest with EmptyFixture { DLCUtil.computeContractId( testVector.fundTxId, testVector.fundOutputIndex, - testVector.temporaryContractId) == testVector.contractId) + testVector.temporaryContractId + ) == testVector.contractId + ) } succeed diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/FundTransactionHandlingTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/FundTransactionHandlingTest.scala index 0c4b881aba..eb756ce045 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/FundTransactionHandlingTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/FundTransactionHandlingTest.scala @@ -24,7 +24,8 @@ class FundTransactionHandlingTest val f: Future[Outcome] = for { bitcoind <- cachedBitcoindWithFundsF futOutcome = withFundedWalletAndBitcoindCached(test, bitcoind)( - getFreshWalletAppConfig) + getFreshWalletAppConfig + ) fut <- futOutcome.toFuture } yield fut new FutureOutcome(f) @@ -38,18 +39,23 @@ class FundTransactionHandlingTest val wallet = fundedWallet.wallet for { feeRate <- wallet.getFeeRate() - fundRawTxHelper <- wallet.fundRawTransaction(destinations = - Vector(destination), - feeRate = feeRate, - fromTagOpt = None, - markAsReserved = false) + fundRawTxHelper <- wallet.fundRawTransaction( + destinations = Vector(destination), + feeRate = feeRate, + fromTagOpt = None, + markAsReserved = false + ) } yield { val fundedTx = fundRawTxHelper.unsignedTx - assert(fundedTx.inputs.length == 1, - s"We should only need one input to fund this tx") + assert( + fundedTx.inputs.length == 1, + s"We should only need one input to fund this tx" + ) assert(fundedTx.outputs.contains(destination)) - assert(fundedTx.outputs.length == 2, - s"We must have a single destination output and a change output") + assert( + fundedTx.outputs.length == 2, + s"We must have a single destination output and a change output" + ) } } @@ -60,18 +66,23 @@ class FundTransactionHandlingTest val wallet = fundedWallet.wallet for { feeRate <- wallet.getFeeRate() - fundRawTxHelper <- wallet.fundRawTransaction(destinations = - Vector(newDestination), - feeRate = feeRate, - fromTagOpt = None, - markAsReserved = false) + fundRawTxHelper <- wallet.fundRawTransaction( + destinations = Vector(newDestination), + feeRate = feeRate, + fromTagOpt = None, + markAsReserved = false + ) } yield { val fundedTx = fundRawTxHelper.unsignedTx - assert(fundedTx.inputs.length == 3, - s"We should need 3 inputs to fund this tx") + assert( + fundedTx.inputs.length == 3, + s"We should need 3 inputs to fund this tx" + ) assert(fundedTx.outputs.contains(newDestination)) - assert(fundedTx.outputs.length == 2, - s"We must have a 2 destination output and a change output") + assert( + fundedTx.outputs.length == 2, + s"We must have a 2 destination output and a change output" + ) } } @@ -82,38 +93,44 @@ class FundTransactionHandlingTest for { feeRate <- wallet.getFeeRate() - fundRawTxHelper <- wallet.fundRawTransaction(destinations = - destinations, - feeRate = feeRate, - fromTagOpt = None, - markAsReserved = false) + fundRawTxHelper <- wallet.fundRawTransaction( + destinations = destinations, + feeRate = feeRate, + fromTagOpt = None, + markAsReserved = false + ) } yield { val fundedTx = fundRawTxHelper.unsignedTx // Can be different depending on waste calculation - assert(fundedTx.inputs.length == 1 || fundedTx.inputs.length == 2, - s"We should only need one or two inputs to fund this tx") + assert( + fundedTx.inputs.length == 1 || fundedTx.inputs.length == 2, + s"We should only need one or two inputs to fund this tx" + ) destinations.foreach(d => assert(fundedTx.outputs.contains(d))) - assert(fundedTx.outputs.length == 6, - s"We must have a 6 destination output and a change output") + assert( + fundedTx.outputs.length == 6, + s"We must have a 6 destination output and a change output" + ) } } it must "fail to fund a raw transaction if we don't have enough money in our wallet" in { fundedWallet: WalletWithBitcoindRpc => - //our wallet should only have 6 bitcoin in it + // our wallet should only have 6 bitcoin in it val tooMuchMoney = Bitcoins(10) val tooBigOutput = destination.copy(value = tooMuchMoney) val wallet = fundedWallet.wallet val fundedTxF = for { feeRate <- wallet.getFeeRate() - fundedTx <- wallet.fundRawTransaction(destinations = - Vector(tooBigOutput), - feeRate = feeRate, - fromTagOpt = None, - markAsReserved = false) + fundedTx <- wallet.fundRawTransaction( + destinations = Vector(tooBigOutput), + feeRate = feeRate, + fromTagOpt = None, + markAsReserved = false + ) } yield fundedTx recoverToSucceededIf[RuntimeException] { @@ -123,18 +140,19 @@ class FundTransactionHandlingTest it must "fail to fund a raw transaction if we have the _exact_ amount of money in the wallet because of the fee" in { fundedWallet: WalletWithBitcoindRpc => - //our wallet should only have 6 bitcoin in it + // our wallet should only have 6 bitcoin in it val tooMuchMoney = Bitcoins(6) val tooBigOutput = destination.copy(value = tooMuchMoney) val wallet = fundedWallet.wallet val fundedTxF = for { feeRate <- wallet.getFeeRate() - fundedTx <- wallet.fundRawTransaction(destinations = - Vector(tooBigOutput), - feeRate = feeRate, - fromTagOpt = None, - markAsReserved = false) + fundedTx <- wallet.fundRawTransaction( + destinations = Vector(tooBigOutput), + feeRate = feeRate, + fromTagOpt = None, + markAsReserved = false + ) } yield fundedTx recoverToSucceededIf[RuntimeException] { @@ -144,8 +162,8 @@ class FundTransactionHandlingTest it must "fund from a specific account" in { fundedWallet: WalletWithBitcoindRpc => - //we want to fund from account 1, not hte default account - //account 1 has 1 btc in it + // we want to fund from account 1, not hte default account + // account 1 has 1 btc in it val amt = Bitcoins(0.1) val newDestination = destination.copy(value = amt) val wallet = fundedWallet.wallet @@ -155,10 +173,12 @@ class FundTransactionHandlingTest for { feeRate <- wallet.getFeeRate() account1DbOpt <- account1DbF - fundRawTxHelper <- wallet.fundRawTransaction(Vector(newDestination), - feeRate, - account1DbOpt.get, - markAsReserved = true) + fundRawTxHelper <- wallet.fundRawTransaction( + Vector(newDestination), + feeRate, + account1DbOpt.get, + markAsReserved = true + ) } yield { val fundedTx = fundRawTxHelper.unsignedTx assert(fundedTx.inputs.nonEmpty) @@ -169,7 +189,7 @@ class FundTransactionHandlingTest it must "fail to fund from an account that does not have the funds" in { fundedWallet: WalletWithBitcoindRpc => - //account 1 should only have 1 btc in it + // account 1 should only have 1 btc in it val amt = Bitcoins(1.1) val newDestination = destination.copy(value = amt) val wallet = fundedWallet.wallet @@ -179,11 +199,12 @@ class FundTransactionHandlingTest val fundedTxF = for { feeRate <- wallet.getFeeRate() account1DbOpt <- account1DbF - fundedTx <- wallet.fundRawTransaction(destinations = - Vector(newDestination), - feeRate = feeRate, - fromAccount = account1DbOpt.get, - markAsReserved = true) + fundedTx <- wallet.fundRawTransaction( + destinations = Vector(newDestination), + feeRate = feeRate, + fromAccount = account1DbOpt.get, + markAsReserved = true + ) } yield fundedTx recoverToSucceededIf[RuntimeException] { @@ -211,10 +232,12 @@ class FundTransactionHandlingTest _ = assert(utxos.size == 1) fundedTx <- - wallet.fundRawTransaction(destinations = Vector(destination), - feeRate = feeRate, - fromAccount = account2, - markAsReserved = true) + wallet.fundRawTransaction( + destinations = Vector(destination), + feeRate = feeRate, + fromAccount = account2, + markAsReserved = true + ) } yield fundedTx recoverToSucceededIf[RuntimeException] { @@ -227,14 +250,16 @@ class FundTransactionHandlingTest val wallet = fundedWallet.wallet for { feeRate <- wallet.getFeeRate() - fundRawTxHelper <- wallet.fundRawTransaction(destinations = - Vector(destination), - feeRate = feeRate, - fromTagOpt = None, - markAsReserved = true) + fundRawTxHelper <- wallet.fundRawTransaction( + destinations = Vector(destination), + feeRate = feeRate, + fromTagOpt = None, + markAsReserved = true + ) spendingInfos <- wallet.findOutputsBeingSpent( - fundRawTxHelper.unsignedTx) + fundRawTxHelper.unsignedTx + ) reserved <- wallet.listUtxos(TxoState.Reserved) } yield { assert(spendingInfos.exists(_.state == TxoState.Reserved)) @@ -244,7 +269,8 @@ class FundTransactionHandlingTest def testAddressTagFunding( wallet: HDWalletApi, - tag: AddressTag): Future[Assertion] = { + tag: AddressTag + ): Future[Assertion] = { for { account <- wallet.getDefaultAccount() feeRate <- wallet.getFeeRate() @@ -266,8 +292,10 @@ class FundTransactionHandlingTest } yield { val tx = fundRawTxHelper.signedTx - assert(tx.inputs.forall(input => - expectedUtxos.exists(_.outPoint == input.previousOutput))) + assert( + tx.inputs.forall(input => + expectedUtxos.exists(_.outPoint == input.previousOutput)) + ) } } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/MultiWalletTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/MultiWalletTest.scala index b3af43f984..1f0e6716c4 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/MultiWalletTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/MultiWalletTest.scala @@ -31,11 +31,13 @@ class MultiWalletTest extends BitcoinSAsyncTest with EmbeddedPg { val walletAF = BitcoinSWalletTest.createDefaultWallet(MockNodeApi, MockChainQueryApi)( - configA.walletConf) + configA.walletConf + ) val walletBF = BitcoinSWalletTest.createDefaultWallet(MockNodeApi, MockChainQueryApi)( - configB.walletConf) + configB.walletConf + ) val assertionF: Future[Assertion] = for { walletA <- walletAF diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessBlockTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessBlockTest.scala index cebfb44c90..00f66688de 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessBlockTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessBlockTest.scala @@ -27,7 +27,8 @@ class ProcessBlockTest extends BitcoinSWalletTestCachedBitcoindNewest { val f: Future[Outcome] = for { bitcoind <- cachedBitcoindWithFundsF futOutcome = withNewWalletAndBitcoindCached(test, bitcoind)( - getFreshWalletAppConfig) + getFreshWalletAppConfig + ) fut <- futOutcome.toFuture } yield fut new FutureOutcome(f) @@ -91,7 +92,7 @@ class ProcessBlockTest extends BitcoinSWalletTestCachedBitcoindNewest { // note: 100 because the very first coinbase utxo is now confirmed assert(coinbaseUtxos.size == 100) - //block reward is still 50 bitcoin per block + // block reward is still 50 bitcoin per block assert(balance == Bitcoins(50)) assert(confirmedUtxos.length == 1) } @@ -109,7 +110,8 @@ class ProcessBlockTest extends BitcoinSWalletTestCachedBitcoindNewest { addr <- wallet.getNewAddress() hashes <- bitcoind.generateToAddress(102, addr) filters <- FutureUtil.sequentially(hashes)( - bitcoind.getBlockFilter(_, FilterType.Basic)) + bitcoind.getBlockFilter(_, FilterType.Basic) + ) filtersWithBlockHash = hashes.zip(filters.map(_.filter)) _ <- wallet.processCompactFilters(filtersWithBlockHash) coinbaseUtxos <- wallet.listUtxos(TxoState.ImmatureCoinbase) @@ -127,9 +129,9 @@ class ProcessBlockTest extends BitcoinSWalletTestCachedBitcoindNewest { // note: 100 because the very first coinbase utxo is now confirmed assert(coinbaseUtxos.size == 100) - //note: This is 50 bitcoins because the block reward on regtest - //is now 25 bitcoin per block due to blocks being mined - //in prior test cases in this test suite. + // note: This is 50 bitcoins because the block reward on regtest + // is now 25 bitcoin per block due to blocks being mined + // in prior test cases in this test suite. assert(balance == Bitcoins(50)) assert(confirmedUtxos.length == 2) } @@ -162,19 +164,25 @@ class ProcessBlockTest extends BitcoinSWalletTestCachedBitcoindNewest { ._2 input = - TransactionInput(TransactionOutPoint(recvTx.txId, UInt32(index)), - EmptyScriptSignature, - UInt32.max) + TransactionInput( + TransactionOutPoint(recvTx.txId, UInt32(index)), + EmptyScriptSignature, + UInt32.max + ) output0 = - TransactionOutput(recvAmount - sendAmount - Satoshis(500), - changeAddr.scriptPubKey) + TransactionOutput( + recvAmount - sendAmount - Satoshis(500), + changeAddr.scriptPubKey + ) output1 = TransactionOutput(sendAmount, bitcoindAddr.scriptPubKey) - unsignedTx = BaseTransaction(Int32.two, - Vector(input), - Vector(output0, output1), - UInt32.zero) + unsignedTx = BaseTransaction( + Int32.two, + Vector(input), + Vector(output0, output1), + UInt32.zero + ) addrDb <- wallet.getAddressInfo(recvAddr).map(_.get) path = addrDb.path @@ -183,10 +191,12 @@ class ProcessBlockTest extends BitcoinSWalletTestCachedBitcoindNewest { .read((coin, path.accountIdx)) .map(_.get) - bip32Path = LegacyHDPath(path.coinType, - path.accountIdx, - path.chainType, - path.address.index) + bip32Path = LegacyHDPath( + path.coinType, + path.accountIdx, + path.chainType, + path.address.index + ) psbt = PSBT .fromUnsignedTx(unsignedTx) @@ -195,7 +205,8 @@ class ProcessBlockTest extends BitcoinSWalletTestCachedBitcoindNewest { signed <- wallet.signPSBT(psbt) tx <- Future.fromTry( - signed.finalizePSBT.flatMap(_.extractTransactionAndValidate)) + signed.finalizePSBT.flatMap(_.extractTransactionAndValidate) + ) _ <- bitcoind.sendRawTransaction(tx) hash <- bitcoind.generateToAddress(1, bitcoindAddr).map(_.head) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessTransactionTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessTransactionTest.scala index 00fc91c059..9f2a0ba269 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessTransactionTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/ProcessTransactionTest.scala @@ -29,8 +29,9 @@ class ProcessTransactionTest extends BitcoinSWalletTest { behavior of "Wallet.processTransaction" /** Verifies that executing the given action doesn't change wallet state */ - private def checkUtxosAndBalance(wallet: WalletApi)( - action: => Future[_]): Future[Assertion] = + private def checkUtxosAndBalance( + wallet: WalletApi + )(action: => Future[_]): Future[Assertion] = for { oldTransactions <- wallet.listTransactions() oldUtxos <- wallet.listUtxos() @@ -72,8 +73,10 @@ class ProcessTransactionTest extends BitcoinSWalletTest { wallet.processTransaction(tx, None) } - _ <- wallet.processTransaction(tx, - Some(MockChainQueryApi.testBlockHash)) + _ <- wallet.processTransaction( + tx, + Some(MockChainQueryApi.testBlockHash) + ) newConfirmed <- wallet.getConfirmedBalance() newUnconfirmed <- wallet.getUnconfirmedBalance() utxosPostAdd <- wallet.listUtxos() @@ -152,21 +155,22 @@ class ProcessTransactionTest extends BitcoinSWalletTest { val receivingAddressF = wallet.getNewAddress() val amount = Bitcoins.one - val amtWithFee = amount + Satoshis(175) //for fee + val amtWithFee = amount + Satoshis(175) // for fee - //build funding tx + // build funding tx val fundingTxF: Future[(Transaction, UInt32)] = for { fundingAddr <- fundingAddressF output = TransactionOutput(amtWithFee, fundingAddr.scriptPubKey) fundingTx = TransactionGenerators.buildCreditingTransaction( TransactionConstants.version, output, - TransactionGenerators.outPoint.sampleSome) + TransactionGenerators.outPoint.sampleSome + ) } yield fundingTx val processedFundingTxF: Future[WalletApi] = for { (fundingTx, _) <- fundingTxF - //make sure wallet is empty + // make sure wallet is empty balance <- wallet.getBalance() _ = assert(balance == Bitcoins.zero) processed <- wallet.processTransaction(fundingTx, None) @@ -174,21 +178,23 @@ class ProcessTransactionTest extends BitcoinSWalletTest { _ = assert(balance == amtWithFee) } yield processed - //build spending tx + // build spending tx val spendingTxF = for { receivingAddress <- receivingAddressF wallet <- processedFundingTxF destinations = Vector( - TransactionOutput(amount, receivingAddress.scriptPubKey)) + TransactionOutput(amount, receivingAddress.scriptPubKey) + ) rawTxHelper <- wallet.fundRawTransaction( destinations = destinations, feeRate = SatoshisPerByte.one, fromTagOpt = None, markAsReserved = true ) - processedSpendingTx <- wallet.processTransaction(transaction = - rawTxHelper.signedTx, - blockHashOpt = None) + processedSpendingTx <- wallet.processTransaction( + transaction = rawTxHelper.signedTx, + blockHashOpt = None + ) balance <- processedSpendingTx.getBalance() } yield assert(balance == amount) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/RescanHandlingTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/RescanHandlingTest.scala index e3e5fb2eac..d5298e31fe 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/RescanHandlingTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/RescanHandlingTest.scala @@ -77,8 +77,10 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { val rescanF = for { initBalance <- initBalanceF _ = - assert(initBalance > CurrencyUnits.zero, - s"Cannot run rescan test if our init wallet balance is zero!") + assert( + initBalance > CurrencyUnits.zero, + s"Cannot run rescan test if our init wallet balance is zero!" + ) rescanState <- wallet.fullRescanNeutrinoWallet(DEFAULT_ADDR_BATCH_SIZE) _ = assert(rescanState.isInstanceOf[RescanState.RescanStarted]) _ <- rescanState.asInstanceOf[RescanState.RescanStarted].blocksMatchedF @@ -98,7 +100,7 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { val amt = Bitcoins.one val numBlocks = 1 - //send funds to a fresh wallet address + // send funds to a fresh wallet address val addrF = wallet.getNewAddress() val bitcoindAddrF = bitcoind.getNewAddress val initBlockHeightF = wallet.chainQueryApi.getBestHashBlockHeight() @@ -109,21 +111,22 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { bitcoindAddr <- bitcoindAddrF blockHashes <- bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) - newTxWallet <- wallet.processTransaction(transaction = tx, - blockHashOpt = - blockHashes.headOption) + newTxWallet <- wallet.processTransaction( + transaction = tx, + blockHashOpt = blockHashes.headOption + ) balance <- newTxWallet.getBalance() unconfirmedBalance <- newTxWallet.getUnconfirmedBalance() } yield { - //balance doesn't have to exactly equal, as there was money in the - //wallet before hand. + // balance doesn't have to exactly equal, as there was money in the + // wallet before hand. assert(balance >= amt) assert(amt == unconfirmedBalance) newTxWallet } - //let's clear the wallet and then do a rescan for the last numBlocks - //that means the wallet should only contain the amt we just processed + // let's clear the wallet and then do a rescan for the last numBlocks + // that means the wallet should only contain the amt we just processed for { _ <- newTxWalletF initBlockHeight <- initBlockHeightF @@ -132,13 +135,13 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { _ <- wallet.clearAllUtxos() zeroBalance <- wallet.getBalance() _ = assert(zeroBalance == Satoshis.zero) - rescanState <- wallet.rescanNeutrinoWallet(startOpt = - txInBlockHeightOpt, - endOpt = None, - addressBatchSize = - DEFAULT_ADDR_BATCH_SIZE, - useCreationTime = false, - force = false) + rescanState <- wallet.rescanNeutrinoWallet( + startOpt = txInBlockHeightOpt, + endOpt = None, + addressBatchSize = DEFAULT_ADDR_BATCH_SIZE, + useCreationTime = false, + force = false + ) _ <- { rescanState match { case started: RescanState.RescanStarted => @@ -164,7 +167,7 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { val initBalanceF = wallet.getBalance() val defaultAccountF = wallet.getDefaultAccount() - //send funds to a fresh wallet address + // send funds to a fresh wallet address val addrF = wallet.getNewAddress() val bitcoindAddrF = bitcoind.getNewAddress val balanceAfterPayment1F = for { @@ -175,14 +178,15 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { bitcoindAddr <- bitcoindAddrF blockHashes <- bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) - newTxWallet <- wallet.processTransaction(transaction = tx, - blockHashOpt = - blockHashes.headOption) + newTxWallet <- wallet.processTransaction( + transaction = tx, + blockHashOpt = blockHashes.headOption + ) balance <- newTxWallet.getBalance() unconfirmedBalance <- newTxWallet.getUnconfirmedBalance() } yield { - //balance doesn't have to exactly equal, as there was money in the - //wallet before hand. + // balance doesn't have to exactly equal, as there was money in the + // wallet before hand. assert(balance >= amt) assert(amt == unconfirmedBalance) balance @@ -208,7 +212,8 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { _ <- RescanState.awaitRescanDone(rescanState) _ <- AsyncUtil.awaitConditionF( () => wallet.getBalance().map(_ == balanceAfterPayment1), - maxTries = 100) + maxTries = 100 + ) balanceAfterRescan <- wallet.getBalance() } yield { assert(balanceAfterClear == CurrencyUnits.zero) @@ -224,7 +229,7 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { val amt = Bitcoins.one val numBlocks = 1 - //send funds to a fresh wallet address + // send funds to a fresh wallet address val addrF = wallet.getNewAddress() val bitcoindAddrF = bitcoind.getNewAddress val newTxWalletF = for { @@ -234,14 +239,15 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { bitcoindAddr <- bitcoindAddrF blockHashes <- bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) - newTxWallet <- wallet.processTransaction(transaction = tx, - blockHashOpt = - blockHashes.headOption) + newTxWallet <- wallet.processTransaction( + transaction = tx, + blockHashOpt = blockHashes.headOption + ) balance <- newTxWallet.getBalance() unconfirmedBalance <- newTxWallet.getUnconfirmedBalance() } yield { - //balance doesn't have to exactly equal, as there was money in the - //wallet before hand. + // balance doesn't have to exactly equal, as there was money in the + // wallet before hand. assert(balance >= amt) assert(amt == unconfirmedBalance) newTxWallet @@ -249,12 +255,13 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { for { _ <- newTxWalletF - rescanState <- wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = - DEFAULT_ADDR_BATCH_SIZE, - useCreationTime = true, - force = false) + rescanState <- wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = DEFAULT_ADDR_BATCH_SIZE, + useCreationTime = true, + force = false + ) _ <- { rescanState match { case started: RescanState.RescanStarted => started.blocksMatchedF @@ -275,7 +282,7 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { val initBalanceF = wallet.getBalance() - //find the first block a utxo was created in + // find the first block a utxo was created in val utxosF = wallet.listUtxos() val oldestHeightF = for { utxos <- utxosF @@ -287,21 +294,23 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { } } yield heights.min.get - //ok now that we have the height of the oldest utxo, let's rescan up to then + // ok now that we have the height of the oldest utxo, let's rescan up to then val rescanF = for { initBalance <- initBalanceF _ = - assert(initBalance > CurrencyUnits.zero, - s"Cannot run rescan test if our init wallet balance is zero!") + assert( + initBalance > CurrencyUnits.zero, + s"Cannot run rescan test if our init wallet balance is zero!" + ) oldestUtxoHeight <- oldestHeightF end = Some(BlockStamp.BlockHeight(oldestUtxoHeight - 1)) - rescanState <- wallet.rescanNeutrinoWallet(startOpt = - BlockStamp.height0Opt, - endOpt = end, - addressBatchSize = - DEFAULT_ADDR_BATCH_SIZE, - useCreationTime = false, - force = false) + rescanState <- wallet.rescanNeutrinoWallet( + startOpt = BlockStamp.height0Opt, + endOpt = end, + addressBatchSize = DEFAULT_ADDR_BATCH_SIZE, + useCreationTime = false, + force = false + ) _ <- { rescanState match { case started: RescanState.RescanStarted => started.blocksMatchedF @@ -319,28 +328,30 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { it must "acknowledge that a rescan is already in progress" in { fixture: WalletWithBitcoindRpc => val wallet = fixture.wallet - //do these in parallel on purpose to simulate multiple threads calling rescan - val startF = wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = - DEFAULT_ADDR_BATCH_SIZE, - useCreationTime = true, - force = false) + // do these in parallel on purpose to simulate multiple threads calling rescan + val startF = wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = DEFAULT_ADDR_BATCH_SIZE, + useCreationTime = true, + force = false + ) - //slight delay to make sure other rescan is started + // slight delay to make sure other rescan is started val alreadyStartedF = AsyncUtil.nonBlockingSleep(10.millis).flatMap { _ => - wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = - DEFAULT_ADDR_BATCH_SIZE, - useCreationTime = true, - force = false) + wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = DEFAULT_ADDR_BATCH_SIZE, + useCreationTime = true, + force = false + ) } for { start <- startF _ = assert(start.isInstanceOf[RescanState.RescanStarted]) - //try another one + // try another one alreadyStarted <- alreadyStartedF _ <- start.asInstanceOf[RescanState.RescanStarted].stop() } yield { @@ -354,32 +365,38 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { val bitcoind = fixture.bitcoind val addressNoFundsF = wallet.getNewAddress() - //start a rescan without sending payment to that address + // start a rescan without sending payment to that address for { address <- addressNoFundsF - _ <- wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = 10, - useCreationTime = true, - force = false) + _ <- wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = 10, + useCreationTime = true, + force = false + ) usedAddresses <- wallet.listFundedAddresses() - _ = assert(!usedAddresses.exists(_._1.address == address), - s"Address should not be used! address=$address") - //now send a payment to our wallet + _ = assert( + !usedAddresses.exists(_._1.address == address), + s"Address should not be used! address=$address" + ) + // now send a payment to our wallet hashes <- bitcoind.generateToAddress(1, address) block <- bitcoind.getBlockRaw(hashes.head) _ <- wallet.processBlock(block) fundedAddresses <- wallet.listFundedAddresses() utxos <- wallet.listUtxos(TxoState.ImmatureCoinbase) } yield { - //note 25 bitcoin reward from coinbase tx here - //if we we move this test case in the future it may need to change + // note 25 bitcoin reward from coinbase tx here + // if we we move this test case in the future it may need to change val expectedOutput = TransactionOutput(Bitcoins(25), address.scriptPubKey) - assert(utxos.exists(_.output == expectedOutput), - s"Balance must show up on utxos") + assert( + utxos.exists(_.output == expectedOutput), + s"Balance must show up on utxos" + ) val addressExists = fundedAddresses.exists(_._1.address == address) assert(addressExists) } @@ -391,18 +408,22 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { val bitcoind = fixture.bitcoind val amt = Bitcoins.one for { - _ <- wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = 10, - useCreationTime = true, - force = false) + _ <- wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = 10, + useCreationTime = true, + force = false + ) addressNoFunds <- wallet.getNewChangeAddress() - //rescan again - _ <- wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = 10, - useCreationTime = true, - force = false) + // rescan again + _ <- wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = 10, + useCreationTime = true, + force = false + ) txid <- bitcoind.sendToAddress(addressNoFunds, amt) tx <- bitcoind.getRawTransactionRaw(txid) _ <- wallet.processTransaction(tx, None) @@ -418,21 +439,27 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { for { isRescanning1 <- wallet.isRescanning() - _ = assert(!isRescanning1, - "Cannot be rescanning before we started the test") - //start the rescan - state <- wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = 10, - useCreationTime = true, - force = false) + _ = assert( + !isRescanning1, + "Cannot be rescanning before we started the test" + ) + // start the rescan + state <- wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = 10, + useCreationTime = true, + force = false + ) isRescanning2 <- wallet.isRescanning() - _ = assert(isRescanning2, - s"Rescan flag must be set after starting a rescan") + _ = assert( + isRescanning2, + s"Rescan flag must be set after starting a rescan" + ) _ <- RescanState.awaitRescanDone(state) _ <- AsyncUtil.nonBlockingSleep( 1.second - ) //extra buffer to avoid race condition + ) // extra buffer to avoid race condition isRescanning3 <- wallet.isRescanning() } yield { assert(!isRescanning3) @@ -445,29 +472,37 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { for { isRescanning1 <- wallet.isRescanning() - _ = assert(!isRescanning1, - "Cannot be rescanning before we started the test") - //start the rescan - state <- wallet.rescanNeutrinoWallet(startOpt = None, - endOpt = None, - addressBatchSize = 10, - useCreationTime = true, - force = false) + _ = assert( + !isRescanning1, + "Cannot be rescanning before we started the test" + ) + // start the rescan + state <- wallet.rescanNeutrinoWallet( + startOpt = None, + endOpt = None, + addressBatchSize = 10, + useCreationTime = true, + force = false + ) isRescanning2 <- wallet.isRescanning() - _ = assert(isRescanning2, - s"Rescan flag must be set after starting a rescan") + _ = assert( + isRescanning2, + s"Rescan flag must be set after starting a rescan" + ) _ = state match { case started: RescanState.RescanStarted => started.fail( new RuntimeException( - "Purposefully terminate rescan early for test")) + "Purposefully terminate rescan early for test" + ) + ) case RescanState.RescanDone | RescanState.RescanAlreadyStarted | RescanState.RescanNotNeeded => fail(s"Rescan must be started") } _ <- AsyncUtil.nonBlockingSleep( 1.second - ) //extra buffer to avoid race condition + ) // extra buffer to avoid race condition isRescanning3 <- wallet.isRescanning() } yield { assert(!isRescanning3) @@ -485,7 +520,7 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { val initBalanceF = wallet.getBalance() val defaultAccountF = wallet.getDefaultAccount() - //send funds to a fresh wallet address + // send funds to a fresh wallet address val addr1F = wallet.getNewAddress() val addr2F = wallet.getNewAddress() val bitcoindAddrF = bitcoind.getNewAddress @@ -493,23 +528,24 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { addr1 <- addr1F addr2 <- addr2F _ <- initBalanceF - //its important that both of these payments are sent in one tx - //so that we check that we can discover payments in the same tx - //across different rescan batches + // its important that both of these payments are sent in one tx + // so that we check that we can discover payments in the same tx + // across different rescan batches sendManyMap = Map(addr1 -> amt, addr2 -> amt) txid <- bitcoind.sendMany(sendManyMap) tx <- bitcoind.getRawTransactionRaw(txid) bitcoindAddr <- bitcoindAddrF blockHashes <- bitcoind.generateToAddress(blocks = numBlocks, address = bitcoindAddr) - newTxWallet <- wallet.processTransaction(transaction = tx, - blockHashOpt = - blockHashes.headOption) + newTxWallet <- wallet.processTransaction( + transaction = tx, + blockHashOpt = blockHashes.headOption + ) balance <- newTxWallet.getBalance() unconfirmedBalance <- newTxWallet.getUnconfirmedBalance() } yield { - //balance doesn't have to exactly equal, as there was money in the - //wallet before hand. + // balance doesn't have to exactly equal, as there was money in the + // wallet before hand. assert(balance >= expectedBalance) assert(expectedBalance == unconfirmedBalance) balance @@ -535,7 +571,8 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { _ <- RescanState.awaitRescanDone(rescanState) _ <- AsyncUtil.awaitConditionF( () => wallet.getBalance().map(_ == balanceAfterPayment1), - maxTries = 100) + maxTries = 100 + ) balanceAfterRescan <- wallet.getBalance() } yield { assert(balanceAfterClear == CurrencyUnits.zero) @@ -548,9 +585,9 @@ class RescanHandlingTest extends BitcoinSWalletTestCachedBitcoindNewest { val wallet = fixture.wallet val rescanF = for { - //need to clear all utxos / addresses to test this - //otherwise the wallet will see we already have addresses and not generate - //a fresh pool of addresses + // need to clear all utxos / addresses to test this + // otherwise the wallet will see we already have addresses and not generate + // a fresh pool of addresses _ <- wallet.clearAllUtxos() _ <- wallet.clearAllAddresses() rescanState <- wallet.fullRescanNeutrinoWallet(DEFAULT_ADDR_BATCH_SIZE) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/TrezorAddressTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/TrezorAddressTest.scala index 694e39f60f..bff6260816 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/TrezorAddressTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/TrezorAddressTest.scala @@ -97,7 +97,8 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture { path: HDPath, chain: HDChainType, addressIndex: Int, - address: BitcoinAddress) + address: BitcoinAddress + ) object TestAddress { implicit val reads: Reads[TestAddress] = Json.reads[TestAddress] @@ -108,7 +109,8 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture { coin: HDCoinType, account: Int, pathType: HDPurpose, - addresses: Vector[TestAddress]) + addresses: Vector[TestAddress] + ) object TestVector { implicit val reads: Reads[TestVector] = Json.reads[TestVector] @@ -149,23 +151,29 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture { for { _ <- startedF wallet = - Wallet(MockNodeApi, - MockChainQueryApi, - ConstantFeeRateProvider(SatoshisPerVirtualByte.one))(config) - init <- Wallet.initialize(wallet = wallet, - bip39PasswordOpt = bip39PasswordOpt) + Wallet( + MockNodeApi, + MockChainQueryApi, + ConstantFeeRateProvider(SatoshisPerVirtualByte.one) + )(config) + init <- Wallet.initialize( + wallet = wallet, + bip39PasswordOpt = bip39PasswordOpt + ) } yield init } case class AccountAndAddrsAndVector( account: AccountDb, addrs: Seq[AddressDb], - vector: TestVector) + vector: TestVector + ) /** Asserts that the given addresses are gthe same as in the given vector */ private def assertSameAddresses( addrs: Seq[AddressDb], - vector: TestVector): Seq[Assertion] = { + vector: TestVector + ): Seq[Assertion] = { assert(vector.addresses.length == addrs.length) val sortedAddresses = addrs.sortBy(_.path.toString) @@ -182,7 +190,8 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture { wallet: Wallet, existing: Vector[AccountDb], keyManagerParams: KeyManagerParams, - testVectors: Vector[TestVector]): Future[Unit] = { + testVectors: Vector[TestVector] + ): Future[Unit] = { val accountsToCreate = existing.length until testVectors.length FutureUtil .sequentially(accountsToCreate) { _ => @@ -191,14 +200,13 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture { .map(_ => ()) } - /** Iterates over the given list of accounts and test vectors, and - * fetches all the - * addresses needed to verify the test vector + /** Iterates over the given list of accounts and test vectors, and fetches all + * the addresses needed to verify the test vector */ def getAccountsWithAddressesAndVectors( wallet: Wallet, - accountsWithVectors: Seq[(AccountDb, TestVector)]): Future[ - Seq[AccountAndAddrsAndVector]] = { + accountsWithVectors: Seq[(AccountDb, TestVector)] + ): Future[Seq[AccountAndAddrsAndVector]] = { FutureUtil.sequentially(accountsWithVectors) { case (acc, vec) => val addrFutures: Future[Seq[AddressDb]] = FutureUtil.sequentially(vec.addresses) { vector => @@ -221,8 +229,10 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture { val confOverride = configForPurposeAndSeed(purpose) implicit val conf: WalletAppConfig = BitcoinSTestAppConfig - .getNeutrinoWithEmbeddedDbTestConfig(() => pgUrl(), - Vector(confOverride)) + .getNeutrinoWithEmbeddedDbTestConfig( + () => pgUrl(), + Vector(confOverride) + ) .walletConf val testVectors = purpose match { @@ -235,10 +245,12 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture { val assertionsF: Future[Seq[Assertion]] = for { wallet <- getWallet(conf) existingAccounts <- wallet.listAccounts(purpose) - _ <- createNeededAccounts(wallet, - existingAccounts, - conf.kmParams, - testVectors) + _ <- createNeededAccounts( + wallet, + existingAccounts, + conf.kmParams, + testVectors + ) accounts <- wallet.listAccounts(purpose) // we want to find all accounts for the given account type, // and match it with its corresponding test vector @@ -249,7 +261,8 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture { accounts.find(_.hdAccount.index == vec.account) match { case None => fail( - s"Did not find account in wallet with index ${vec.account}. Accounts: ${accounts.mkString}") + s"Did not find account in wallet with index ${vec.account}. Accounts: ${accounts.mkString}" + ) case Some(account) => assert(account.xpub == vec.xpub) account -> vec diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOHandlingTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOHandlingTest.scala index e6e6e57acf..b630d1d2b4 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOHandlingTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOHandlingTest.scala @@ -12,9 +12,10 @@ class UTXOHandlingTest extends BitcoinSUnitTest { behavior of "UTXOHandling" - val utxo = sampleSegwitUTXO(EmptyScriptPubKey, - state = TxoState.Reserved - ) //state doesn't matter here + val utxo = sampleSegwitUTXO( + EmptyScriptPubKey, + state = TxoState.Reserved + ) // state doesn't matter here val requiredConfs = 6 val reserved = utxo.copyWithState(Reserved) @@ -26,57 +27,76 @@ class UTXOHandlingTest extends BitcoinSUnitTest { val pendingConfReceived = utxo.copyWithState(PendingConfirmationsReceived) it must "correct update receive txo state based on confirmations" in { - //it must stay reserved if we are receiving confirmations + // it must stay reserved if we are receiving confirmations assert( - UtxoHandling.updateReceivedTxoWithConfs(reserved, - 1, - requiredConfs) == reserved) + UtxoHandling.updateReceivedTxoWithConfs( + reserved, + 1, + requiredConfs + ) == reserved + ) - //it must stay immature coinbase if we don't have > 101 confirmations + // it must stay immature coinbase if we don't have > 101 confirmations assert( UtxoHandling.updateReceivedTxoWithConfs( immatureCoinbase, 10, - requiredConfs) == immatureCoinbase) + requiredConfs + ) == immatureCoinbase + ) assert( - UtxoHandling.updateReceivedTxoWithConfs(immatureCoinbase, - 101, - requiredConfs) == confReceived) + UtxoHandling.updateReceivedTxoWithConfs( + immatureCoinbase, + 101, + requiredConfs + ) == confReceived + ) - //we must stay pending confirmations received with only 1 confirmation + // we must stay pending confirmations received with only 1 confirmation assert( UtxoHandling.updateReceivedTxoWithConfs( pendingConfReceived, 1, - requiredConfs) == pendingConfReceived) + requiredConfs + ) == pendingConfReceived + ) - //must be able to go back to broadcast received if we don't have confirmations (re-org scenario) + // must be able to go back to broadcast received if we don't have confirmations (re-org scenario) assert( UtxoHandling .updateReceivedTxoWithConfs(pendingConfReceived, 0, requiredConfs) - .state == TxoState.BroadcastReceived) + .state == TxoState.BroadcastReceived + ) - //transition from TxoState.ConfirmedReceived -> TxoState.PendingConfirmationsReceived (reorg scenario) + // transition from TxoState.ConfirmedReceived -> TxoState.PendingConfirmationsReceived (reorg scenario) assert( - UtxoHandling.updateReceivedTxoWithConfs(confReceived, - 1, - requiredConfs) == confReceived - .copyWithState(PendingConfirmationsReceived)) + UtxoHandling.updateReceivedTxoWithConfs( + confReceived, + 1, + requiredConfs + ) == confReceived + .copyWithState(PendingConfirmationsReceived) + ) - //it must stay TxoState.ConfirmedReceived if we keep receiving confirmations + // it must stay TxoState.ConfirmedReceived if we keep receiving confirmations assert( - UtxoHandling.updateReceivedTxoWithConfs(confReceived, - requiredConfs, - requiredConfs) == confReceived) + UtxoHandling.updateReceivedTxoWithConfs( + confReceived, + requiredConfs, + requiredConfs + ) == confReceived + ) - //it must stay broadcast received with 0 confirmations + // it must stay broadcast received with 0 confirmations val broadcastReceived = utxo .copyWithState(TxoState.BroadcastReceived) assert( UtxoHandling.updateReceivedTxoWithConfs( broadcastReceived, 0, - requiredConfs) == broadcastReceived) + requiredConfs + ) == broadcastReceived + ) } it must "correctly update spent txo state based on confirmations" in { @@ -93,21 +113,23 @@ class UTXOHandlingTest extends BitcoinSUnitTest { val withSpendingTxId = reserved.copyWithSpendingTxId(DoubleSha256DigestBE.empty) - //it must transition from reserved to broacast spent + // it must transition from reserved to broacast spent assert( UtxoHandling .updateSpentTxoWithConfs(withSpendingTxId, 0, requiredConfs) - .state == TxoState.BroadcastSpent) + .state == TxoState.BroadcastSpent + ) - //it must transition from reserved to spent + // it must transition from reserved to spent assert( UtxoHandling .updateSpentTxoWithConfs(withSpendingTxId, 1, requiredConfs) - .state == TxoState.PendingConfirmationsSpent) + .state == TxoState.PendingConfirmationsSpent + ) - //cannot spend an immature coinbase output + // cannot spend an immature coinbase output assertThrows[RuntimeException] { - //cannot have utxo spent from coinbase before 101 blocks + // cannot have utxo spent from coinbase before 101 blocks UtxoHandling.updateSpentTxoWithConfs(immatureCoinbase, 100, requiredConfs) } @@ -119,55 +141,72 @@ class UTXOHandlingTest extends BitcoinSUnitTest { .copyWithState(TxoState.ConfirmedSpent) val updated = - UtxoHandling.updateSpentTxoWithConfs(pendingConfReceivedWithTxId, - requiredConfs, - requiredConfs) - //it must transition from Pending Confirmation Received -> Pending Confirmation Spent + UtxoHandling.updateSpentTxoWithConfs( + pendingConfReceivedWithTxId, + requiredConfs, + requiredConfs + ) + // it must transition from Pending Confirmation Received -> Pending Confirmation Spent assert(updated == expectedConfSpent) - //must stay at pending confirmations spent with only 1 confirmation + // must stay at pending confirmations spent with only 1 confirmation assert( - UtxoHandling.updateSpentTxoWithConfs(pendingConfSpent, - 1, - requiredConfs) == pendingConfSpent) + UtxoHandling.updateSpentTxoWithConfs( + pendingConfSpent, + 1, + requiredConfs + ) == pendingConfSpent + ) - //must transition from PendingConfirmationsSpent -> ConfirmedSpent + // must transition from PendingConfirmationsSpent -> ConfirmedSpent assert( - UtxoHandling.updateSpentTxoWithConfs(pendingConfSpent, - requiredConfs, - requiredConfs) == confSpent) + UtxoHandling.updateSpentTxoWithConfs( + pendingConfSpent, + requiredConfs, + requiredConfs + ) == confSpent + ) - //transition form TxoState.ConfirmedSpent -> TxoState.PendingConfirmationSpent (reorg scenario) + // transition form TxoState.ConfirmedSpent -> TxoState.PendingConfirmationSpent (reorg scenario) assert( UtxoHandling.updateSpentTxoWithConfs( confSpent, 1, - requiredConfs) == confSpent.copyWithState(PendingConfirmationsSpent)) + requiredConfs + ) == confSpent.copyWithState(PendingConfirmationsSpent) + ) - //stay confirmed if we are already confirmed + // stay confirmed if we are already confirmed assert( - UtxoHandling.updateSpentTxoWithConfs(confSpent, - requiredConfs, - requiredConfs) == confSpent) + UtxoHandling.updateSpentTxoWithConfs( + confSpent, + requiredConfs, + requiredConfs + ) == confSpent + ) val expectedConfReceivedWithTxid = confReceived.copyWithSpendingTxId(DoubleSha256DigestBE.empty) - //TxoState.ConfirmedReceived -> TxoState.ConfirmedSpent + // TxoState.ConfirmedReceived -> TxoState.ConfirmedSpent assert( UtxoHandling.updateSpentTxoWithConfs( expectedConfReceivedWithTxid, requiredConfs, - requiredConfs) == expectedConfReceivedWithTxid.copyWithState( - TxoState.ConfirmedSpent)) + requiredConfs + ) == expectedConfReceivedWithTxid.copyWithState(TxoState.ConfirmedSpent) + ) - //it must stay BroadcastSpent with 0 confirmations + // it must stay BroadcastSpent with 0 confirmations val broadcastSpent = utxo .copyWithSpendingTxId(DoubleSha256DigestBE.empty) .copyWithState(TxoState.BroadcastSpent) assert( - UtxoHandling.updateSpentTxoWithConfs(broadcastSpent, - 0, - requiredConfs) == broadcastSpent) + UtxoHandling.updateSpentTxoWithConfs( + broadcastSpent, + 0, + requiredConfs + ) == broadcastSpent + ) } } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOLifeCycleTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOLifeCycleTest.scala index cb9c1c6dce..c13da6c89b 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOLifeCycleTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/UTXOLifeCycleTest.scala @@ -35,7 +35,8 @@ class UTXOLifeCycleTest val f: Future[Outcome] = for { bitcoind <- cachedBitcoindWithFundsF futOutcome = withFundedWalletAndBitcoindCached(test, bitcoind)( - getFreshWalletAppConfig) + getFreshWalletAppConfig + ) fut <- futOutcome.toFuture } yield fut new FutureOutcome(f) @@ -104,7 +105,8 @@ class UTXOLifeCycleTest txid1: DoubleSha256DigestBE, txid2: DoubleSha256DigestBE, txid3: DoubleSha256DigestBE, - state: TxoState): Assertion = { + state: TxoState + ): Assertion = { val utxo1 = utxos.find(_.txid == txid1).get assert(utxo1.state == state) val utxo2 = utxos.find(_.txid == txid2).get @@ -181,11 +183,13 @@ class UTXOLifeCycleTest utxos <- wallet.listUtxos() _ = assert(oldUtxos.size + 3 == utxos.size) - _ = checkState(utxos, - txid1, - txid2, - txid3, - TxoState.PendingConfirmationsReceived) + _ = checkState( + utxos, + txid1, + txid2, + txid3, + TxoState.PendingConfirmationsReceived + ) // mine the third block blockHashes <- bitcoind.generateToAddress(1, minerAddr) @@ -198,11 +202,13 @@ class UTXOLifeCycleTest utxos <- wallet.listUtxos() _ = assert(oldUtxos.size + 3 == utxos.size) - _ = checkState(utxos, - txid1, - txid2, - txid3, - TxoState.PendingConfirmationsReceived) + _ = checkState( + utxos, + txid1, + txid2, + txid3, + TxoState.PendingConfirmationsReceived + ) // mine the fourth block blockHashes <- bitcoind.generateToAddress(1, minerAddr) @@ -215,11 +221,13 @@ class UTXOLifeCycleTest utxos <- wallet.listUtxos() _ = assert(oldUtxos.size + 3 == utxos.size) - _ = checkState(utxos, - txid1, - txid2, - txid3, - TxoState.PendingConfirmationsReceived) + _ = checkState( + utxos, + txid1, + txid2, + txid3, + TxoState.PendingConfirmationsReceived + ) // mine the fifth block blockHashes <- bitcoind.generateToAddress(1, minerAddr) @@ -232,11 +240,13 @@ class UTXOLifeCycleTest utxos <- wallet.listUtxos() _ = assert(oldUtxos.size + 3 == utxos.size) - _ = checkState(utxos, - txid1, - txid2, - txid3, - TxoState.PendingConfirmationsReceived) + _ = checkState( + utxos, + txid1, + txid2, + txid3, + TxoState.PendingConfirmationsReceived + ) // mine the sixth block blockHashes <- bitcoind.generateToAddress(1, minerAddr) @@ -264,9 +274,11 @@ class UTXOLifeCycleTest val wallet = param.wallet for { - tx <- wallet.sendToAddress(testAddr, - Satoshis(3000), - Some(SatoshisPerByte.one)) + tx <- wallet.sendToAddress( + testAddr, + Satoshis(3000), + Some(SatoshisPerByte.one) + ) coins <- wallet.findOutputsBeingSpent(tx) _ = assert(coins.forall(_.state == BroadcastSpent)) @@ -303,7 +315,8 @@ class UTXOLifeCycleTest } res <- recoverToSucceededIf[RuntimeException]( - wallet.processTransaction(newTx, None)) + wallet.processTransaction(newTx, None) + ) } yield res } @@ -348,7 +361,8 @@ class UTXOLifeCycleTest } res <- recoverToSucceededIf[RuntimeException]( - wallet.processTransaction(newTx, None)) + wallet.processTransaction(newTx, None) + ) } yield res } @@ -362,12 +376,14 @@ class UTXOLifeCycleTest txId <- bitcoind.sendToAddress(addr, Satoshis(3000)) tx <- bitcoind.getRawTransactionRaw(txId) - _ <- wallet.processOurTransaction(transaction = tx, - feeRate = SatoshisPerByte(Satoshis(3)), - inputAmount = Satoshis(4000), - sentAmount = Satoshis(3000), - blockHashOpt = None, - newTags = Vector.empty) + _ <- wallet.processOurTransaction( + transaction = tx, + feeRate = SatoshisPerByte(Satoshis(3)), + inputAmount = Satoshis(4000), + sentAmount = Satoshis(3000), + blockHashOpt = None, + newTags = Vector.empty + ) updatedCoin <- wallet.findByScriptPubKey(addr.scriptPubKey) @@ -389,12 +405,14 @@ class UTXOLifeCycleTest txId <- bitcoind.sendToAddress(addr, Satoshis(3000)) tx <- bitcoind.getRawTransactionRaw(txId) - _ <- wallet.processOurTransaction(transaction = tx, - feeRate = SatoshisPerByte(Satoshis(3)), - inputAmount = Satoshis(4000), - sentAmount = Satoshis(3000), - blockHashOpt = None, - newTags = Vector.empty) + _ <- wallet.processOurTransaction( + transaction = tx, + feeRate = SatoshisPerByte(Satoshis(3)), + inputAmount = Satoshis(4000), + sentAmount = Satoshis(3000), + blockHashOpt = None, + newTags = Vector.empty + ) updatedCoin <- wallet.findByScriptPubKey(addr.scriptPubKey) @@ -410,7 +428,8 @@ class UTXOLifeCycleTest wallet.findByScriptPubKey(addr.scriptPubKey) } yield { assert( - pendingCoins.forall(_.state == TxoState.PendingConfirmationsReceived)) + pendingCoins.forall(_.state == TxoState.PendingConfirmationsReceived) + ) assert(!oldTransactions.map(_.transaction).contains(tx)) assert(newTransactions.map(_.transaction).contains(tx)) } @@ -461,10 +480,12 @@ class UTXOLifeCycleTest for { oldTransactions <- wallet.listTransactions() feeRate <- wallet.getFeeRate() - rawTxHelper <- wallet.fundRawTransaction(Vector(dummyOutput), - feeRate, - fromTagOpt = None, - markAsReserved = true) + rawTxHelper <- wallet.fundRawTransaction( + Vector(dummyOutput), + feeRate, + fromTagOpt = None, + markAsReserved = true + ) tx = rawTxHelper.unsignedTx updatedCoins <- wallet.findOutputsBeingSpent(tx) @@ -488,10 +509,12 @@ class UTXOLifeCycleTest for { oldTransactions <- wallet.listTransactions() feeRate <- wallet.getFeeRate() - rawTxHelper <- wallet.fundRawTransaction(Vector(dummyOutput), - feeRate, - fromTagOpt = None, - markAsReserved = true) + rawTxHelper <- wallet.fundRawTransaction( + Vector(dummyOutput), + feeRate, + fromTagOpt = None, + markAsReserved = true + ) tx = rawTxHelper.unsignedTx reservedUtxos <- wallet.findOutputsBeingSpent(tx) @@ -519,17 +542,20 @@ class UTXOLifeCycleTest for { oldTransactions <- wallet.listTransactions() feeRate <- wallet.getFeeRate() - rawTxHelper <- wallet.fundRawTransaction(Vector(dummyOutput), - feeRate, - fromTagOpt = None, - markAsReserved = true) + rawTxHelper <- wallet.fundRawTransaction( + Vector(dummyOutput), + feeRate, + fromTagOpt = None, + markAsReserved = true + ) tx = rawTxHelper.unsignedTx allReserved <- wallet.listUtxos(TxoState.Reserved) _ = assert( tx.inputs .map(_.previousOutput) - .forall(allReserved.map(_.outPoint).contains)) + .forall(allReserved.map(_.outPoint).contains) + ) unreservedUtxos <- wallet.unmarkUTXOsAsReserved(tx) newTransactions <- wallet.listTransactions() @@ -545,8 +571,10 @@ class UTXOLifeCycleTest val wallet = param.wallet val bitcoind = param.bitcoind val dummyOutput = - TransactionOutput(Satoshis(100000), - P2PKHScriptPubKey(ECPublicKey.freshPublicKey)) + TransactionOutput( + Satoshis(100000), + P2PKHScriptPubKey(ECPublicKey.freshPublicKey) + ) val accountF = wallet.getDefaultAccount() for { oldTransactions <- wallet.listTransactions() @@ -559,13 +587,15 @@ class UTXOLifeCycleTest ) builderResult = rawTxHelper.txBuilderWithFinalizer.builder.result() unsignedTx = rawTxHelper.txBuilderWithFinalizer.finalizer.buildTx( - builderResult) + builderResult + ) tx = RawTxSigner.sign(unsignedTx, rawTxHelper.scriptSigParams) allReserved <- wallet.listUtxos(TxoState.Reserved) _ = assert( tx.inputs .map(_.previousOutput) - .forall(allReserved.map(_.outPoint).contains)) + .forall(allReserved.map(_.outPoint).contains) + ) // Confirm tx in a block _ <- bitcoind.sendRawTransaction(tx) @@ -601,13 +631,17 @@ class UTXOLifeCycleTest val output = TransactionOutput(amt, testAddr.scriptPubKey) val changeOutput = - TransactionOutput(utxo.output.value - amt - Satoshis(1000), - changeAddr.scriptPubKey) + TransactionOutput( + utxo.output.value - amt - Satoshis(1000), + changeAddr.scriptPubKey + ) - val tx = BaseTransaction(Int32.two, - Vector(input), - Vector(output, changeOutput), - UInt32.zero) + val tx = BaseTransaction( + Int32.two, + Vector(input), + Vector(output, changeOutput), + UInt32.zero + ) PSBT.fromUnsignedTx(tx) } @@ -615,7 +649,8 @@ class UTXOLifeCycleTest psbt <- wallet.signPSBT(unsignedPSBT) tx <- Future.fromTry( - psbt.finalizePSBT.flatMap(_.extractTransactionAndValidate)) + psbt.finalizePSBT.flatMap(_.extractTransactionAndValidate) + ) // Confirm tx in a block _ <- bitcoind.sendRawTransaction(tx) @@ -626,7 +661,8 @@ class UTXOLifeCycleTest updatedCoins <- wallet.findOutputsBeingSpent(tx) } yield { assert( - updatedCoins.forall(_.state == TxoState.PendingConfirmationsSpent)) + updatedCoins.forall(_.state == TxoState.PendingConfirmationsSpent) + ) assert(updatedCoins.forall(_.spendingTxIdOpt.contains(tx.txIdBE))) } } @@ -639,15 +675,15 @@ class UTXOLifeCycleTest val reservedUtxoF: Future[SpendingInfoDb] = for { utxos <- utxosF first = utxos.head - //just reserve this one to start + // just reserve this one to start reserved <- wallet.markUTXOsAsReserved(Vector(first)) } yield reserved.head val reserveFailedF = for { utxos <- utxosF _ <- reservedUtxoF - //now try to reserve them all - //this should fail as the first utxo is reserved + // now try to reserve them all + // this should fail as the first utxo is reserved _ <- wallet.markUTXOsAsReserved(utxos) } yield () @@ -658,7 +694,7 @@ class UTXOLifeCycleTest reserved <- reservedUtxoF utxos <- wallet.listUtxos(TxoState.Reserved) } yield { - //make sure only 1 utxo is still reserved + // make sure only 1 utxo is still reserved assert(utxos.length == 1) assert(reserved.outPoint == utxos.head.outPoint) } @@ -674,32 +710,32 @@ class UTXOLifeCycleTest val throwAwayAddrF = bitcoind.getNewAddress for { txId <- txIdF - //generate a few blocks to make the utxo pending confirmations received + // generate a few blocks to make the utxo pending confirmations received throwAwayAddr <- throwAwayAddrF hashes <- bitcoind.generateToAddress(blocks = 1, throwAwayAddr) block <- bitcoind.getBlockRaw(hashes.head) _ <- wallet.processBlock(block) - //make sure the utxo is pending confirmations received + // make sure the utxo is pending confirmations received utxos <- wallet.listUtxos(TxoState.PendingConfirmationsReceived) _ = assert(utxos.length == 1) utxo = utxos.head _ = assert(utxo.txid == txId) _ = assert(utxo.state == TxoState.PendingConfirmationsReceived) - //now mark the utxo as reserved + // now mark the utxo as reserved _ <- wallet.markUTXOsAsReserved(Vector(utxo)) - //confirm it is reserved + // confirm it is reserved _ <- wallet .listUtxos(TxoState.Reserved) .map(utxos => assert(utxos.contains(utxo.copyWithState(TxoState.Reserved)))) - //now process another block + // now process another block hashes2 <- bitcoind.generateToAddress(blocks = 1, throwAwayAddr) block2 <- bitcoind.getBlockRaw(hashes2.head) _ <- wallet.processBlock(block2) - //the utxo should still be reserved + // the utxo should still be reserved reservedUtxos <- wallet.listUtxos(TxoState.Reserved) reservedUtxo = reservedUtxos.head } yield { @@ -718,40 +754,42 @@ class UTXOLifeCycleTest for { bitcoindAdr <- bitcoindAddrF utxoCount <- utxoCountF - //build a spending transaction + // build a spending transaction tx <- wallet.sendToAddress(bitcoindAdr, amt, SatoshisPerVirtualByte.one) c <- wallet.listUtxos() _ = assert(c.length == utxoCount.length) txIdBE <- bitcoind.sendRawTransaction(tx) - //find all utxos that we can use to fund a transaction + // find all utxos that we can use to fund a transaction utxos <- wallet .listUtxos() .map(_.filter(u => TxoState.receivedStates.contains(u.state))) broadcastReceived <- wallet.listUtxos(TxoState.BroadcastReceived) - _ = assert(broadcastReceived.length == 1) //change output + _ = assert(broadcastReceived.length == 1) // change output - //mark all utxos as reserved + // mark all utxos as reserved _ <- wallet.markUTXOsAsReserved(utxos) newReservedUtxos <- wallet.listUtxos(TxoState.Reserved) - //make sure all utxos are reserved + // make sure all utxos are reserved _ = assert(newReservedUtxos.length == utxoCount.length) blockHash <- bitcoind.generateToAddress(1, bitcoindAdr).map(_.head) block <- bitcoind.getBlockRaw(blockHash) _ <- wallet.processBlock(block) broadcastSpentUtxo <- wallet.listUtxos( - TxoState.PendingConfirmationsSpent) + TxoState.PendingConfirmationsSpent + ) pendingConfirmationsReceivedUtxos <- wallet.listUtxos( - TxoState.PendingConfirmationsReceived) + TxoState.PendingConfirmationsReceived + ) finalReservedUtxos <- wallet.listUtxos(TxoState.Reserved) } yield { assert(newReservedUtxos == finalReservedUtxos) assert(pendingConfirmationsReceivedUtxos.isEmpty) assert(broadcastSpentUtxo.length == 1) - //make sure spendingTxId got set correctly + // make sure spendingTxId got set correctly assert(broadcastSpentUtxo.head.spendingTxIdOpt.get == txIdBE) - //make sure no utxos get unreserved when processing the block + // make sure no utxos get unreserved when processing the block assert(finalReservedUtxos.length == newReservedUtxos.length) } } @@ -775,8 +813,10 @@ class UTXOLifeCycleTest .map(out => (receiveTx.txId, out._2)) .get - receiveOutPoint = TransactionOutPoint(receiveOutPointPair._1, - UInt32(receiveOutPointPair._2)) + receiveOutPoint = TransactionOutPoint( + receiveOutPointPair._1, + UInt32(receiveOutPointPair._2) + ) receivedUtxo <- wallet.findByOutPoints(Vector(receiveOutPoint)) _ = assert(receivedUtxo.size == 1) @@ -788,7 +828,8 @@ class UTXOLifeCycleTest testAddr, sendValue, feeRate, - CoinSelectionAlgo.SelectedUtxos(Set(receiveOutPointPair))) + CoinSelectionAlgo.SelectedUtxos(Set(receiveOutPointPair)) + ) _ <- wallet.broadcastTransaction(sendTx) receivedUtxo <- wallet.findByOutPoints(Vector(receiveOutPoint)) @@ -826,8 +867,10 @@ class UTXOLifeCycleTest .map(out => (receiveTx.txId, out._2)) .get - receiveOutPoint = TransactionOutPoint(receiveOutPointPair._1, - UInt32(receiveOutPointPair._2)) + receiveOutPoint = TransactionOutPoint( + receiveOutPointPair._1, + UInt32(receiveOutPointPair._2) + ) receivedUtxo <- wallet.findByOutPoints(Vector(receiveOutPoint)) _ = assert(receivedUtxo.size == 1) @@ -839,7 +882,8 @@ class UTXOLifeCycleTest testAddr, sendValue, feeRate, - CoinSelectionAlgo.SelectedUtxos(Set(receiveOutPointPair))) + CoinSelectionAlgo.SelectedUtxos(Set(receiveOutPointPair)) + ) receivedUtxo <- wallet.findByOutPoints(Vector(receiveOutPoint)) _ = assert(receivedUtxo.size == 1) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletAppConfigTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletAppConfigTest.scala index 8eceeb5ae7..c3c62aa01c 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletAppConfigTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletAppConfigTest.scala @@ -54,7 +54,8 @@ class WalletAppConfigTest extends BitcoinSAsyncTest { s"bitcoin-s.wallet.defaultAccountType = segwit" ) val thirdConf = ConfigFactory.parseString( - s"bitcoin-s.wallet.defaultAccountType = nested-segwit") + s"bitcoin-s.wallet.defaultAccountType = nested-segwit" + ) val overriden = config.withOverrides(otherConf) @@ -102,7 +103,7 @@ class WalletAppConfigTest extends BitcoinSAsyncTest { val seedFile = config.seedPath val startedF = config.start() - //stop old oracle + // stop old oracle val stoppedF = for { _ <- startedF _ <- config.stop() @@ -111,7 +112,7 @@ class WalletAppConfigTest extends BitcoinSAsyncTest { val deletedF = for { _ <- stoppedF } yield { - //delete the seed so we start with a new seed + // delete the seed so we start with a new seed Files.delete(seedFile) } @@ -120,7 +121,7 @@ class WalletAppConfigTest extends BitcoinSAsyncTest { _ <- config.start() } yield () - //start it again and except an exception + // start it again and except an exception recoverToSucceededIf[RuntimeException] { start2F } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletCallbackTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletCallbackTest.scala index b2deea62ba..ba421e36af 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletCallbackTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletCallbackTest.scala @@ -104,7 +104,8 @@ class WalletCallbackTest extends BitcoinSWalletTest { |8a5a6bfd87c71d00000000001600145543e613b22f2393e76510cede73952405a5c9b9024730 |440220348dc443d9a0cc6b5365d7ef8d62e1ca4d890c6f4d817a0fb0f48ff36b97e08702201d |77554641889932523e7d103385d99834cb9f29328ce11282ccbe218acf56440121028bb78dbe - |0ea469c97061b8dcc870ec25d5abcd938f19ec17e32422f8f318fa251b992000""".stripMargin) + |0ea469c97061b8dcc870ec25d5abcd938f19ec17e32422f8f318fa251b992000""".stripMargin + ) for { txno <- wallet.listTransactions().map(_.size) @@ -163,7 +164,8 @@ class WalletCallbackTest extends BitcoinSWalletTest { result <- resultP.future } yield assert( // just compare outPoints because states will be changed so they won't be equal - result.map(_.outPoint) == Vector(utxos.head).map(_.outPoint)) + result.map(_.outPoint) == Vector(utxos.head).map(_.outPoint) + ) } it must "verify OnReservedUtxos callbacks are executed when un-reserving" in { diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletIntegrationTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletIntegrationTest.scala index f1ab57519a..4cbfe3f9be 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletIntegrationTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletIntegrationTest.scala @@ -32,7 +32,8 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { bitcoind <- cachedBitcoindWithFundsF futOutcome = withNewWalletAndBitcoindCached( test = test, - bitcoind = bitcoind)(getFreshWalletAppConfig) + bitcoind = bitcoind + )(getFreshWalletAppConfig) fut <- futOutcome.toFuture } yield fut new FutureOutcome(f) @@ -149,15 +150,19 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { ) // Safe to use utxos.head because we've already asserted that we only have our change output assert( - outgoingTx.get.actualFee + outgoingTx.get.sentAmount == outgoingTx.get.inputAmount - utxos.head.output.value) + outgoingTx.get.actualFee + outgoingTx.get.sentAmount == outgoingTx.get.inputAmount - utxos.head.output.value + ) // change UTXO should be smaller than what we had, but still have money in it assert(balancePostSend > 0.sats) assert(balancePostSend < valueFromBitcoind) assert( - WalletTestUtil.isCloseEnough(balancePostSend, - valueFromBitcoind - valueToBitcoind, - delta = outgoingTx.get.actualFee)) + WalletTestUtil.isCloseEnough( + balancePostSend, + valueFromBitcoind - valueToBitcoind, + delta = outgoingTx.get.actualFee + ) + ) assert(tx.confirmations.exists(_ > 0)) } } @@ -201,7 +206,8 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { // After replacement tx is broadcast, old tx should be gone _ <- recoverToSucceededIf[InvalidAddressOrKey]( - bitcoind.getRawTransaction(tx1.txIdBE)) + bitcoind.getRawTransaction(tx1.txIdBE) + ) // Check we didn't send extra to bitcoind bitcoindBal2 <- bitcoind.getUnconfirmedBalance @@ -316,7 +322,8 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { // Assert we mined to our address coinbaseTx = block.transactions.head _ = assert( - coinbaseTx.outputs.exists(_.scriptPubKey == addr.scriptPubKey)) + coinbaseTx.outputs.exists(_.scriptPubKey == addr.scriptPubKey) + ) _ <- wallet.processBlock(block) @@ -330,7 +337,8 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { // Attempt to spend utxo _ <- recoverToSucceededIf[RuntimeException]( - wallet.sendToAddress(bitcoindAddr, valueToBitcoind, None)) + wallet.sendToAddress(bitcoindAddr, valueToBitcoind, None) + ) spendingTx = { val inputs = utxos.map { db => @@ -342,7 +350,8 @@ class WalletIntegrationTest extends BitcoinSWalletTestCachedBitcoindNewest { } _ <- recoverToSucceededIf[RuntimeException]( - wallet.processTransaction(spendingTx, None)) + wallet.processTransaction(spendingTx, None) + ) // Make coinbase mature _ <- bitcoind.generateToAddress(101, bitcoindAddr) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletSendingTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletSendingTest.scala index d5f4423758..dd04e728cc 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletSendingTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletSendingTest.scala @@ -43,7 +43,9 @@ class WalletSendingTest extends BitcoinSWalletTest { } yield { assert( tx.outputs.contains( - TransactionOutput(amountToSend, testAddress.scriptPubKey))) + TransactionOutput(amountToSend, testAddress.scriptPubKey) + ) + ) } } @@ -110,12 +112,15 @@ class WalletSendingTest extends BitcoinSWalletTest { def testOpReturnCommitment( wallet: Wallet, - hashMessage: Boolean): Future[Assertion] = { + hashMessage: Boolean + ): Future[Assertion] = { val message = "ben was here" for { - tx <- wallet.makeOpReturnCommitment(message = message, - hashMessage = hashMessage, - feeRateOpt = None) + tx <- wallet.makeOpReturnCommitment( + message = message, + hashMessage = hashMessage, + feeRateOpt = None + ) outgoingTxDbOpt <- wallet.outgoingTxDAO.read(tx.txIdBE) } yield { @@ -130,9 +135,11 @@ class WalletSendingTest extends BitcoinSWalletTest { } val expectedAsm = - Seq(OP_RETURN, - BytesToPushOntoStack(messageBytes.size), - ScriptConstant(messageBytes)) + Seq( + OP_RETURN, + BytesToPushOntoStack(messageBytes.size), + ScriptConstant(messageBytes) + ) assert(opReturnOutput.scriptPubKey.asm == expectedAsm) @@ -142,7 +149,8 @@ class WalletSendingTest extends BitcoinSWalletTest { assert(outgoingTxDb.sentAmount == 0.satoshis) val changeOutput = tx.outputs.find(_.value > 0.satoshis).get assert( - outgoingTxDb.actualFee + changeOutput.value == outgoingTxDb.inputAmount) + outgoingTxDb.actualFee + changeOutput.value == outgoingTxDb.inputAmount + ) } } @@ -162,16 +170,19 @@ class WalletSendingTest extends BitcoinSWalletTest { wallet.makeOpReturnCommitment( "This message is much too long and is over 80 bytes, the limit for OP_RETURN. It should cause an error.", hashMessage = false, - None) + None + ) } } it should "fail to send to a different network address" in { fundedWallet => val wallet = fundedWallet.wallet val sendToAddressesF = - wallet.sendToAddress(BitcoinAddress("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"), - Satoshis(1000), - None) + wallet.sendToAddress( + BitcoinAddress("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"), + Satoshis(1000), + None + ) recoverToSucceededIf[IllegalArgumentException] { sendToAddressesF @@ -203,15 +214,19 @@ class WalletSendingTest extends BitcoinSWalletTest { outPoints = allOutPoints.drop(allOutPoints.size / 2) tx <- wallet.sendFromOutPoints(outPoints, testAddress, amountToSend, None) } yield { - assert(outPoints.forall(outPoint => - tx.inputs.exists(_.previousOutput == outPoint)), - "Every outpoint was not included included") + assert( + outPoints.forall(outPoint => + tx.inputs.exists(_.previousOutput == outPoint)), + "Every outpoint was not included included" + ) assert(tx.inputs.size == outPoints.size, "An extra input was added") val expectedOutput = TransactionOutput(amountToSend, testAddress.scriptPubKey) - assert(tx.outputs.contains(expectedOutput), - "Did not contain expected output") + assert( + tx.outputs.contains(expectedOutput), + "Did not contain expected output" + ) } } @@ -226,9 +241,11 @@ class WalletSendingTest extends BitcoinSWalletTest { } yield { val expectedFeeRate = wallet.feeRateApi.asInstanceOf[RandomFeeProvider].lastFeeRate.get - assert(outPoints.forall(outPoint => - tx.inputs.exists(_.previousOutput == outPoint)), - "Every outpoint was not included included") + assert( + outPoints.forall(outPoint => + tx.inputs.exists(_.previousOutput == outPoint)), + "Every outpoint was not included included" + ) assert(tx.inputs.size == outPoints.size, "An extra input was added") val inputAmount = utxos.map(_.output.value).sum @@ -275,7 +292,8 @@ class WalletSendingTest extends BitcoinSWalletTest { utxos .map(_.outPoint) .forall(outPoint => tx.inputs.exists(_.previousOutput == outPoint)), - "Every outpoint was not included included") + "Every outpoint was not included included" + ) assert(tx.inputs.size == utxos.size, "An extra input was added") val inputAmount = utxos.map(_.output.value).sum @@ -359,9 +377,11 @@ class WalletSendingTest extends BitcoinSWalletTest { utxo <- wallet.listUtxos().map(_.head) // Create tx not signaling RBF - input = TransactionInput(utxo.outPoint, - EmptyScriptSignature, - TransactionConstants.disableRBFSequence) + input = TransactionInput( + utxo.outPoint, + EmptyScriptSignature, + TransactionConstants.disableRBFSequence + ) output = TransactionOutput(utxo.output.value - Satoshis(500), addr.scriptPubKey) tx = @@ -435,7 +455,8 @@ class WalletSendingTest extends BitcoinSWalletTest { val wallet = fundedWallet.wallet recoverToSucceededIf[RuntimeException]( - wallet.bumpFeeCPFP(EmptyTransaction.txIdBE, SatoshisPerByte.one)) + wallet.bumpFeeCPFP(EmptyTransaction.txIdBE, SatoshisPerByte.one) + ) } it should "fail to send from outpoints when already spent" in { @@ -451,16 +472,20 @@ class WalletSendingTest extends BitcoinSWalletTest { .copyWithState(TxoState.PendingConfirmationsSpent) _ <- wallet.spendingInfoDAO.update(spent) test <- recoverToSucceededIf[IllegalArgumentException]( - wallet.sendFromOutPoints(allUtxos.map(_.outPoint), - testAddress, - amountToSend, - None)) + wallet.sendFromOutPoints( + allUtxos.map(_.outPoint), + testAddress, + amountToSend, + None + ) + ) } yield test } def testSendWithAlgo( wallet: Wallet, - algo: CoinSelectionAlgo): Future[Assertion] = { + algo: CoinSelectionAlgo + ): Future[Assertion] = { for { account <- wallet.getDefaultAccount() feeRate <- wallet.getFeeRate() @@ -479,8 +504,10 @@ class WalletSendingTest extends BitcoinSWalletTest { val expectedOutput = TransactionOutput(amountToSend, testAddress.scriptPubKey) - assert(tx.outputs.contains(expectedOutput), - "Did not contain expected output") + assert( + tx.outputs.contains(expectedOutput), + "Did not contain expected output" + ) } } @@ -489,8 +516,10 @@ class WalletSendingTest extends BitcoinSWalletTest { } it should "correctly send with accumulate smallest" in { fundedWallet => - testSendWithAlgo(fundedWallet.wallet, - CoinSelectionAlgo.AccumulateSmallestViable) + testSendWithAlgo( + fundedWallet.wallet, + CoinSelectionAlgo.AccumulateSmallestViable + ) } it should "correctly send with standard accumulate" in { fundedWallet => @@ -499,7 +528,7 @@ class WalletSendingTest extends BitcoinSWalletTest { it must "it must not double spend utxos used to fund other txs in the wallet" in { fundedWallet => - //i expected an error saying insufficient balance + // i expected an error saying insufficient balance val addr1F = fundedWallet.wallet.getNewAddress() val addr2F = fundedWallet.wallet.getNewAddress() @@ -513,10 +542,10 @@ class WalletSendingTest extends BitcoinSWalletTest { 500000 ) // for fee, fee rates are random so we might need a lot - //build these transactions in parallel intentionally + // build these transactions in parallel intentionally tx1F = fundedWallet.wallet.sendToAddress(addr1, amt, None) tx2F = fundedWallet.wallet.sendToAddress(addr2, amt, None) - //one of these should fail because we don't have enough money + // one of these should fail because we don't have enough money _ <- tx1F _ <- tx2F } yield () @@ -525,8 +554,11 @@ class WalletSendingTest extends BitcoinSWalletTest { recoverToExceptionIf[RuntimeException](failedTx) exnF.map(err => - assert(err.getMessage.contains( - "Not enough value in given outputs to make transaction spending 599500000 sats plus fees"))) + assert( + err.getMessage.contains( + "Not enough value in given outputs to make transaction spending 599500000 sats plus fees" + ) + )) } } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala index 1a88fa1d1b..c25a82cc79 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala @@ -59,7 +59,8 @@ class WalletUnitTest extends BitcoinSWalletTest { it should "know what the last address index is" in { wallet => def getMostRecent( hdAccount: HDAccount, - chain: HDChainType): Future[AddressDb] = { + chain: HDChainType + ): Future[AddressDb] = { val recentOptFut: Future[Option[AddressDb]] = chain match { case Change => wallet.addressDAO.findMostRecentChange(hdAccount) @@ -76,7 +77,8 @@ class WalletUnitTest extends BitcoinSWalletTest { def assertIndexIs( hdAccount: HDAccount, chain: HDChainType, - addrIndex: Int): Future[Assertion] = { + addrIndex: Int + ): Future[Assertion] = { getMostRecent(hdAccount, chain) map { addr => assert(addr.path.address.index == addrIndex) } @@ -90,7 +92,8 @@ class WalletUnitTest extends BitcoinSWalletTest { */ def testChain( hdAccount: HDAccount, - chain: HDChainType): Future[Assertion] = { + chain: HDChainType + ): Future[Assertion] = { val getAddrFunc: () => Future[BitcoinAddress] = chain match { case Change => wallet.getNewChangeAddress _ case External => wallet.getNewAddress _ @@ -106,7 +109,8 @@ class WalletUnitTest extends BitcoinSWalletTest { addrF.map { case Some(addr) => fail( - s"Found ${addr.address} $chain address although there was no previous addreses generated") + s"Found ${addr.address} $chain address although there was no previous addreses generated" + ) case None => } } @@ -130,21 +134,27 @@ class WalletUnitTest extends BitcoinSWalletTest { it should "match block filters" in { wallet: Wallet => for { height <- wallet.chainQueryApi.getFilterCount() - filtersResponse <- chainQueryApi.getFiltersBetweenHeights(startHeight = 0, - endHeight = - height) + filtersResponse <- chainQueryApi.getFiltersBetweenHeights( + startHeight = 0, + endHeight = height + ) matched <- wallet.findMatches( filters = filtersResponse, scripts = Vector( // this is a random address which is included into the test block - BitcoinAddress("n1RH2x3b3ah4TGQtgrmNAHfmad9wr8U2QY").scriptPubKey), + BitcoinAddress("n1RH2x3b3ah4TGQtgrmNAHfmad9wr8U2QY").scriptPubKey + ), parallelismLevel = 1 ) } yield { assert( Vector( - BlockMatchingResponse(blockHash = MockChainQueryApi.testBlockHash, - blockHeight = 1)) == matched) + BlockMatchingResponse( + blockHash = MockChainQueryApi.testBlockHash, + blockHeight = 1 + ) + ) == matched + ) } } @@ -168,27 +178,30 @@ class WalletUnitTest extends BitcoinSWalletTest { Wallet .initialize(wallet, bip39PasswordOpt) .flatMap { _ => - //use a BIP39 password to make the key-managers different + // use a BIP39 password to make the key-managers different Wallet.initialize( wallet, - Some("random-password-to-make-key-managers-different")) + Some("random-password-to-make-key-managers-different") + ) } } } it must "be able to detect different master xpubs on wallet startup" in { wallet: Wallet => - //create new config with different entropy - //to make the keymanagers differetn + // create new config with different entropy + // to make the keymanagers differetn val config = ConfigFactory.parseString( - s"bitcoin-s.keymanager.entropy=${CryptoUtil.randomBytes(16).toHex}") + s"bitcoin-s.keymanager.entropy=${CryptoUtil.randomBytes(16).toHex}" + ) val uniqueEntropyWalletConfig = wallet.walletConfig.withOverrides(config) val startedF = uniqueEntropyWalletConfig.start() val walletDiffKeyManagerF: Future[Wallet] = for { _ <- startedF } yield { Wallet(wallet.nodeApi, wallet.chainQueryApi, wallet.feeRateApi)( - uniqueEntropyWalletConfig) + uniqueEntropyWalletConfig + ) } recoverToSucceededIf[IllegalArgumentException] { @@ -221,7 +234,8 @@ class WalletUnitTest extends BitcoinSWalletTest { assert(signed != psbt) assert( signed.inputMaps.head.partialSignatures - .exists(_.pubKey.toPublicKey == walletKey)) + .exists(_.pubKey.toPublicKey == walletKey) + ) } } @@ -244,7 +258,8 @@ class WalletUnitTest extends BitcoinSWalletTest { assert(signed != psbt) assert( signed.inputMaps.head.partialSignatures - .exists(_.pubKey.toPublicKey == walletKey)) + .exists(_.pubKey.toPublicKey == walletKey) + ) } } @@ -267,7 +282,8 @@ class WalletUnitTest extends BitcoinSWalletTest { assert(signed != psbt) assert( signed.inputMaps.head.partialSignatures - .exists(_.pubKey.toPublicKey == walletKey)) + .exists(_.pubKey.toPublicKey == walletKey) + ) } } @@ -291,7 +307,8 @@ class WalletUnitTest extends BitcoinSWalletTest { assert(signed != psbt) assert( signed.inputMaps.head.partialSignatures - .exists(_.pubKey.toPublicKey == walletKey)) + .exists(_.pubKey.toPublicKey == walletKey) + ) } } @@ -325,24 +342,24 @@ class WalletUnitTest extends BitcoinSWalletTest { for { isEmpty <- wallet.isEmpty() _ = assert(isEmpty) - //manually override the seeds creation time + // manually override the seeds creation time seedPath = wallet.walletConfig.kmConf.seedPath mnemonic = WalletStorage .decryptSeedFromDisk(seedPath = seedPath, passphraseOpt = None) .getOrElse(sys.error(s"failed to decrypt seed for unit test")) .asInstanceOf[DecryptedMnemonic] _ = { - //delete old seed file because we do not allow overwriting a seed file + // delete old seed file because we do not allow overwriting a seed file Files.delete(wallet.walletConfig.seedPath) } modifiedMnemonic = mnemonic.copy(creationTime = - Instant.now.minusSeconds(60 * 60 + 1)) //1 hour and 1 minute + Instant.now.minusSeconds(60 * 60 + 1)) // 1 hour and 1 minute _ = WalletStorage.writeSeedToDisk(seedPath, modifiedMnemonic) - //delete old wallet database + // delete old wallet database _ = { if (pgEnabled) { - //cannot delete database file if using postgres + // cannot delete database file if using postgres () } else { val path = wallet.walletConfig.datadir @@ -353,10 +370,11 @@ class WalletUnitTest extends BitcoinSWalletTest { } _ = wallet.walletConfig.migrate() - //initialize it + // initialize it initOldWallet <- Wallet.initialize( wallet = wallet, - bip39PasswordOpt = wallet.walletConfig.bip39PasswordOpt) + bip39PasswordOpt = wallet.walletConfig.bip39PasswordOpt + ) isOldWalletEmpty <- initOldWallet.isEmpty() } yield assert(!isOldWalletEmpty) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/models/AddressDAOTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/models/AddressDAOTest.scala index 59a09c7ef8..42d807f4f8 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/models/AddressDAOTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/models/AddressDAOTest.scala @@ -24,10 +24,14 @@ class AddressDAOTest extends WalletDAOFixture { it should "preserve public key scripts" in { daos => val addressDAO = daos.addressDAO - val addr1 = WalletTestUtil.getAddressDb(WalletTestUtil.firstAccountDb, - addressIndex = 0) - val addr2 = WalletTestUtil.getAddressDb(WalletTestUtil.firstAccountDb, - addressIndex = 1) + val addr1 = WalletTestUtil.getAddressDb( + WalletTestUtil.firstAccountDb, + addressIndex = 0 + ) + val addr2 = WalletTestUtil.getAddressDb( + WalletTestUtil.firstAccountDb, + addressIndex = 1 + ) assert(addr1.scriptPubKey != addr2.scriptPubKey) for { @@ -39,7 +43,9 @@ class AddressDAOTest extends WalletDAOFixture { assert(addr2 == created2) assert( Vector(addr1, addr2).sortBy(_.address.toString) == found.sortBy( - _.address.toString)) + _.address.toString + ) + ) } } @@ -73,10 +79,14 @@ class AddressDAOTest extends WalletDAOFixture { val addressDAO = daos.addressDAO val addr1 = WalletTestUtil.getAddressDb(WalletTestUtil.firstAccountDb) - val addr2 = WalletTestUtil.getAddressDb(WalletTestUtil.firstAccountDb, - addressIndex = 1) - val addr3 = WalletTestUtil.getAddressDb(WalletTestUtil.firstAccountDb, - addressIndex = 2) + val addr2 = WalletTestUtil.getAddressDb( + WalletTestUtil.firstAccountDb, + addressIndex = 1 + ) + val addr3 = WalletTestUtil.getAddressDb( + WalletTestUtil.firstAccountDb, + addressIndex = 2 + ) val spks = Vector(addr1.scriptPubKey, addr2.scriptPubKey) for { @@ -98,24 +108,26 @@ class AddressDAOTest extends WalletDAOFixture { val addrStr = "bc1qfjex5a4m5w0atqrpwad3zj4vkfkuhun46tge9c" val address = Bech32Address.fromString(addrStr) val spk = address.scriptPubKey.asInstanceOf[P2WPKHWitnessSPKV0] - //insert the script first + // insert the script first val spkDb = ScriptPubKeyDb(address.scriptPubKey) val createdSpkF = spkDAO.create(spkDb) - //now try to insert the address in the database + // now try to insert the address in the database val segwitHdPath: SegWitHDPath = SegWitHDPath.fromString("m/84'/0'/0'/0/0") val pubKey: ECPublicKey = ECPublicKey.freshPublicKey - val addressDb = SegWitAddressDb.apply(segwitHdPath, - pubKey, - spk.pubKeyHash, - address, - EmptyScriptWitness, - spk) + val addressDb = SegWitAddressDb.apply( + segwitHdPath, + pubKey, + spk.pubKeyHash, + address, + EmptyScriptWitness, + spk + ) for { createdSpk <- createdSpkF _ <- addressDAO.create(addressDb) - //make sure we can find it now + // make sure we can find it now foundOpt <- addressDAO.read(address) } yield { assert(foundOpt.isDefined) @@ -131,24 +143,26 @@ class AddressDAOTest extends WalletDAOFixture { val addrStr = "bc1qfjex5a4m5w0atqrpwad3zj4vkfkuhun46tge9c" val address = Bech32Address.fromString(addrStr) val spk = address.scriptPubKey.asInstanceOf[P2WPKHWitnessSPKV0] - //insert the script first + // insert the script first val spkDb = ScriptPubKeyDb(address.scriptPubKey) val createdSpkF = spkDAO.create(spkDb) - //now try to insert the address in the database + // now try to insert the address in the database val segwitHdPath: SegWitHDPath = SegWitHDPath.fromString("m/84'/0'/0'/0/0") val pubKey: ECPublicKey = ECPublicKey.freshPublicKey - val addressDb = SegWitAddressDb.apply(segwitHdPath, - pubKey, - spk.pubKeyHash, - address, - EmptyScriptWitness, - spk) + val addressDb = SegWitAddressDb.apply( + segwitHdPath, + pubKey, + spk.pubKeyHash, + address, + EmptyScriptWitness, + spk + ) for { createdSpk <- createdSpkF _ <- addressDAO.upsert(addressDb) - //make sure we can find it now + // make sure we can find it now foundOpt <- addressDAO.read(address) } yield { assert(foundOpt.isDefined) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/models/AddressTagDAOTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/models/AddressTagDAOTest.scala index f0fae9df2e..bb293cc393 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/models/AddressTagDAOTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/models/AddressTagDAOTest.scala @@ -21,12 +21,15 @@ class AddressTagDAOTest extends WalletDAOFixture { behavior of "AddressTagDAO" val exampleTag: UnknownAddressTag = - UnknownAddressTag(UnknownAddressTagName("Example"), - UnknownAddressTagType("ExampleTagType")) + UnknownAddressTag( + UnknownAddressTagName("Example"), + UnknownAddressTagType("ExampleTagType") + ) def testInsertionFailure( daos: FixtureParam, - tag: AddressTag): Future[Assertion] = { + tag: AddressTag + ): Future[Assertion] = { val tagDAO = daos.addressTagDAO val addr = TestUtil.testBitcoinAddress val tagDb = AddressTagDb(addr, tag.tagName, tag.tagType) @@ -102,8 +105,10 @@ class AddressTagDAOTest extends WalletDAOFixture { AddressTagDb(createdAddress.address, exampleTag) addressTagDAO.create(tagDb) } - dropped <- addressTagDAO.dropByAddressAndName(createdAddress.address, - createdAddressTag.tagName) + dropped <- addressTagDAO.dropByAddressAndName( + createdAddress.address, + createdAddressTag.tagName + ) } yield { assert(dropped == 1) } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/models/IncomingTransactionDAOTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/models/IncomingTransactionDAOTest.scala index 573e120d8e..ddb8bffdca 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/models/IncomingTransactionDAOTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/models/IncomingTransactionDAOTest.scala @@ -9,12 +9,16 @@ import org.bitcoins.testkit.wallet.WalletTestUtil class IncomingTransactionDAOTest extends WalletDAOFixture { val txDb: TransactionDb = - TransactionDbHelper.fromTransaction(WalletTestUtil.sampleTransaction, - Some(DoubleSha256DigestBE.empty)) + TransactionDbHelper.fromTransaction( + WalletTestUtil.sampleTransaction, + Some(DoubleSha256DigestBE.empty) + ) val incoming: IncomingTransactionDb = - IncomingTransactionDb(WalletTestUtil.sampleTransaction.txIdBE, - Satoshis(10000)) + IncomingTransactionDb( + WalletTestUtil.sampleTransaction.txIdBE, + Satoshis(10000) + ) it should "insert and read an transaction into the database" in { daos => val txDAO = daos.transactionDAO diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/models/OutgoingTransactionDAOTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/models/OutgoingTransactionDAOTest.scala index cca146ab0b..9696102bd9 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/models/OutgoingTransactionDAOTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/models/OutgoingTransactionDAOTest.scala @@ -9,14 +9,17 @@ import org.bitcoins.testkit.wallet.WalletTestUtil class OutgoingTransactionDAOTest extends WalletDAOFixture { val txDb: TransactionDb = - TransactionDbHelper.fromTransaction(WalletTestUtil.sampleTransaction, - Some(DoubleSha256DigestBE.empty)) + TransactionDbHelper.fromTransaction( + WalletTestUtil.sampleTransaction, + Some(DoubleSha256DigestBE.empty) + ) val outgoing: OutgoingTransactionDb = OutgoingTransactionDb.fromTransaction( WalletTestUtil.sampleTransaction, Satoshis(250000000), WalletTestUtil.sampleTransaction.outputs.head.value, - Satoshis(10000)) + Satoshis(10000) + ) it should "insert and read an transaction into the database" in { daos => val txDAO = daos.transactionDAO diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/models/ScriptPubKeyDAOTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/models/ScriptPubKeyDAOTest.scala index cfac541745..023a5df51d 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/models/ScriptPubKeyDAOTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/models/ScriptPubKeyDAOTest.scala @@ -18,7 +18,8 @@ class ScriptPubKeyDAOTest extends WalletDAOFixture { val multisig = MultiSignatureScriptPubKey( 2, - Vector(ECPublicKey.freshPublicKey, ECPublicKey.freshPublicKey)) + Vector(ECPublicKey.freshPublicKey, ECPublicKey.freshPublicKey) + ) val pkh = P2PKHScriptPubKey(ECPublicKey.freshPublicKey) @@ -39,15 +40,19 @@ class ScriptPubKeyDAOTest extends WalletDAOFixture { NonStandardIfConditionalScriptPubKey(raw1, raw2), MultiSignatureWithTimeoutScriptPubKey(multisig, cltv), NonStandardNotIfConditionalScriptPubKey(raw1, raw2), - P2PKWithTimeoutScriptPubKey(ECPublicKey.freshPublicKey, - ScriptNumber.one, - ECPublicKey.freshPublicKey), + P2PKWithTimeoutScriptPubKey( + ECPublicKey.freshPublicKey, + ScriptNumber.one, + ECPublicKey.freshPublicKey + ), NonStandardScriptPubKey(Seq(OP_NOP)), P2WPKHWitnessSPKV0(ECPublicKey.freshPublicKey), P2WSHWitnessSPKV0(pkh), WitnessCommitment( DoubleSha256Digest( - "0000000000000000000000000000000000000000000000000000000000000000")) + "0000000000000000000000000000000000000000000000000000000000000000" + ) + ) ).map(spk => ScriptPubKeyDb(spk)) for { @@ -110,7 +115,8 @@ class ScriptPubKeyDAOTest extends WalletDAOFixture { val multisig = MultiSignatureScriptPubKey( 2, - Vector(ECPublicKey.freshPublicKey, ECPublicKey.freshPublicKey)) + Vector(ECPublicKey.freshPublicKey, ECPublicKey.freshPublicKey) + ) val pkh = P2PKHScriptPubKey(ECPublicKey.freshPublicKey) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/models/SpendingInfoDAOTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/models/SpendingInfoDAOTest.scala index dc9424e366..ba340f76f6 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/models/SpendingInfoDAOTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/models/SpendingInfoDAOTest.scala @@ -31,29 +31,38 @@ class SpendingInfoDAOTest extends WalletDAOFixture { val addressDAO = daos.addressDAO val spendingInfoDAO = daos.utxoDAO - val addr1 = WalletTestUtil.getAddressDb(WalletTestUtil.firstAccountDb, - addressIndex = 0) - val addr2 = WalletTestUtil.getAddressDb(WalletTestUtil.firstAccountDb, - addressIndex = 1) + val addr1 = WalletTestUtil.getAddressDb( + WalletTestUtil.firstAccountDb, + addressIndex = 0 + ) + val addr2 = WalletTestUtil.getAddressDb( + WalletTestUtil.firstAccountDb, + addressIndex = 1 + ) assert(addr1.scriptPubKey != addr2.scriptPubKey) for { createdAddr1 <- addressDAO.create(addr1) createdAddr2 <- addressDAO.create(addr2) - u1 = sampleLegacyUTXO(addr1.scriptPubKey, - state = TxoState.BroadcastReceived) + u1 = sampleLegacyUTXO( + addr1.scriptPubKey, + state = TxoState.BroadcastReceived + ) _ <- insertDummyIncomingTransaction(daos, u1) utxo1 <- daos.utxoDAO.create(u1) - u2 = WalletTestUtil.sampleSegwitUTXO(addr2.scriptPubKey, - state = TxoState.BroadcastReceived) + u2 = WalletTestUtil.sampleSegwitUTXO( + addr2.scriptPubKey, + state = TxoState.BroadcastReceived + ) _ <- insertDummyIncomingTransaction(daos, u2) utxo2 <- daos.utxoDAO.create(u2) utxos = Vector(utxo1, utxo2) changed = utxos.map( - _.copyWithState(TxoState.PendingConfirmationsReceived)) + _.copyWithState(TxoState.PendingConfirmationsReceived) + ) updated <- spendingInfoDAO.updateAllSpendingInfoDb(changed) } yield { assert(updated == changed) @@ -72,14 +81,17 @@ class SpendingInfoDAOTest extends WalletDAOFixture { account <- daos.accountDAO.create(WalletTestUtil.firstAccountDb) addr <- addressDAO.create(getAddressDb(account)) - u1 = sampleLegacyUTXO(addr.scriptPubKey, - state = TxoState.PendingConfirmationsReceived) + u1 = sampleLegacyUTXO( + addr.scriptPubKey, + state = TxoState.PendingConfirmationsReceived + ) _ <- insertDummyIncomingTransaction(daos, u1) utxo1 <- daos.utxoDAO.create(u1) u2 = WalletTestUtil.sampleSegwitUTXO( addr.scriptPubKey, - state = TxoState.PendingConfirmationsReceived) + state = TxoState.PendingConfirmationsReceived + ) _ <- insertDummyIncomingTransaction(daos, u2) utxo2 <- daos.utxoDAO.create(u2) @@ -95,13 +107,14 @@ class SpendingInfoDAOTest extends WalletDAOFixture { for { created <- WalletTestUtil.insertSegWitUTXO( daos = daos, - state = TxoState.PendingConfirmationsReceived) + state = TxoState.PendingConfirmationsReceived + ) spk = created.output.scriptPubKey read <- utxoDAO.read(created.id.get).map(_.map(_.toSpendingInfoDb(spk))) } yield read match { case None => fail(s"Did not read back a UTXO") case Some(_: SegwitV0SpendingInfo) => succeed - case Some(other) => fail(s"did not get segwit UTXO: $other") + case Some(other) => fail(s"did not get segwit UTXO: $other") } } @@ -110,13 +123,14 @@ class SpendingInfoDAOTest extends WalletDAOFixture { for { created <- WalletTestUtil.insertLegacyUTXO( daos, - state = TxoState.PendingConfirmationsReceived) + state = TxoState.PendingConfirmationsReceived + ) spk = created.output.scriptPubKey read <- utxoDAO.read(created.id.get).map(_.map(_.toSpendingInfoDb(spk))) } yield read match { case None => fail(s"Did not read back a UTXO") case Some(_: LegacySpendingInfo) => succeed - case Some(other) => fail(s"did not get a legacy UTXO: $other") + case Some(other) => fail(s"did not get a legacy UTXO: $other") } } @@ -124,9 +138,10 @@ class SpendingInfoDAOTest extends WalletDAOFixture { val utxoDAO = daos.utxoDAO for { - utxo <- WalletTestUtil.insertLegacyUTXO(daos, - state = - TxoState.ConfirmedReceived) + utxo <- WalletTestUtil.insertLegacyUTXO( + daos, + state = TxoState.ConfirmedReceived + ) transaction = { val randomTX = TransactionGenerators.transaction .suchThat(_.inputs.nonEmpty) @@ -135,17 +150,21 @@ class SpendingInfoDAOTest extends WalletDAOFixture { val inputs = { val head = randomTX.inputs.head val ourInput = - TransactionInput(utxo.outPoint, - ScriptSignature.empty, - head.sequence) + TransactionInput( + utxo.outPoint, + ScriptSignature.empty, + head.sequence + ) ourInput +: randomTX.inputs.tail } - BaseTransaction(randomTX.version, - inputs = inputs, - outputs = randomTX.outputs, - lockTime = randomTX.lockTime) + BaseTransaction( + randomTX.version, + inputs = inputs, + outputs = randomTX.outputs, + lockTime = randomTX.lockTime + ) } txos <- utxoDAO.findOutputsBeingSpent(transaction) @@ -159,9 +178,10 @@ class SpendingInfoDAOTest extends WalletDAOFixture { it must "insert an unspent TXO and find it as unspent" in { daos => val spendingInfoDAO = daos.utxoDAO for { - utxo <- WalletTestUtil.insertLegacyUTXO(daos, - state = - TxoState.ConfirmedReceived) + utxo <- WalletTestUtil.insertLegacyUTXO( + daos, + state = TxoState.ConfirmedReceived + ) state = utxo.copy(state = TxoState.PendingConfirmationsReceived) updated <- spendingInfoDAO.update(state) unspent <- spendingInfoDAO.findAllUnspent() @@ -176,9 +196,10 @@ class SpendingInfoDAOTest extends WalletDAOFixture { it must "insert a spent TXO and NOT find it as unspent" in { daos => val spendingInfoDAO = daos.utxoDAO for { - utxo <- WalletTestUtil.insertLegacyUTXO(daos = daos, - state = - TxoState.ConfirmedReceived) + utxo <- WalletTestUtil.insertLegacyUTXO( + daos = daos, + state = TxoState.ConfirmedReceived + ) state = utxo .copy(spendingTxIdOpt = Some(randomTXID)) .copy(state = TxoState.PendingConfirmationsSpent) @@ -193,11 +214,15 @@ class SpendingInfoDAOTest extends WalletDAOFixture { for { utxo <- WalletTestUtil.insertLegacyUTXO( daos, - state = TxoState.PendingConfirmationsReceived) - utxo2 <- WalletTestUtil.insertLegacyUTXO(daos, - state = TxoState.BroadcastSpent) + state = TxoState.PendingConfirmationsReceived + ) + utxo2 <- WalletTestUtil.insertLegacyUTXO( + daos, + state = TxoState.BroadcastSpent + ) foundTxos <- spendingInfoDAO.findOutputsReceived( - Vector(utxo.txid, utxo2.txid)) + Vector(utxo.txid, utxo2.txid) + ) } yield { assert(foundTxos.length == 1) assert(foundTxos.contains(utxo)) @@ -210,13 +235,14 @@ class SpendingInfoDAOTest extends WalletDAOFixture { for { created <- WalletTestUtil.insertNestedSegWitUTXO( daos, - state = TxoState.PendingConfirmationsReceived) + state = TxoState.PendingConfirmationsReceived + ) spk = created.output.scriptPubKey read <- utxoDAO.read(created.id.get).map(_.map(_.toSpendingInfoDb(spk))) } yield read match { - case None => fail(s"Did not read back a UTXO") + case None => fail(s"Did not read back a UTXO") case Some(_: NestedSegwitV0SpendingInfo) => succeed - case Some(other) => fail(s"did not get a nested segwit UTXO: $other") + case Some(other) => fail(s"did not get a nested segwit UTXO: $other") } } @@ -226,15 +252,18 @@ class SpendingInfoDAOTest extends WalletDAOFixture { for { created <- WalletTestUtil.insertNestedSegWitUTXO( daos, - state = TxoState.ConfirmedReceived) + state = TxoState.ConfirmedReceived + ) db <- utxoDAO.read(created.id.get) account <- daos.accountDAO.create(WalletTestUtil.firstAccountDb) addr <- daos.addressDAO.create(getAddressDb(account)) // Add another utxo - u2 = WalletTestUtil.sampleSegwitUTXO(addr.scriptPubKey, - state = TxoState.ConfirmedReceived) + u2 = WalletTestUtil.sampleSegwitUTXO( + addr.scriptPubKey, + state = TxoState.ConfirmedReceived + ) _ <- insertDummyIncomingTransaction(daos, u2) _ <- utxoDAO.create(u2) diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/sync/WalletSyncTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/sync/WalletSyncTest.scala index 691f9bad34..3a4d75a85b 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/sync/WalletSyncTest.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/sync/WalletSyncTest.scala @@ -16,7 +16,7 @@ class WalletSyncTest extends BitcoinSWalletTestCachedBitcoindNewest { val wallet = param.wallet val bitcoind = param.bitcoind val genesisBlockHashF = bitcoind.getBlockHash(0) - //first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions + // first we need to implement the 'getBestBlockHashFunc' and 'getBlockHeaderFunc' functions val getBestBlockHashFunc = SyncUtil.getBestBlockHashFunc(bitcoind) val getBlockHeaderFunc = SyncUtil.getBlockHeaderFunc(bitcoind) @@ -25,11 +25,13 @@ class WalletSyncTest extends BitcoinSWalletTestCachedBitcoindNewest { val syncedWalletF = { for { genesisBlockHash <- genesisBlockHashF - synced <- WalletSync.syncFullBlocks(wallet, - getBlockHeaderFunc, - getBestBlockHashFunc, - getBlockFunc, - genesisBlockHash) + synced <- WalletSync.syncFullBlocks( + wallet, + getBlockHeaderFunc, + getBestBlockHashFunc, + getBlockFunc, + genesisBlockHash + ) } yield synced } diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/util/GetAddresses.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/util/GetAddresses.scala index 12cf301665..cac4b07f36 100644 --- a/wallet-test/src/test/scala/org/bitcoins/wallet/util/GetAddresses.scala +++ b/wallet-test/src/test/scala/org/bitcoins/wallet/util/GetAddresses.scala @@ -5,20 +5,17 @@ import play.api.libs.json._ import scala.sys.process._ -/** This program connects to a running Trezor, and gets - * xpubs and addresses from legacy, segwit and nested - * segwit accounts for mainnet. The intention here was - * to also do this for testnet, but for some reason - * my emulator refuses to work when specifying a - * testnet BIP32 path. Something to look into in the +/** This program connects to a running Trezor, and gets xpubs and addresses from + * legacy, segwit and nested segwit accounts for mainnet. The intention here + * was to also do this for testnet, but for some reason my emulator refuses to + * work when specifying a testnet BIP32 path. Something to look into in the * future. * - * To replicate this: - * 1) Boot up a Trezor emulator (https://github.com/trezor/trezor-firmware/blob/master/core/docs/emulator.md) - * 2) Run Trezor bridge (instructions in link above) - * 3) Go to trezor.io/start, restore wallet from seed - * 4) Leave emulator open - * 5) Run this program. Result gets printed to stdout. + * To replicate this: 1) Boot up a Trezor emulator + * (https://github.com/trezor/trezor-firmware/blob/master/core/docs/emulator.md) + * 2) Run Trezor bridge (instructions in link above) 3) Go to trezor.io/start, + * restore wallet from seed 4) Leave emulator open 5) Run this program. Result + * gets printed to stdout. */ object GetAddresses extends App { @@ -47,7 +44,7 @@ object GetAddresses extends App { case HDPurposes.Legacy => "legacy" case HDPurposes.NestedSegWit => "p2sh-segwit" case HDPurposes.SegWit => "segwit" - case other => throw new RuntimeException(s"Unexpected purpose $other") + case other => throw new RuntimeException(s"Unexpected purpose $other") } val trezorPathType = @@ -55,7 +52,7 @@ object GetAddresses extends App { case HDPurposes.Legacy => "address" case HDPurposes.NestedSegWit => "p2shsegwit" case HDPurposes.SegWit => "segwit" - case other => throw new RuntimeException(s"Unexpected purpose $other") + case other => throw new RuntimeException(s"Unexpected purpose $other") } val xpubCmd = diff --git a/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala b/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala index 3a113460d0..02d03060b1 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala @@ -155,8 +155,8 @@ abstract class Wallet } override def processCompactFilters( - blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)]): Future[ - Wallet] = { + blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)] + ): Future[Wallet] = { val utxosF = listUtxos() val spksF = listScriptPubKeys() val blockHashOpt = blockFilters.lastOption.map(_._1) @@ -169,13 +169,14 @@ abstract class Wallet utxos <- utxosF scripts <- spksF _ = logger.debug( - s"Processing ${blockFilters.length} block filters for ${utxos.length} utxos and ${scripts.length} scripts") + s"Processing ${blockFilters.length} block filters for ${utxos.length} utxos and ${scripts.length} scripts" + ) scriptPubKeys = utxos.flatMap(_.redeemScriptOpt).toSet ++ scripts.map(_.scriptPubKey) blockHashToDownload <- { if (scriptPubKeys.isEmpty) { - //do nothing as an optimization, if we have nothing in the wallet - //we don't need to search the filters + // do nothing as an optimization, if we have nothing in the wallet + // we don't need to search the filters Future.successful(Vector.empty) } else { FutureUtil @@ -193,15 +194,15 @@ abstract class Wallet heightOpt match { case Some(height) => if (blockHashToDownload.isEmpty) { - //if we don't have any block hashes - //we need to update the wallet's sync height + // if we don't have any block hashes + // we need to update the wallet's sync height stateDescriptorDAO .updateSyncHeight(hash, height) .map(_ => ()) } else { - //if we do have a block hash that we matched - //we need to let wallet.processBlock() - //update the wallet's sync height + // if we do have a block hash that we matched + // we need to let wallet.processBlock() + // update the wallet's sync height Future.unit } case None => @@ -214,8 +215,8 @@ abstract class Wallet } private def searchFilterMatches(spks: Vector[ScriptPubKey])( - blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)]): Future[ - Vector[DoubleSha256DigestBE]] = FutureUtil.makeAsync { () => + blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)] + ): Future[Vector[DoubleSha256DigestBE]] = FutureUtil.makeAsync { () => val asmVec = spks.map(_.asmBytes) blockFilters.flatMap { case (blockHash, blockFilter) => val matcher = SimpleFilterMatcher(blockFilter) @@ -241,10 +242,8 @@ abstract class Wallet } yield addressCount == 0 && spendingInfoCount == 0 override def clearUtxos(account: HDAccount): Future[Wallet] = { - val aggregatedActions: DBIOAction[ - Wallet, - NoStream, - Effect.Read with Effect.Write] = { + val aggregatedActions + : DBIOAction[Wallet, NoStream, Effect.Read with Effect.Write] = { for { accountUtxos <- spendingInfoDAO.findAllForAccountAction(account) _ <- spendingInfoDAO.deleteSpendingInfoDbAllAction(accountUtxos) @@ -255,17 +254,16 @@ abstract class Wallet } override def clearAllUtxos(): Future[Wallet] = { - val aggregatedActions: DBIOAction[ - Unit, - NoStream, - Effect.Write with Effect.Transactional] = + val aggregatedActions + : DBIOAction[Unit, NoStream, Effect.Write with Effect.Transactional] = spendingInfoDAO.deleteAllAction().map(_ => ()) val resultedF = safeDatabase.run(aggregatedActions) resultedF.failed.foreach(err => logger.error( s"Failed to clear utxos, addresses and scripts from the database", - err)) + err + )) resultedF.map(_ => this) } @@ -280,7 +278,8 @@ abstract class Wallet } override def getBalance()(implicit - ec: ExecutionContext): Future[CurrencyUnit] = { + ec: ExecutionContext + ): Future[CurrencyUnit] = { safeDatabase.run(spendingInfoDAO.getBalanceAction()) } @@ -304,30 +303,34 @@ abstract class Wallet } override def getUnconfirmedBalance( - account: HDAccount): Future[CurrencyUnit] = { + account: HDAccount + ): Future[CurrencyUnit] = { safeDatabase.run(spendingInfoDAO.getUnconfirmedBalanceAction(Some(account))) } override def getUnconfirmedBalance(tag: AddressTag): Future[CurrencyUnit] = { spendingInfoDAO.findAllUnspentForTag(tag).map { allUnspent => - val confirmed = allUnspent.filter(utxo => - TxoState.pendingReceivedStates.contains(utxo.state)) + val confirmed = allUnspent + .filter(utxo => TxoState.pendingReceivedStates.contains(utxo.state)) confirmed.foldLeft(CurrencyUnits.zero)(_ + _.output.value) } } - override def findByOutPoints(outPoints: Vector[TransactionOutPoint]): Future[ - Vector[SpendingInfoDb]] = { + override def findByOutPoints( + outPoints: Vector[TransactionOutPoint] + ): Future[Vector[SpendingInfoDb]] = { spendingInfoDAO.findByOutPoints(outPoints) } override def findByTxIds( - txIds: Vector[DoubleSha256DigestBE]): Future[Vector[TransactionDb]] = { + txIds: Vector[DoubleSha256DigestBE] + ): Future[Vector[TransactionDb]] = { transactionDAO.findByTxIds(txIds) } override def findOutputsBeingSpent( - tx: Transaction): Future[Vector[SpendingInfoDb]] = { + tx: Transaction + ): Future[Vector[SpendingInfoDb]] = { spendingInfoDAO.findOutputsBeingSpent(tx) } @@ -335,29 +338,35 @@ abstract class Wallet protected[wallet] def listOutpoints(): Future[Vector[TransactionOutPoint]] = spendingInfoDAO.findAllOutpoints() - /** Takes a [[RawTxBuilderWithFinalizer]] for a transaction to be sent, and completes it by: - * finalizing and signing the transaction, then correctly processing and logging it + /** Takes a [[RawTxBuilderWithFinalizer]] for a transaction to be sent, and + * completes it by: finalizing and signing the transaction, then correctly + * processing and logging it */ private def finishSend[F <: RawTxFinalizer]( rawTxHelper: FundRawTxHelper[F], sentAmount: CurrencyUnit, feeRate: FeeUnit, - newTags: Vector[AddressTag]): Future[Transaction] = { + newTags: Vector[AddressTag] + ): Future[Transaction] = { val signed = rawTxHelper.signedTx val processedTxF = for { ourOuts <- findOurOuts(signed) creditingAmount = rawTxHelper.scriptSigParams.foldLeft( - CurrencyUnits.zero)(_ + _.amount) - _ <- processOurTransaction(transaction = signed, - feeRate = feeRate, - inputAmount = creditingAmount, - sentAmount = sentAmount, - blockHashOpt = None, - newTags = newTags) + CurrencyUnits.zero + )(_ + _.amount) + _ <- processOurTransaction( + transaction = signed, + feeRate = feeRate, + inputAmount = creditingAmount, + sentAmount = sentAmount, + blockHashOpt = None, + newTags = newTags + ) } yield { logger.debug( - s"Signed transaction=${signed.txIdBE.hex} with outputs=${signed.outputs.length}, inputs=${signed.inputs.length}") + s"Signed transaction=${signed.txIdBE.hex} with outputs=${signed.outputs.length}, inputs=${signed.inputs.length}" + ) logger.trace(s"Change output(s) for transaction=${signed.txIdBE.hex}") ourOuts.foreach { out => @@ -367,8 +376,8 @@ abstract class Wallet } processedTxF.recoverWith { case _ => - //if something fails, we need to unreserve the utxos associated with this tx - //and then propogate the failed future upwards + // if something fails, we need to unreserve the utxos associated with this tx + // and then propogate the failed future upwards unmarkUTXOsAsReserved(signed).flatMap(_ => processedTxF) } } @@ -376,7 +385,8 @@ abstract class Wallet override def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = { + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = { require( address.networkParameters.isSameNetworkBytes(networkParameters), s"Cannot send to address on other network, got ${address.networkParameters}" @@ -385,13 +395,16 @@ abstract class Wallet for { utxoDbs <- spendingInfoDAO.findByOutPoints(outPoints) diff = utxoDbs.map(_.outPoint).diff(outPoints) - _ = require(diff.isEmpty, - s"Not all OutPoints belong to this wallet, diff $diff") + _ = require( + diff.isEmpty, + s"Not all OutPoints belong to this wallet, diff $diff" + ) spentUtxos = utxoDbs.filterNot(utxo => TxoState.receivedStates.contains(utxo.state)) _ = require( spentUtxos.isEmpty, - s"Some out points given have already been spent, ${spentUtxos.map(_.outPoint)}") + s"Some out points given have already been spent, ${spentUtxos.map(_.outPoint)}" + ) utxos <- Future.sequence { utxoDbs.map(utxo => @@ -406,9 +419,11 @@ abstract class Wallet inputs = InputUtil.calcSequenceForInputs(utxos) txBuilder = RawTxBuilder() ++= inputs += dummyOutput - finalizer = SubtractFeeFromOutputsFinalizer(inputInfos, - feeRate, - Vector(address.scriptPubKey)) + finalizer = SubtractFeeFromOutputsFinalizer( + inputInfos, + feeRate, + Vector(address.scriptPubKey) + ) .andThen(ShuffleFinalizer) .andThen(AddWitnessDataFinalizer(inputInfos)) @@ -418,12 +433,15 @@ abstract class Wallet _ = require( tmp.outputs.size == 1, - s"Created tx is not as expected, does not have 1 output, got $tmp") + s"Created tx is not as expected, does not have 1 output, got $tmp" + ) rawTxHelper = FundRawTxHelper(withFinalizer, utxos, feeRate, Future.unit) - tx <- finishSend(rawTxHelper, - tmp.outputs.head.value, - feeRate, - Vector.empty) + tx <- finishSend( + rawTxHelper, + tmp.outputs.head.value, + feeRate, + Vector.empty + ) } yield tx } @@ -433,8 +451,8 @@ abstract class Wallet amount: CurrencyUnit, feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = { + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = { require( address.networkParameters.isSameNetworkBytes(networkParameters), s"Cannot send to address on other network, got ${address.networkParameters}" @@ -443,13 +461,16 @@ abstract class Wallet for { utxoDbs <- spendingInfoDAO.findByOutPoints(outPoints) diff = utxoDbs.map(_.outPoint).diff(outPoints) - _ = require(diff.isEmpty, - s"Not all OutPoints belong to this wallet, diff $diff") + _ = require( + diff.isEmpty, + s"Not all OutPoints belong to this wallet, diff $diff" + ) spentUtxos = utxoDbs.filterNot(utxo => TxoState.receivedStates.contains(utxo.state)) _ = require( spentUtxos.isEmpty, - s"Some out points given have already been spent, ${spentUtxos.map(_.outPoint)}") + s"Some out points given have already been spent, ${spentUtxos.map(_.outPoint)}" + ) prevTxFs = utxoDbs.map(utxo => transactionDAO.findByOutPoint(utxo.outPoint).map(_.get.transaction)) @@ -466,7 +487,8 @@ abstract class Wallet Vector(output), utxos, feeRate, - changeAddr.scriptPubKey) + changeAddr.scriptPubKey + ) rawTxHelper = FundRawTxHelper(txBuilder, utxos, feeRate, Future.unit) tx <- finishSend(rawTxHelper, amount, feeRate, newTags) } yield tx @@ -474,7 +496,8 @@ abstract class Wallet /** Sends the entire wallet balance to the given address */ override def sweepWallet(address: BitcoinAddress, feeRate: FeeUnit)(implicit - ec: ExecutionContext): Future[Transaction] = { + ec: ExecutionContext + ): Future[Transaction] = { for { utxos <- listUtxos() balance = utxos.foldLeft(CurrencyUnits.zero)(_ + _.output.value) @@ -486,14 +509,16 @@ abstract class Wallet override def bumpFeeRBF( txId: DoubleSha256DigestBE, - newFeeRate: FeeUnit): Future[Transaction] = { + newFeeRate: FeeUnit + ): Future[Transaction] = { for { txDbOpt <- transactionDAO.findByTxId(txId) txDb <- txDbOpt match { case Some(db) => Future.successful(db) case None => Future.failed( - new RuntimeException(s"Unable to find transaction ${txId.hex}")) + new RuntimeException(s"Unable to find transaction ${txId.hex}") + ) } tx = txDb.transaction @@ -504,12 +529,15 @@ abstract class Wallet utxos <- spendingInfoDAO.findByOutPoints(outPoints) _ = require(utxos.nonEmpty, "Can only bump fee for our own transaction") - _ = require(utxos.size == tx.inputs.size, - "Can only bump fee for a transaction we own all the inputs") + _ = require( + utxos.size == tx.inputs.size, + "Can only bump fee for a transaction we own all the inputs" + ) _ = require( txDb.blockHashOpt.isEmpty, - s"Cannot replace a confirmed transaction, ${txDb.blockHashOpt.get.hex}") + s"Cannot replace a confirmed transaction, ${txDb.blockHashOpt.get.hex}" + ) spendingInfos <- FutureUtil.sequentially(utxos) { utxo => transactionDAO @@ -534,7 +562,8 @@ abstract class Wallet require( oldFeeRate.currencyUnit < newFeeRate.currencyUnit, - s"Cannot bump to a lower fee ${oldFeeRate.currencyUnit} < ${newFeeRate.currencyUnit}") + s"Cannot bump to a lower fee ${oldFeeRate.currencyUnit} < ${newFeeRate.currencyUnit}" + ) } myAddrs <- addressDAO.findByScriptPubKeys(spks) @@ -561,17 +590,21 @@ abstract class Wallet sequence = tx.inputs.head.sequence + UInt32.one outputs = tx.outputs.filterNot(_.scriptPubKey == changeSpk) - txBuilder = StandardNonInteractiveFinalizer.txBuilderFrom(outputs, - spendingInfos, - newFeeRate, - changeSpk, - sequence) + txBuilder = StandardNonInteractiveFinalizer.txBuilderFrom( + outputs, + spendingInfos, + newFeeRate, + changeSpk, + sequence + ) amount = outputs.foldLeft(CurrencyUnits.zero)(_ + _.value) - rawTxHelper = FundRawTxHelper(txBuilder, - spendingInfos, - newFeeRate, - Future.unit) + rawTxHelper = FundRawTxHelper( + txBuilder, + spendingInfos, + newFeeRate, + Future.unit + ) tx <- finishSend(rawTxHelper, amount, newFeeRate, Vector.empty) } yield tx @@ -583,8 +616,8 @@ abstract class Wallet feeRate: FeeUnit, algo: CoinSelectionAlgo, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = { + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = { require( address.networkParameters.isSameNetworkBytes(networkParameters), s"Cannot send to address on other network, got ${address.networkParameters}" @@ -592,13 +625,14 @@ abstract class Wallet logger.info(s"Sending $amount to $address at feerate $feeRate") val destination = TransactionOutput(amount, address.scriptPubKey) for { - rawTxHelper <- fundRawTransactionInternal(destinations = - Vector(destination), - feeRate = feeRate, - fromAccount = fromAccount, - coinSelectionAlgo = algo, - fromTagOpt = None, - markAsReserved = true) + rawTxHelper <- fundRawTransactionInternal( + destinations = Vector(destination), + feeRate = feeRate, + fromAccount = fromAccount, + coinSelectionAlgo = algo, + fromTagOpt = None, + markAsReserved = true + ) tx <- finishSend(rawTxHelper, amount, feeRate, newTags) } yield tx } @@ -607,40 +641,47 @@ abstract class Wallet address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = - sendWithAlgo(address, - amount, - feeRate, - CoinSelectionAlgo.LeastWaste, - fromAccount) + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = + sendWithAlgo( + address, + amount, + feeRate, + CoinSelectionAlgo.LeastWaste, + fromAccount + ) override def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = - sendWithAlgo(address, - amount, - feeRate, - CoinSelectionAlgo.LeastWaste, - fromAccount, - newTags) + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = + sendWithAlgo( + address, + amount, + feeRate, + CoinSelectionAlgo.LeastWaste, + fromAccount, + newTags + ) override def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = { - require(amounts.size == addresses.size, - "Must have an amount for every address") + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = { + require( + amounts.size == addresses.size, + "Must have an amount for every address" + ) require( addresses.forall( - _.networkParameters.isSameNetworkBytes(networkParameters)), + _.networkParameters.isSameNetworkBytes(networkParameters) + ), s"Cannot send to address on other network, got ${addresses.map(_.networkParameters)}" ) val destinations = addresses.zip(amounts).map { case (address, amount) => @@ -654,19 +695,21 @@ abstract class Wallet message: String, hashMessage: Boolean, feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = { + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = { val messageToUse = if (hashMessage) { CryptoUtil.sha256(ByteVector(message.getBytes)).bytes } else { if (message.length > 80) { throw new IllegalArgumentException( - s"Message cannot be greater than 80 characters, it should be hashed, got $message") + s"Message cannot be greater than 80 characters, it should be hashed, got $message" + ) } else ByteVector(message.getBytes) } val asm = Seq(OP_RETURN) ++ BitcoinScriptUtil.calculatePushOp( - messageToUse) :+ ScriptConstant(messageToUse) + messageToUse + ) :+ ScriptConstant(messageToUse) val scriptPubKey = ScriptPubKey(asm) @@ -681,10 +724,12 @@ abstract class Wallet fromTagOpt = None, markAsReserved = true ) - tx <- finishSend(fundRawTxHelper, - CurrencyUnits.zero, - feeRate, - Vector.empty) + tx <- finishSend( + fundRawTxHelper, + CurrencyUnits.zero, + feeRate, + Vector.empty + ) } yield tx } @@ -692,14 +737,16 @@ abstract class Wallet outputs: Vector[TransactionOutput], feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = { + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = { for { - fundRawTxHelper <- fundRawTransactionInternal(destinations = outputs, - feeRate = feeRate, - fromAccount = fromAccount, - fromTagOpt = None, - markAsReserved = true) + fundRawTxHelper <- fundRawTransactionInternal( + destinations = outputs, + feeRate = feeRate, + fromAccount = fromAccount, + fromTagOpt = None, + markAsReserved = true + ) sentAmount = outputs.foldLeft(CurrencyUnits.zero)(_ + _.value) tx <- finishSend(fundRawTxHelper, sentAmount, feeRate, newTags) } yield tx @@ -716,24 +763,29 @@ abstract class Wallet /** @inheritdoc */ override def bumpFeeCPFP( txId: DoubleSha256DigestBE, - feeRate: FeeUnit): Future[Transaction] = { + feeRate: FeeUnit + ): Future[Transaction] = { for { txDbOpt <- transactionDAO.findByTxId(txId) txDb <- txDbOpt match { case Some(db) => Future.successful(db) case None => Future.failed( - new RuntimeException(s"Unable to find transaction ${txId.hex}")) + new RuntimeException(s"Unable to find transaction ${txId.hex}") + ) } tx = txDb.transaction spendingInfos <- spendingInfoDAO.findTx(tx) - _ = require(spendingInfos.nonEmpty, - s"Transaction ${txId.hex} must have an output we own") + _ = require( + spendingInfos.nonEmpty, + s"Transaction ${txId.hex} must have an output we own" + ) _ = require( txDb.blockHashOpt.isEmpty, - s"Cannot replace a confirmed transaction, ${txDb.blockHashOpt.get.hex}") + s"Cannot replace a confirmed transaction, ${txDb.blockHashOpt.get.hex}" + ) changeSpendingInfos = spendingInfos.flatMap { db => if (db.isChange) { @@ -755,8 +807,9 @@ abstract class Wallet } yield childTx } - override def signPSBT(psbt: PSBT)(implicit - ec: ExecutionContext): Future[PSBT] = { + override def signPSBT( + psbt: PSBT + )(implicit ec: ExecutionContext): Future[PSBT] = { val inputTxIds = psbt.transaction.inputs.zipWithIndex.map { case (input, index) => input.previousOutput.txIdBE -> index @@ -790,8 +843,10 @@ abstract class Wallet case Some(utxo) => val psbtWithUtxoData = utxo.redeemScript match { case Some(redeemScript) => - unsigned.addRedeemOrWitnessScriptToInput(redeemScript, - index) + unsigned.addRedeemOrWitnessScriptToInput( + redeemScript, + index + ) case None => unsigned } @@ -807,10 +862,12 @@ abstract class Wallet // Only sign if that key doesn't have a signature yet if ( !input.partialSignatures.exists( - _.pubKey.toPublicKey == sign.publicKey) + _.pubKey.toPublicKey == sign.publicKey + ) ) { logger.debug( - s"Signing input $index with key ${sign.publicKey.hex}") + s"Signing input $index with key ${sign.publicKey.hex}" + ) accum.sign(index, sign) } else { accum @@ -826,7 +883,8 @@ abstract class Wallet } protected def getLastAccountOpt( - purpose: HDPurpose): Future[Option[AccountDb]] = { + purpose: HDPurpose + ): Future[Option[AccountDb]] = { accountDAO .findAll() .map(_.filter(_.hdAccount.purpose == purpose)) @@ -837,8 +895,9 @@ abstract class Wallet .map(_.lastOption) } - /** Creates a new account my reading from our account database, finding the last account, - * and then incrementing the account index by one, and then creating that account + /** Creates a new account my reading from our account database, finding the + * last account, and then incrementing the account index by one, and then + * creating that account * * @return */ @@ -857,9 +916,11 @@ abstract class Wallet // account before creating new override def createNewAccount( hdAccount: HDAccount, - kmParams: KeyManagerParams): Future[Wallet] = { + kmParams: KeyManagerParams + ): Future[Wallet] = { logger.info( - s"Creating new account at index ${hdAccount.index} for purpose ${kmParams.purpose}") + s"Creating new account at index ${hdAccount.index} for purpose ${kmParams.purpose}" + ) val xpub: ExtPublicKey = { keyManager.deriveXPub(hdAccount) match { @@ -902,7 +963,8 @@ abstract class Wallet } override def findByScriptPubKey( - scriptPubKey: ScriptPubKey): Future[Vector[SpendingInfoDb]] = { + scriptPubKey: ScriptPubKey + ): Future[Vector[SpendingInfoDb]] = { spendingInfoDAO.findByScriptPubKey(scriptPubKey) } @@ -912,12 +974,13 @@ abstract class Wallet getFeeRate() .map(feeRate => Some(feeRate)) .recover { case NonFatal(_) => - //logger.error("Cannot get fee rate ", ex) + // logger.error("Cannot get fee rate ", ex) None } .foreach { feeRateOpt => walletCallbacks.executeOnFeeRateChanged( - feeRateOpt.getOrElse(SatoshisPerVirtualByte.negativeOne)) + feeRateOpt.getOrElse(SatoshisPerVirtualByte.negativeOne) + ) } () } @@ -927,7 +990,8 @@ abstract class Wallet feeRateChangedRunnable, walletConfig.feeRatePollDelay.toSeconds, walletConfig.feeRatePollInterval.toSeconds, - TimeUnit.SECONDS) + TimeUnit.SECONDS + ) } } @@ -945,19 +1009,22 @@ object Wallet extends WalletLogger { def apply( nodeApi: NodeApi, chainQueryApi: ChainQueryApi, - feeRateApi: FeeRateApi)(implicit config: WalletAppConfig): Wallet = { + feeRateApi: FeeRateApi + )(implicit config: WalletAppConfig): Wallet = { WalletImpl(nodeApi, chainQueryApi, feeRateApi) } /** Creates the master xpub for the key manager in the database - * @throws RuntimeException if a different master xpub key exists in the database + * @throws RuntimeException + * if a different master xpub key exists in the database */ - private def createMasterXPub(keyManager: BIP39KeyManager)(implicit - walletAppConfig: WalletAppConfig): Future[ExtPublicKey] = { + private def createMasterXPub( + keyManager: BIP39KeyManager + )(implicit walletAppConfig: WalletAppConfig): Future[ExtPublicKey] = { import walletAppConfig.ec val masterXPubDAO = MasterXPubDAO() val countF = masterXPubDAO.count() - //make sure we don't have a xpub in the db + // make sure we don't have a xpub in the db countF.flatMap { count => if (count == 0) { masterXPubDAO.create(keyManager.getRootXPub).map(_.toExtPublicKey) @@ -971,7 +1038,8 @@ object Wallet extends WalletLogger { xpubs.head.toExtPublicKey } else { throw new IllegalArgumentException( - s"Wallet database contains different master xpubs, got=${xpubs}") + s"Wallet database contains different master xpubs, got=${xpubs}" + ) } } } @@ -979,12 +1047,12 @@ object Wallet extends WalletLogger { } - /** Creates the level 0 account for the given HD purpose, if the root account exists do nothing */ + /** Creates the level 0 account for the given HD purpose, if the root account + * exists do nothing + */ private def createRootAccount(wallet: Wallet, keyManager: BIP39KeyManager)( - implicit ec: ExecutionContext): DBIOAction[ - AccountDb, - NoStream, - Effect.Read with Effect.Write] = { + implicit ec: ExecutionContext + ): DBIOAction[AccountDb, NoStream, Effect.Read with Effect.Write] = { val coinType = HDUtil.getCoinType(keyManager.kmParams.network) val coin = HDCoin(purpose = keyManager.kmParams.purpose, coinType = coinType) @@ -993,11 +1061,11 @@ object Wallet extends WalletLogger { val xpub = keyManager.deriveXPub(account).get val accountDb = AccountDb(xpub, account) - //see if we already have this account in our database - //Three possible cases: - //1. We have nothing in our database, so we need to insert it - //2. We already have this account in our database, so we do nothing - //3. We have this account in our database, with a DIFFERENT xpub. This is bad. Fail with an exception + // see if we already have this account in our database + // Three possible cases: + // 1. We have nothing in our database, so we need to insert it + // 2. We already have this account in our database, so we do nothing + // 3. We have this account in our database, with a DIFFERENT xpub. This is bad. Fail with an exception // this most likely means that we have a different key manager than we expected wallet.accountDAO .findByPrimaryKeyAction((account.coin, account.index)) @@ -1010,7 +1078,8 @@ object Wallet extends WalletLogger { DBIOAction.failed(new RuntimeException(errorMsg)) } else { logger.debug( - s"Account already exists in database, no need to create it, account=${account}") + s"Account already exists in database, no need to create it, account=${account}" + ) DBIOAction.successful(account) } case None => @@ -1021,7 +1090,8 @@ object Wallet extends WalletLogger { def initialize( wallet: Wallet, - bip39PasswordOpt: Option[String]): Future[Wallet] = { + bip39PasswordOpt: Option[String] + ): Future[Wallet] = { implicit val walletAppConfig = wallet.walletConfig import walletAppConfig.ec val passwordOpt = walletAppConfig.aesPasswordOpt @@ -1031,25 +1101,30 @@ object Wallet extends WalletLogger { // so the user can change the default account kind later // and still have their wallet work val createAccountActions: Vector[ - DBIOAction[AccountDb, NoStream, Effect.Read with Effect.Write]] = { + DBIOAction[AccountDb, NoStream, Effect.Read with Effect.Write] + ] = { val accounts = HDPurposes.singleSigPurposes.map { purpose => - //we need to create key manager params for each purpose - //and then initialize a key manager to derive the correct xpub + // we need to create key manager params for each purpose + // and then initialize a key manager to derive the correct xpub val kmParams = wallet.keyManager.kmParams.copy(purpose = purpose) val kmE = { - BIP39KeyManager.fromParams(kmParams = kmParams, - passwordOpt = passwordOpt, - bip39PasswordOpt = bip39PasswordOpt) + BIP39KeyManager.fromParams( + kmParams = kmParams, + passwordOpt = passwordOpt, + bip39PasswordOpt = bip39PasswordOpt + ) } kmE match { case Right(km) => createRootAccount(wallet = wallet, keyManager = km) case Left(err) => - //probably means you haven't initialized the key manager via the - //'CreateKeyManagerApi' + // probably means you haven't initialized the key manager via the + // 'CreateKeyManagerApi' DBIOAction.failed( new RuntimeException( - s"Failed to create keymanager with params=$kmParams err=$err")) + s"Failed to create keymanager with params=$kmParams err=$err" + ) + ) } } @@ -1059,25 +1134,27 @@ object Wallet extends WalletLogger { _ <- createMasterXpubF actions = createAccountActions accounts <- wallet.accountDAO.safeDatabase.runVec( - DBIOAction.sequence(actions)) + DBIOAction.sequence(actions) + ) _ = accounts.foreach { a => logger.info(s"Created account=${a} to DB") } _ <- { - //check if creationTime is well in the past, if so generate a pool of addresses - //see: https://github.com/bitcoin-s/bitcoin-s/issues/5033 + // check if creationTime is well in the past, if so generate a pool of addresses + // see: https://github.com/bitcoin-s/bitcoin-s/issues/5033 val creationTime = wallet.keyManager.creationTime val threshold = Instant.now().minus(1, ChronoUnit.HOURS) val isOldCreationTime = creationTime.compareTo(threshold) <= 0 if (isOldCreationTime) { wallet - .generateScriptPubKeys(account = walletAppConfig.defaultAccount, - addressBatchSize = - walletAppConfig.discoveryBatchSize, - forceGenerateSpks = true) + .generateScriptPubKeys( + account = walletAppConfig.defaultAccount, + addressBatchSize = walletAppConfig.discoveryBatchSize, + forceGenerateSpks = true + ) .map(_ => ()) } else { - //fresh seed, no need to generate addresses + // fresh seed, no need to generate addresses Future.unit } } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/WalletHolder.scala b/wallet/src/main/scala/org/bitcoins/wallet/WalletHolder.scala index 59aabd1c6c..da37789f63 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/WalletHolder.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/WalletHolder.scala @@ -53,8 +53,8 @@ import scala.concurrent.{ExecutionContext, Future} class WalletNotInitialized extends Exception("The wallet is not initialized") class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit - ec: ExecutionContext) - extends DLCNeutrinoHDWalletApi + ec: ExecutionContext +) extends DLCNeutrinoHDWalletApi with BitcoinSLogger { @volatile private var walletOpt: Option[DLCNeutrinoHDWalletApi] = @@ -73,7 +73,8 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit } def replaceWallet( - newWallet: DLCNeutrinoHDWalletApi): Future[DLCNeutrinoHDWalletApi] = + newWallet: DLCNeutrinoHDWalletApi + ): Future[DLCNeutrinoHDWalletApi] = synchronized { val oldWalletOpt = walletOpt walletOpt = None @@ -97,8 +98,8 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit res } - private def delegate[T]: ( - DLCNeutrinoHDWalletApi => Future[T]) => Future[T] = { + private def delegate[T] + : (DLCNeutrinoHDWalletApi => Future[T]) => Future[T] = { Future(wallet).flatMap[T](_) } @@ -106,8 +107,8 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit delegate(_.processBlock(block)) override def processCompactFilters( - blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)]): Future[ - NeutrinoHDWalletApi] = { + blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)] + ): Future[NeutrinoHDWalletApi] = { delegate(_.processCompactFilters(blockFilters)) } @@ -116,13 +117,17 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit endOpt: Option[BlockStamp], addressBatchSize: Int, useCreationTime: Boolean, - force: Boolean)(implicit ec: ExecutionContext): Future[RescanState] = + force: Boolean + )(implicit ec: ExecutionContext): Future[RescanState] = delegate( - _.rescanNeutrinoWallet(startOpt, - endOpt, - addressBatchSize, - useCreationTime, - force)) + _.rescanNeutrinoWallet( + startOpt, + endOpt, + addressBatchSize, + useCreationTime, + force + ) + ) override def discoveryBatchSize(): Int = wallet.discoveryBatchSize() @@ -147,51 +152,57 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit override def processTransaction( transaction: Transaction, - blockHash: Option[DoubleSha256DigestBE]): Future[WalletApi] = delegate( - _.processTransaction(transaction, blockHash)) + blockHash: Option[DoubleSha256DigestBE] + ): Future[WalletApi] = delegate(_.processTransaction(transaction, blockHash)) override def findTransaction( - txId: DoubleSha256DigestBE): Future[Option[TransactionDb]] = delegate( - _.findTransaction(txId)) + txId: DoubleSha256DigestBE + ): Future[Option[TransactionDb]] = delegate(_.findTransaction(txId)) override def fundRawTransaction( destinations: Vector[TransactionOutput], feeRate: FeeUnit, fromTagOpt: Option[AddressTag], - markAsReserved: Boolean): Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = delegate( - _.fundRawTransaction(destinations, feeRate, fromTagOpt, markAsReserved)) + markAsReserved: Boolean + ): Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = delegate( + _.fundRawTransaction(destinations, feeRate, fromTagOpt, markAsReserved) + ) override def fundRawTransaction( destinations: Vector[TransactionOutput], feeRate: FeeUnit, fromAccount: AccountDb, - markAsReserved: Boolean): Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { + markAsReserved: Boolean + ): Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { delegate( - _.fundRawTransaction(destinations, feeRate, fromAccount, markAsReserved)) + _.fundRawTransaction(destinations, feeRate, fromAccount, markAsReserved) + ) } override def listTransactions(): Future[Vector[TransactionDb]] = delegate( - _.listTransactions()) + _.listTransactions() + ) override def updateUtxoPendingStates(): Future[Vector[SpendingInfoDb]] = delegate(_.updateUtxoPendingStates()) override def getConfirmedBalance(): Future[CurrencyUnit] = delegate( - _.getConfirmedBalance()) + _.getConfirmedBalance() + ) override def getConfirmedBalance(tag: AddressTag): Future[CurrencyUnit] = delegate(_.getConfirmedBalance(tag)) override def getUnconfirmedBalance(): Future[CurrencyUnit] = delegate( - _.getUnconfirmedBalance()) + _.getUnconfirmedBalance() + ) override def getUnconfirmedBalance(tag: AddressTag): Future[CurrencyUnit] = delegate(_.getUnconfirmedBalance(tag)) override def listUtxos(): Future[Vector[SpendingInfoDb]] = delegate( - _.listUtxos()) + _.listUtxos() + ) override def listUtxos(tag: AddressTag): Future[Vector[SpendingInfoDb]] = delegate(_.listUtxos(tag)) @@ -200,39 +211,45 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit delegate(_.listUtxos(state)) override def listAddresses(): Future[Vector[AddressDb]] = delegate( - _.listAddresses()) + _.listAddresses() + ) override def listSpentAddresses(): Future[Vector[AddressDb]] = delegate( - _.listSpentAddresses()) + _.listSpentAddresses() + ) - override def listFundedAddresses(): Future[ - Vector[(AddressDb, CurrencyUnit)]] = delegate(_.listFundedAddresses()) + override def listFundedAddresses() + : Future[Vector[(AddressDb, CurrencyUnit)]] = delegate( + _.listFundedAddresses() + ) override def listUnusedAddresses(): Future[Vector[AddressDb]] = delegate( - _.listUnusedAddresses()) + _.listUnusedAddresses() + ) override def listScriptPubKeys(): Future[Vector[ScriptPubKeyDb]] = delegate( - _.listScriptPubKeys()) + _.listScriptPubKeys() + ) override def watchScriptPubKey( - scriptPubKey: ScriptPubKey): Future[ScriptPubKeyDb] = delegate( - _.watchScriptPubKey(scriptPubKey)) + scriptPubKey: ScriptPubKey + ): Future[ScriptPubKeyDb] = delegate(_.watchScriptPubKey(scriptPubKey)) override def markUTXOsAsReserved( - utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = delegate( - _.markUTXOsAsReserved(utxos)) + utxos: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] = delegate(_.markUTXOsAsReserved(utxos)) override def markUTXOsAsReserved( - tx: Transaction): Future[Vector[SpendingInfoDb]] = delegate( - _.markUTXOsAsReserved(tx)) + tx: Transaction + ): Future[Vector[SpendingInfoDb]] = delegate(_.markUTXOsAsReserved(tx)) override def unmarkUTXOsAsReserved( - utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = delegate( - _.unmarkUTXOsAsReserved(utxos)) + utxos: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] = delegate(_.unmarkUTXOsAsReserved(utxos)) override def unmarkUTXOsAsReserved( - tx: Transaction): Future[Vector[SpendingInfoDb]] = delegate( - _.unmarkUTXOsAsReserved(tx)) + tx: Transaction + ): Future[Vector[SpendingInfoDb]] = delegate(_.unmarkUTXOsAsReserved(tx)) override def isEmpty(): Future[Boolean] = delegate(_.isEmpty()) @@ -244,47 +261,50 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit } override def getNewAddress(): Future[BitcoinAddress] = delegate( - _.getNewAddress()) + _.getNewAddress() + ) override def getNewAddress( addressType: AddressType, - tags: Vector[AddressTag]): Future[BitcoinAddress] = delegate( - _.getNewAddress(addressType, tags)) + tags: Vector[AddressTag] + ): Future[BitcoinAddress] = delegate(_.getNewAddress(addressType, tags)) override def getNewAddress(tags: Vector[AddressTag]): Future[BitcoinAddress] = delegate(_.getNewAddress(tags)) override def getUnusedAddress( - addressType: AddressType): Future[BitcoinAddress] = delegate( - _.getUnusedAddress(addressType)) + addressType: AddressType + ): Future[BitcoinAddress] = delegate(_.getUnusedAddress(addressType)) override def getUnusedAddress: Future[BitcoinAddress] = delegate( - _.getUnusedAddress) + _.getUnusedAddress + ) override def getAddressInfo( - address: BitcoinAddress): Future[Option[AddressInfo]] = delegate( - _.getAddressInfo(address)) + address: BitcoinAddress + ): Future[Option[AddressInfo]] = delegate(_.getAddressInfo(address)) override def tagAddress( address: BitcoinAddress, - tag: AddressTag): Future[AddressTagDb] = delegate( - _.tagAddress(address, tag)) + tag: AddressTag + ): Future[AddressTagDb] = delegate(_.tagAddress(address, tag)) override def getAddressTags( - address: BitcoinAddress): Future[Vector[AddressTagDb]] = delegate( - _.getAddressTags(address)) + address: BitcoinAddress + ): Future[Vector[AddressTagDb]] = delegate(_.getAddressTags(address)) override def getAddressTags( address: BitcoinAddress, - tagType: AddressTagType): Future[Vector[AddressTagDb]] = delegate( - _.getAddressTags(address, tagType)) + tagType: AddressTagType + ): Future[Vector[AddressTagDb]] = delegate(_.getAddressTags(address, tagType)) override def getAddressTags(): Future[Vector[AddressTagDb]] = delegate( - _.getAddressTags()) + _.getAddressTags() + ) override def getAddressTags( - tagType: AddressTagType): Future[Vector[AddressTagDb]] = delegate( - _.getAddressTags(tagType)) + tagType: AddressTagType + ): Future[Vector[AddressTagDb]] = delegate(_.getAddressTags(tagType)) override def dropAddressTag(addressTagDb: AddressTagDb): Future[Int] = delegate(_.dropAddressTag(addressTagDb)) @@ -294,39 +314,42 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit override def dropAddressTagType( address: BitcoinAddress, - addressTagType: AddressTagType): Future[Int] = delegate( - _.dropAddressTagType(address, addressTagType)) + addressTagType: AddressTagType + ): Future[Int] = delegate(_.dropAddressTagType(address, addressTagType)) override def dropAddressTagName( address: BitcoinAddress, - tagName: AddressTagName): Future[Int] = delegate( - _.dropAddressTagName(address, tagName)) + tagName: AddressTagName + ): Future[Int] = delegate(_.dropAddressTagName(address, tagName)) override def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendFromOutPoints(outPoints, address, feeRate)) override def sweepWallet(address: BitcoinAddress, feeRate: FeeUnit)(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sweepWallet(address, feeRate)) + ec: ExecutionContext + ): Future[Transaction] = delegate(_.sweepWallet(address, feeRate)) override def bumpFeeRBF( txId: DoubleSha256DigestBE, - newFeeRate: FeeUnit): Future[Transaction] = delegate( - _.bumpFeeRBF(txId, newFeeRate)) + newFeeRate: FeeUnit + ): Future[Transaction] = delegate(_.bumpFeeRBF(txId, newFeeRate)) override def bumpFeeCPFP( txId: DoubleSha256DigestBE, - feeRate: FeeUnit): Future[Transaction] = delegate( - _.bumpFeeCPFP(txId, feeRate)) + feeRate: FeeUnit + ): Future[Transaction] = delegate(_.bumpFeeCPFP(txId, feeRate)) override def isChange(output: TransactionOutput): Future[Boolean] = delegate( - _.isChange(output)) + _.isChange(output) + ) override def getSyncState(): Future[BlockSyncState] = delegate( - _.getSyncState()) + _.getSyncState() + ) override def isRescanning(): Future[Boolean] = delegate(_.isRescanning()) @@ -337,15 +360,18 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit refundLT: UInt32, peerAddressOpt: Option[InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[ - DLCMessage.DLCOffer] = delegate( - _.createDLCOffer(contractInfo, - collateral, - feeRateOpt, - refundLT, - peerAddressOpt, - externalPayoutAddressOpt, - externalChangeAddressOpt)) + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCMessage.DLCOffer] = delegate( + _.createDLCOffer( + contractInfo, + collateral, + feeRateOpt, + refundLT, + peerAddressOpt, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) + ) override def createDLCOffer( contractInfo: ContractInfo, @@ -355,56 +381,66 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit refundLT: UInt32, peerAddressOpt: Option[InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[ - DLCMessage.DLCOffer] = delegate( - _.createDLCOffer(contractInfo, - collateral, - feeRateOpt, - locktime, - refundLT, - peerAddressOpt, - externalPayoutAddressOpt, - externalChangeAddressOpt)) + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCMessage.DLCOffer] = delegate( + _.createDLCOffer( + contractInfo, + collateral, + feeRateOpt, + locktime, + refundLT, + peerAddressOpt, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) + ) override def acceptDLCOffer( dlcOffer: DLCMessage.DLCOffer, peerAddress: Option[InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[ - DLCMessage.DLCAccept] = delegate( - _.acceptDLCOffer(dlcOffer, - peerAddress, - externalPayoutAddressOpt, - externalChangeAddressOpt)) + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCMessage.DLCAccept] = delegate( + _.acceptDLCOffer( + dlcOffer, + peerAddress, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) + ) override def signDLC(acceptTLV: DLCAcceptTLV): Future[DLCMessage.DLCSign] = delegate(_.signDLC(acceptTLV)) override def signDLC( - accept: DLCMessage.DLCAccept): Future[DLCMessage.DLCSign] = delegate( - _.signDLC(accept)) + accept: DLCMessage.DLCAccept + ): Future[DLCMessage.DLCSign] = delegate(_.signDLC(accept)) override def addDLCSigs(signTLV: DLCSignTLV): Future[DLCDb] = delegate( - _.addDLCSigs(signTLV)) + _.addDLCSigs(signTLV) + ) override def addDLCSigs(sigs: DLCMessage.DLCSign): Future[DLCDb] = delegate( - _.addDLCSigs(sigs)) + _.addDLCSigs(sigs) + ) override def getDLCFundingTx(contractId: ByteVector): Future[Transaction] = delegate(_.getDLCFundingTx(contractId)) override def broadcastDLCFundingTx( - contractId: ByteVector): Future[Transaction] = delegate( - _.broadcastDLCFundingTx(contractId)) + contractId: ByteVector + ): Future[Transaction] = delegate(_.broadcastDLCFundingTx(contractId)) override def executeDLC( contractId: ByteVector, - oracleSigs: Seq[OracleAttestmentTLV]): Future[Option[Transaction]] = + oracleSigs: Seq[OracleAttestmentTLV] + ): Future[Option[Transaction]] = delegate(_.executeDLC(contractId, oracleSigs)) override def executeDLC( contractId: ByteVector, - oracleSigs: Vector[OracleSignatures]): Future[Option[Transaction]] = + oracleSigs: Vector[OracleSignatures] + ): Future[Option[Transaction]] = delegate(_.executeDLC(contractId, oracleSigs)) override def executeDLCRefund(contractId: ByteVector): Future[Transaction] = @@ -419,24 +455,30 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit delegate(_.findDLC(dlcId)) override def findDLCByTemporaryContractId( - tempContractId: Sha256Digest): Future[Option[DLCStatus]] = delegate( - _.findDLCByTemporaryContractId(tempContractId)) + tempContractId: Sha256Digest + ): Future[Option[DLCStatus]] = delegate( + _.findDLCByTemporaryContractId(tempContractId) + ) override def cancelDLC(dlcId: Sha256Digest): Future[Unit] = delegate( - _.cancelDLC(dlcId)) + _.cancelDLC(dlcId) + ) override def getDLCOffer( - dlcId: Sha256Digest): Future[Option[DLCMessage.DLCOffer]] = delegate( - _.getDLCOffer(dlcId)) + dlcId: Sha256Digest + ): Future[Option[DLCMessage.DLCOffer]] = delegate(_.getDLCOffer(dlcId)) override def getWalletAccounting(): Future[DLCWalletAccounting] = delegate( - _.getWalletAccounting()) + _.getWalletAccounting() + ) override def registerIncomingDLCOffer( offerTLV: DLCOfferTLV, peer: Option[String], - message: Option[String]): Future[Sha256Digest] = delegate( - _.registerIncomingDLCOffer(offerTLV, peer, message)) + message: Option[String] + ): Future[Sha256Digest] = delegate( + _.registerIncomingDLCOffer(offerTLV, peer, message) + ) override def listIncomingDLCOffers(): Future[Vector[IncomingDLCOfferDb]] = delegate(_.listIncomingDLCOffers()) @@ -445,14 +487,18 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit delegate(_.rejectIncomingDLCOffer(offerHash)) override def findIncomingDLCOffer( - offerHash: Sha256Digest): Future[Option[IncomingDLCOfferDb]] = delegate( - _.findIncomingDLCOffer(offerHash)) + offerHash: Sha256Digest + ): Future[Option[IncomingDLCOfferDb]] = delegate( + _.findIncomingDLCOffer(offerHash) + ) override def listDLCContacts(): Future[Vector[DLCContactDb]] = delegate( - _.listDLCContacts()) + _.listDLCContacts() + ) override def addDLCContact(contact: DLCContactDb): Future[Unit] = delegate( - _.addDLCContact(contact)) + _.addDLCContact(contact) + ) override def removeDLCContact(address: InetSocketAddress): Future[Unit] = delegate(_.removeDLCContact(address)) @@ -462,15 +508,15 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit override def addDLCContactMapping( dlcId: Sha256Digest, - contactId: InetSocketAddress): Future[Unit] = delegate( - _.addDLCContactMapping(dlcId, contactId)) + contactId: InetSocketAddress + ): Future[Unit] = delegate(_.addDLCContactMapping(dlcId, contactId)) override def removeDLCContactMapping(dlcId: Sha256Digest): Future[Unit] = delegate(_.removeDLCContactMapping(dlcId)) override def listDLCsByContact( - address: InetSocketAddress): Future[Vector[DLCStatus]] = delegate( - _.listDLCsByContact(address)) + address: InetSocketAddress + ): Future[Vector[DLCStatus]] = delegate(_.listDLCsByContact(address)) override def keyManager: BIP39KeyManagerApi = wallet.keyManager @@ -484,11 +530,12 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit delegate(_.getNewChangeAddress(account)) override def getDefaultAccount(): Future[AccountDb] = delegate( - _.getDefaultAccount()) + _.getDefaultAccount() + ) override def getDefaultAccountForType( - addressType: AddressType): Future[AccountDb] = delegate( - _.getDefaultAccountForType(addressType)) + addressType: AddressType + ): Future[AccountDb] = delegate(_.getDefaultAccountForType(addressType)) override def sendWithAlgo( address: BitcoinAddress, @@ -496,9 +543,10 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit feeRate: FeeUnit, algo: CoinSelectionAlgo, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sendWithAlgo(address, amount, feeRate, algo, fromAccount, newTags)) + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.sendWithAlgo(address, amount, feeRate, algo, fromAccount, newTags) + ) override def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], @@ -506,51 +554,59 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit amount: CurrencyUnit, feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sendFromOutPoints(outPoints, - address, - amount, - feeRate, - fromAccount, - newTags)) + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.sendFromOutPoints( + outPoints, + address, + amount, + feeRate, + fromAccount, + newTags + ) + ) override def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sendToAddress(address, amount, feeRate, fromAccount, newTags)) + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.sendToAddress(address, amount, feeRate, fromAccount, newTags) + ) override def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sendToAddresses(addresses, amounts, feeRate, fromAccount, newTags)) + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.sendToAddresses(addresses, amounts, feeRate, fromAccount, newTags) + ) override def sendToOutputs( outputs: Vector[TransactionOutput], feeRate: FeeUnit, fromAccount: AccountDb, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sendToOutputs(outputs, feeRate, fromAccount, newTags)) + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.sendToOutputs(outputs, feeRate, fromAccount, newTags) + ) override def signPSBT(psbt: PSBT)(implicit - ec: ExecutionContext): Future[PSBT] = delegate(_.signPSBT(psbt)) + ec: ExecutionContext + ): Future[PSBT] = delegate(_.signPSBT(psbt)) override def makeOpReturnCommitment( message: String, hashMessage: Boolean, feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.makeOpReturnCommitment(message, hashMessage, feeRate, fromAccount)) + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.makeOpReturnCommitment(message, hashMessage, feeRate, fromAccount) + ) override def listDefaultAccountUtxos(): Future[Vector[SpendingInfoDb]] = delegate(_.listDefaultAccountUtxos()) @@ -560,34 +616,38 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit override def listUtxos( hdAccount: HDAccount, - tag: AddressTag): Future[Vector[SpendingInfoDb]] = delegate( - _.listUtxos(hdAccount)) + tag: AddressTag + ): Future[Vector[SpendingInfoDb]] = delegate(_.listUtxos(hdAccount)) override def listUtxos( hdAccount: HDAccount, - state: TxoState): Future[Vector[SpendingInfoDb]] = delegate( - _.listUtxos(hdAccount, state)) + state: TxoState + ): Future[Vector[SpendingInfoDb]] = delegate(_.listUtxos(hdAccount, state)) override def listAddresses(account: HDAccount): Future[Vector[AddressDb]] = delegate(_.listAddresses(account)) override def listSpentAddresses( - account: HDAccount): Future[Vector[AddressDb]] = delegate( - _.listSpentAddresses(account)) + account: HDAccount + ): Future[Vector[AddressDb]] = delegate(_.listSpentAddresses(account)) override def listFundedAddresses( - account: HDAccount): Future[Vector[(AddressDb, CurrencyUnit)]] = delegate( - _.listFundedAddresses(account)) + account: HDAccount + ): Future[Vector[(AddressDb, CurrencyUnit)]] = delegate( + _.listFundedAddresses(account) + ) override def listUnusedAddresses( - account: HDAccount): Future[Vector[AddressDb]] = delegate( - _.listUnusedAddresses(account)) + account: HDAccount + ): Future[Vector[AddressDb]] = delegate(_.listUnusedAddresses(account)) override def clearAllUtxos(): Future[HDWalletApi] = delegate( - _.clearAllUtxos()) + _.clearAllUtxos() + ) override def clearUtxos(account: HDAccount): Future[HDWalletApi] = delegate( - _.clearUtxos(account)) + _.clearUtxos(account) + ) override def clearAllAddresses(): Future[WalletApi] = { delegate(_.clearAllAddresses()) @@ -596,20 +656,25 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit override def getAddress( account: AccountDb, chainType: HDChainType, - addressIndex: Int): Future[AddressDb] = delegate( - _.getAddress(account, chainType, addressIndex)) + addressIndex: Int + ): Future[AddressDb] = delegate( + _.getAddress(account, chainType, addressIndex) + ) override def listAccounts(): Future[Vector[AccountDb]] = delegate( - _.listAccounts()) + _.listAccounts() + ) override def createNewAccount( - keyManagerParams: KeyManagerParams): Future[HDWalletApi] = delegate( - _.createNewAccount(keyManagerParams)) + keyManagerParams: KeyManagerParams + ): Future[HDWalletApi] = delegate(_.createNewAccount(keyManagerParams)) override def createNewAccount( hdAccount: HDAccount, - keyManagerParams: KeyManagerParams): Future[HDWalletApi] = delegate( - _.createNewAccount(hdAccount, keyManagerParams)) + keyManagerParams: KeyManagerParams + ): Future[HDWalletApi] = delegate( + _.createNewAccount(hdAccount, keyManagerParams) + ) override def getSyncDescriptorOpt(): Future[Option[SyncHeightDescriptor]] = delegate(_.getSyncDescriptorOpt()) @@ -625,19 +690,23 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit override def processTransactions( transactions: Vector[Transaction], - blockHash: Option[DoubleSha256DigestBE])(implicit - ec: ExecutionContext): Future[WalletApi] = delegate( - _.processTransactions(transactions, blockHash)) + blockHash: Option[DoubleSha256DigestBE] + )(implicit ec: ExecutionContext): Future[WalletApi] = delegate( + _.processTransactions(transactions, blockHash) + ) override def getBalance()(implicit - ec: ExecutionContext): Future[CurrencyUnit] = delegate(_.getBalance()) + ec: ExecutionContext + ): Future[CurrencyUnit] = delegate(_.getBalance()) override def getBalance(tag: AddressTag)(implicit - ec: ExecutionContext): Future[CurrencyUnit] = delegate(_.getBalance(tag)) + ec: ExecutionContext + ): Future[CurrencyUnit] = delegate(_.getBalance(tag)) override def getAddressInfo( spendingInfoDb: SpendingInfoDb, - networkParameters: NetworkParameters): Future[Option[AddressInfo]] = + networkParameters: NetworkParameters + ): Future[Option[AddressInfo]] = delegate(_.getAddressInfo(spendingInfoDb, networkParameters)) override def sendFromOutPoints( @@ -646,24 +715,27 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit amount: CurrencyUnit, feeRateOpt: Option[FeeUnit] )(implicit ec: ExecutionContext): Future[Transaction] = delegate( - _.sendFromOutPoints(outPoints, address, amount, feeRateOpt)) + _.sendFromOutPoints(outPoints, address, amount, feeRateOpt) + ) override def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, feeRateOpt: Option[FeeUnit] )(implicit ec: ExecutionContext): Future[Transaction] = delegate( - _.sendFromOutPoints(outPoints, address, feeRateOpt)) + _.sendFromOutPoints(outPoints, address, feeRateOpt) + ) override def sweepWallet(address: BitcoinAddress)(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sweepWallet(address)) + ec: ExecutionContext + ): Future[Transaction] = delegate(_.sweepWallet(address)) override def sweepWallet( address: BitcoinAddress, - feeRateOpt: Option[FeeUnit])(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sweepWallet(address, feeRateOpt)) + feeRateOpt: Option[FeeUnit] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.sweepWallet(address, feeRateOpt) + ) override def sendWithAlgo( address: BitcoinAddress, @@ -671,50 +743,59 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit feeRateOpt: Option[FeeUnit], algo: CoinSelectionAlgo )(implicit ec: ExecutionContext): Future[Transaction] = delegate( - _.sendWithAlgo(address, amount, feeRateOpt, algo)) + _.sendWithAlgo(address, amount, feeRateOpt, algo) + ) override def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, feeRateOpt: Option[FeeUnit] )(implicit ec: ExecutionContext): Future[Transaction] = delegate( - _.sendToAddress(address, amount, feeRateOpt)) + _.sendToAddress(address, amount, feeRateOpt) + ) override def sendToOutputs( outputs: Vector[TransactionOutput], - feeRateOpt: Option[FeeUnit])(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sendToOutputs(outputs, feeRateOpt)) + feeRateOpt: Option[FeeUnit] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.sendToOutputs(outputs, feeRateOpt) + ) override def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], - feeRateOpt: Option[FeeUnit])(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.sendToAddresses(addresses, amounts, feeRateOpt)) + feeRateOpt: Option[FeeUnit] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.sendToAddresses(addresses, amounts, feeRateOpt) + ) override def makeOpReturnCommitment( message: String, hashMessage: Boolean, - feeRateOpt: Option[FeeUnit])(implicit - ec: ExecutionContext): Future[Transaction] = delegate( - _.makeOpReturnCommitment(message, hashMessage, feeRateOpt)) + feeRateOpt: Option[FeeUnit] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( + _.makeOpReturnCommitment(message, hashMessage, feeRateOpt) + ) override def getBalance(account: HDAccount)(implicit - ec: ExecutionContext): Future[CurrencyUnit] = delegate( - _.getBalance(account)) + ec: ExecutionContext + ): Future[CurrencyUnit] = delegate(_.getBalance(account)) override def processCompactFilter( blockHash: DoubleSha256DigestBE, - blockFilter: GolombFilter): Future[NeutrinoHDWalletApi] = + blockFilter: GolombFilter + ): Future[NeutrinoHDWalletApi] = delegate(_.processCompactFilter(blockHash, blockFilter)) override def fullRescanNeutrinoWallet(addressBatchSize: Int, force: Boolean)( - implicit ec: ExecutionContext): Future[RescanState] = delegate( - _.fullRescanNeutrinoWallet(addressBatchSize, force)) + implicit ec: ExecutionContext + ): Future[RescanState] = delegate( + _.fullRescanNeutrinoWallet(addressBatchSize, force) + ) override def getNewChangeAddress()(implicit - ec: ExecutionContext): Future[BitcoinAddress] = + ec: ExecutionContext + ): Future[BitcoinAddress] = delegate(_.getNewChangeAddress()) override def sendWithAlgo( @@ -722,8 +803,8 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit amount: CurrencyUnit, feeRate: FeeUnit, algo: CoinSelectionAlgo, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendWithAlgo(address, amount, feeRate, algo, fromAccount)) override def sendWithAlgo( @@ -731,16 +812,16 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit amount: CurrencyUnit, feeRateOpt: Option[FeeUnit], algo: CoinSelectionAlgo, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendWithAlgo(address, amount, feeRateOpt, algo, fromAccount)) override def sendWithAlgo( address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - algo: CoinSelectionAlgo)(implicit - ec: ExecutionContext): Future[Transaction] = + algo: CoinSelectionAlgo + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendWithAlgo(address, amount, feeRate, algo)) override def sendWithAlgo( @@ -748,8 +829,8 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit amount: CurrencyUnit, feeRate: FeeUnit, algo: CoinSelectionAlgo, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendWithAlgo(address, amount, feeRate, algo, newTags)) override def sendFromOutPoints( @@ -757,26 +838,29 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( - _.sendFromOutPoints(outPoints, address, amount, feeRate, fromAccount)) + _.sendFromOutPoints(outPoints, address, amount, feeRate, fromAccount) + ) override def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, amount: CurrencyUnit, feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( - _.sendFromOutPoints(outPoints, address, amount, feeRateOpt, fromAccount)) + _.sendFromOutPoints(outPoints, address, amount, feeRateOpt, fromAccount) + ) override def sendFromOutPoints( outPoints: Vector[TransactionOutPoint], address: BitcoinAddress, amount: CurrencyUnit, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendFromOutPoints(outPoints, address, amount, feeRate)) override def sendFromOutPoints( @@ -784,117 +868,124 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendFromOutPoints(outPoints, address, amount, feeRate, newTags)) override def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToAddress(address, amount, feeRate, fromAccount)) override def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToAddress(address, amount, feeRateOpt, fromAccount)) override def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToAddress(address, amount, feeRate)) override def sendToAddress( address: BitcoinAddress, amount: CurrencyUnit, feeRate: FeeUnit, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToAddress(address, amount, feeRate, newTags)) override def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToAddresses(addresses, amounts, feeRate, fromAccount)) override def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToAddresses(addresses, amounts, feeRateOpt, fromAccount)) override def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToAddresses(addresses, amounts, feeRate)) override def sendToAddresses( addresses: Vector[BitcoinAddress], amounts: Vector[CurrencyUnit], feeRate: FeeUnit, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToAddresses(addresses, amounts, feeRate, newTags)) override def sendToOutputs( outputs: Vector[TransactionOutput], feeRate: FeeUnit, - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToOutputs(outputs, feeRate, fromAccount)) override def sendToOutputs( outputs: Vector[TransactionOutput], feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToOutputs(outputs, feeRateOpt, fromAccount)) override def sendToOutputs( outputs: Vector[TransactionOutput], feeRate: FeeUnit, - newTags: Vector[AddressTag])(implicit - ec: ExecutionContext): Future[Transaction] = + newTags: Vector[AddressTag] + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToOutputs(outputs, feeRate, newTags)) override def sendToOutputs( outputs: Vector[TransactionOutput], - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.sendToOutputs(outputs, feeRate)) override def makeOpReturnCommitment( message: String, hashMessage: Boolean, feeRateOpt: Option[FeeUnit], - fromAccount: AccountDb)(implicit - ec: ExecutionContext): Future[Transaction] = + fromAccount: AccountDb + )(implicit ec: ExecutionContext): Future[Transaction] = delegate( - _.makeOpReturnCommitment(message, hashMessage, feeRateOpt, fromAccount)) + _.makeOpReturnCommitment(message, hashMessage, feeRateOpt, fromAccount) + ) override def makeOpReturnCommitment( message: String, hashMessage: Boolean, - feeRate: FeeUnit)(implicit ec: ExecutionContext): Future[Transaction] = + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Transaction] = delegate(_.makeOpReturnCommitment(message, hashMessage, feeRate)) override def getAddress(chainType: HDChainType, addressIndex: Int)(implicit - ec: ExecutionContext): Future[AddressDb] = + ec: ExecutionContext + ): Future[AddressDb] = delegate(_.getAddress(chainType, addressIndex)) override def listAccounts(purpose: HDPurpose)(implicit - ec: ExecutionContext): Future[Vector[AccountDb]] = + ec: ExecutionContext + ): Future[Vector[AccountDb]] = delegate(_.listAccounts(purpose)) override def createDLCOffer( @@ -904,15 +995,18 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit refundLT: UInt32, peerAddressOpt: Option[InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[ - DLCMessage.DLCOffer] = delegate( - _.createDLCOffer(contractInfoTLV, - collateral, - feeRateOpt, - refundLT, - peerAddressOpt, - externalPayoutAddressOpt, - externalChangeAddressOpt)) + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCMessage.DLCOffer] = delegate( + _.createDLCOffer( + contractInfoTLV, + collateral, + feeRateOpt, + refundLT, + peerAddressOpt, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) + ) override def createDLCOffer( contractInfoTLV: ContractInfoTLV, @@ -922,50 +1016,61 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit refundLT: UInt32, peerAddressOpt: Option[InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[ - DLCMessage.DLCOffer] = delegate( - _.createDLCOffer(contractInfoTLV, - collateral, - feeRateOpt, - locktime, - refundLT, - peerAddressOpt, - externalPayoutAddressOpt, - externalChangeAddressOpt)) + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCMessage.DLCOffer] = delegate( + _.createDLCOffer( + contractInfoTLV, + collateral, + feeRateOpt, + locktime, + refundLT, + peerAddressOpt, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) + ) override def acceptDLCOffer( dlcOfferTLV: DLCOfferTLV, peerAddress: Option[InetSocketAddress], externalPayoutAddressOpt: Option[BitcoinAddress], - externalChangeAddressOpt: Option[BitcoinAddress]): Future[ - DLCMessage.DLCAccept] = delegate( - _.acceptDLCOffer(dlcOfferTLV, - peerAddress, - externalPayoutAddressOpt, - externalChangeAddressOpt)) + externalChangeAddressOpt: Option[BitcoinAddress] + ): Future[DLCMessage.DLCAccept] = delegate( + _.acceptDLCOffer( + dlcOfferTLV, + peerAddress, + externalPayoutAddressOpt, + externalChangeAddressOpt + ) + ) override def executeDLC( contractId: ByteVector, - oracleSig: OracleAttestmentTLV): Future[Option[Transaction]] = + oracleSig: OracleAttestmentTLV + ): Future[Option[Transaction]] = delegate(_.executeDLC(contractId, oracleSig)) override def executeDLC( contractId: ByteVector, - oracleSig: OracleSignatures): Future[Option[Transaction]] = + oracleSig: OracleSignatures + ): Future[Option[Transaction]] = delegate(_.executeDLC(contractId, oracleSig)) - override def findByOutPoints(outPoints: Vector[TransactionOutPoint]): Future[ - Vector[SpendingInfoDb]] = { + override def findByOutPoints( + outPoints: Vector[TransactionOutPoint] + ): Future[Vector[SpendingInfoDb]] = { delegate(_.findByOutPoints(outPoints)) } override def findByTxIds( - txIds: Vector[DoubleSha256DigestBE]): Future[Vector[TransactionDb]] = { + txIds: Vector[DoubleSha256DigestBE] + ): Future[Vector[TransactionDb]] = { delegate(_.findByTxIds(txIds)) } override def findOutputsBeingSpent( - tx: Transaction): Future[Vector[SpendingInfoDb]] = { + tx: Transaction + ): Future[Vector[SpendingInfoDb]] = { delegate(_.findOutputsBeingSpent(tx)) } @@ -978,7 +1083,8 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit } override def findByScriptPubKey( - scriptPubKey: ScriptPubKey): Future[Vector[SpendingInfoDb]] = { + scriptPubKey: ScriptPubKey + ): Future[Vector[SpendingInfoDb]] = { delegate(_.findByScriptPubKey(scriptPubKey)) } @@ -988,19 +1094,24 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit inputAmount: CurrencyUnit, sentAmount: CurrencyUnit, blockHashOpt: Option[DoubleSha256DigestBE], - newTags: Vector[AddressTag]): Future[ProcessTxResult] = { + newTags: Vector[AddressTag] + ): Future[ProcessTxResult] = { delegate( - _.processOurTransaction(transaction = transaction, - feeRate = feeRate, - inputAmount = inputAmount, - sentAmount = sentAmount, - blockHashOpt = blockHashOpt, - newTags = newTags)) + _.processOurTransaction( + transaction = transaction, + feeRate = feeRate, + inputAmount = inputAmount, + sentAmount = sentAmount, + blockHashOpt = blockHashOpt, + newTags = newTags + ) + ) } } object WalletHolder { def empty(implicit ec: ExecutionContext): WalletHolder = new WalletHolder( - None) + None + ) } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/callback/WalletCallbackStreamManager.scala b/wallet/src/main/scala/org/bitcoins/wallet/callback/WalletCallbackStreamManager.scala index df63bf987e..75f5d85017 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/callback/WalletCallbackStreamManager.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/callback/WalletCallbackStreamManager.scala @@ -31,9 +31,8 @@ case class WalletCallbackStreamManager( with BitcoinSLogger { import system.dispatcher - private val txProcessedQueueSource: Source[ - Transaction, - SourceQueueWithComplete[Transaction]] = { + private val txProcessedQueueSource + : Source[Transaction, SourceQueueWithComplete[Transaction]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -47,9 +46,8 @@ case class WalletCallbackStreamManager( matSourceAndQueue(txProcessedQueueSource, txProcessedSink) } - private val txBroadcastQueueSource: Source[ - Transaction, - SourceQueueWithComplete[Transaction]] = { + private val txBroadcastQueueSource + : Source[Transaction, SourceQueueWithComplete[Transaction]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -63,15 +61,16 @@ case class WalletCallbackStreamManager( matSourceAndQueue(txBroadcastQueueSource, txBroadcastSink) } - private val onReservedUtxosSource: Source[ - Vector[SpendingInfoDb], - SourceQueueWithComplete[Vector[SpendingInfoDb]]] = { + private val onReservedUtxosSource + : Source[Vector[ + SpendingInfoDb + ], + SourceQueueWithComplete[Vector[SpendingInfoDb]]] = { Source.queue(maxBufferSize, overflowStrategy) } - private val onReservedUtxosSink: Sink[ - Vector[SpendingInfoDb], - Future[Done]] = { + private val onReservedUtxosSink + : Sink[Vector[SpendingInfoDb], Future[Done]] = { Sink.foreachAsync(1) { case utxos => callbacks.executeOnReservedUtxos(utxos) } @@ -81,9 +80,8 @@ case class WalletCallbackStreamManager( matSourceAndQueue(onReservedUtxosSource, onReservedUtxosSink) } - private val onAddressGeneratedSource: Source[ - BitcoinAddress, - SourceQueueWithComplete[BitcoinAddress]] = { + private val onAddressGeneratedSource + : Source[BitcoinAddress, SourceQueueWithComplete[BitcoinAddress]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -97,9 +95,8 @@ case class WalletCallbackStreamManager( matSourceAndQueue(onAddressGeneratedSource, onAddressGeneratedSink) } - private val onBlockProcessedSource: Source[ - Block, - SourceQueueWithComplete[Block]] = { + private val onBlockProcessedSource + : Source[Block, SourceQueueWithComplete[Block]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -113,9 +110,8 @@ case class WalletCallbackStreamManager( matSourceAndQueue(onBlockProcessedSource, onBockProcessedSink) } - private val onRescanCompleteSource: Source[ - String, - SourceQueueWithComplete[String]] = { + private val onRescanCompleteSource + : Source[String, SourceQueueWithComplete[String]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -129,9 +125,8 @@ case class WalletCallbackStreamManager( matSourceAndQueue(onRescanCompleteSource, onRescanCompleteSink) } - private val onFeeChangeSource: Source[ - FeeUnit, - SourceQueueWithComplete[FeeUnit]] = { + private val onFeeChangeSource + : Source[FeeUnit, SourceQueueWithComplete[FeeUnit]] = { Source.queue(maxBufferSize, overflowStrategy) } @@ -152,9 +147,9 @@ case class WalletCallbackStreamManager( override def stop(): Future[Unit] = { val start = System.currentTimeMillis() - //can't complete a stream twice + // can't complete a stream twice if (!isStopped.get()) { - //complete all queues + // complete all queues txProcessedQueue.complete() txBroadcastQueue.complete() onReservedUtxosQueue.complete() @@ -165,7 +160,8 @@ case class WalletCallbackStreamManager( isStopped.set(true) } else { logger.warn( - s"Already stopped all queues associated with this NodeCallBackStreamManager") + s"Already stopped all queues associated with this NodeCallBackStreamManager" + ) } for { @@ -179,42 +175,38 @@ case class WalletCallbackStreamManager( } yield { logger.info( s"Done draining akka streams for WalletCallbackStreamManager, it took=${System - .currentTimeMillis() - start}ms") + .currentTimeMillis() - start}ms" + ) () } } private def matSourceAndQueue[T]( source: Source[T, SourceQueueWithComplete[T]], - sink: Sink[T, Future[Done]]): ( - SourceQueueWithComplete[T], - Future[Done]) = { + sink: Sink[T, Future[Done]] + ): (SourceQueueWithComplete[T], Future[Done]) = { source .toMat(sink)(Keep.both) .run() } - override def onTransactionProcessed: CallbackHandler[ - Transaction, - OnTransactionProcessed] = { + override def onTransactionProcessed + : CallbackHandler[Transaction, OnTransactionProcessed] = { callbacks.onTransactionProcessed } - override def onTransactionBroadcast: CallbackHandler[ - Transaction, - OnTransactionBroadcast] = { + override def onTransactionBroadcast + : CallbackHandler[Transaction, OnTransactionBroadcast] = { callbacks.onTransactionBroadcast } - override def onReservedUtxos: CallbackHandler[ - Vector[SpendingInfoDb], - OnReservedUtxos] = { + override def onReservedUtxos + : CallbackHandler[Vector[SpendingInfoDb], OnReservedUtxos] = { callbacks.onReservedUtxos } - override def onNewAddressGenerated: CallbackHandler[ - BitcoinAddress, - OnNewAddressGenerated] = { + override def onNewAddressGenerated + : CallbackHandler[BitcoinAddress, OnNewAddressGenerated] = { callbacks.onNewAddressGenerated } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/callback/WalletCallbacks.scala b/wallet/src/main/scala/org/bitcoins/wallet/callback/WalletCallbacks.scala index 0d0942bc18..97c2b6c5f0 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/callback/WalletCallbacks.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/callback/WalletCallbacks.scala @@ -11,27 +11,23 @@ import org.bitcoins.core.wallet.fee.FeeUnit import scala.concurrent.{ExecutionContext, Future} -/** Callbacks for responding to events in the wallet. - * The appropriate callback is executed whenever the wallet finishes, - * the corresponding function. +/** Callbacks for responding to events in the wallet. The appropriate callback + * is executed whenever the wallet finishes, the corresponding function. */ trait WalletCallbacks extends ModuleCallbacks[WalletCallbacks] with BitcoinSLogger { - def onTransactionProcessed: CallbackHandler[ - Transaction, - OnTransactionProcessed] + def onTransactionProcessed + : CallbackHandler[Transaction, OnTransactionProcessed] - def onTransactionBroadcast: CallbackHandler[ - Transaction, - OnTransactionBroadcast] + def onTransactionBroadcast + : CallbackHandler[Transaction, OnTransactionBroadcast] def onReservedUtxos: CallbackHandler[Vector[SpendingInfoDb], OnReservedUtxos] - def onNewAddressGenerated: CallbackHandler[ - BitcoinAddress, - OnNewAddressGenerated] + def onNewAddressGenerated + : CallbackHandler[BitcoinAddress, OnNewAddressGenerated] def onBlockProcessed: CallbackHandler[Block, OnBlockProcessed] @@ -41,70 +37,95 @@ trait WalletCallbacks def +(other: WalletCallbacks): WalletCallbacks - def executeOnTransactionProcessed(tx: Transaction)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnTransactionProcessed( + tx: Transaction + )(implicit ec: ExecutionContext): Future[Unit] = { onTransactionProcessed.execute( tx, (err: Throwable) => logger.error( s"${onTransactionProcessed.name} Callback failed with error: ", - err)) + err + ) + ) } - def executeOnTransactionBroadcast(tx: Transaction)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnTransactionBroadcast( + tx: Transaction + )(implicit ec: ExecutionContext): Future[Unit] = { onTransactionBroadcast.execute( tx, (err: Throwable) => logger.error( s"${onTransactionProcessed.name} Callback failed with error: ", - err)) + err + ) + ) } - def executeOnReservedUtxos(utxos: Vector[SpendingInfoDb])(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnReservedUtxos( + utxos: Vector[SpendingInfoDb] + )(implicit ec: ExecutionContext): Future[Unit] = { onReservedUtxos.execute( utxos, (err: Throwable) => - logger.error(s"${onReservedUtxos.name} Callback failed with error: ", - err)) + logger.error( + s"${onReservedUtxos.name} Callback failed with error: ", + err + ) + ) } - def executeOnNewAddressGenerated(address: BitcoinAddress)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnNewAddressGenerated( + address: BitcoinAddress + )(implicit ec: ExecutionContext): Future[Unit] = { onNewAddressGenerated.execute( address, (err: Throwable) => logger.error( s"${onNewAddressGenerated.name} Callback failed with error: ", - err)) + err + ) + ) } - def executeOnBlockProcessed(block: Block)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnBlockProcessed( + block: Block + )(implicit ec: ExecutionContext): Future[Unit] = { onBlockProcessed.execute( block, (err: Throwable) => - logger.error(s"${onBlockProcessed.name} Callback failed with error: ", - err)) + logger.error( + s"${onBlockProcessed.name} Callback failed with error: ", + err + ) + ) } - def executeOnRescanComplete(walletName: String)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnRescanComplete( + walletName: String + )(implicit ec: ExecutionContext): Future[Unit] = { onRescanComplete.execute( walletName, (err: Throwable) => - logger.error(s"${onRescanComplete.name} Callback failed with error: ", - err)) + logger.error( + s"${onRescanComplete.name} Callback failed with error: ", + err + ) + ) } - def executeOnFeeRateChanged(feeRate: FeeUnit)(implicit - ec: ExecutionContext): Future[Unit] = { + def executeOnFeeRateChanged( + feeRate: FeeUnit + )(implicit ec: ExecutionContext): Future[Unit] = { onFeeRateChanged.execute( feeRate, (err: Throwable) => - logger.error(s"${onFeeRateChanged.name} Callback failed with error: ", - err)) + logger.error( + s"${onFeeRateChanged.name} Callback failed with error: ", + err + ) + ) } } @@ -114,14 +135,17 @@ object WalletCallbacks extends CallbackFactory[WalletCallbacks] { private case class WalletCallbacksImpl( onTransactionProcessed: CallbackHandler[ Transaction, - OnTransactionProcessed], + OnTransactionProcessed + ], onTransactionBroadcast: CallbackHandler[ Transaction, - OnTransactionBroadcast], + OnTransactionBroadcast + ], onReservedUtxos: CallbackHandler[Vector[SpendingInfoDb], OnReservedUtxos], onNewAddressGenerated: CallbackHandler[ BitcoinAddress, - OnNewAddressGenerated], + OnNewAddressGenerated + ], onBlockProcessed: CallbackHandler[Block, OnBlockProcessed], onRescanComplete: CallbackHandler[String, OnRescanComplete], onFeeRateChanged: CallbackHandler[FeeUnit, OnFeeRateChanged] @@ -150,7 +174,9 @@ object WalletCallbacks extends CallbackFactory[WalletCallbacks] { def onTransactionBroadcast(f: OnTransactionBroadcast): WalletCallbacks = WalletCallbacks(onTransactionBroadcast = Vector(f)) - /** Constructs a set of callbacks that only acts on utxos becoming reserved or unreserved */ + /** Constructs a set of callbacks that only acts on utxos becoming reserved or + * unreserved + */ def onReservedUtxos(f: OnReservedUtxos): WalletCallbacks = WalletCallbacks(onReservedUtxos = Vector(f)) @@ -168,12 +194,14 @@ object WalletCallbacks extends CallbackFactory[WalletCallbacks] { /** Empty callbacks that does nothing with the received data */ override val empty: WalletCallbacks = - apply(Vector.empty, - Vector.empty, - Vector.empty, - Vector.empty, - Vector.empty, - Vector.empty) + apply( + Vector.empty, + Vector.empty, + Vector.empty, + Vector.empty, + Vector.empty, + Vector.empty + ) def apply( onTransactionProcessed: Vector[OnTransactionProcessed] = Vector.empty, @@ -188,29 +216,35 @@ object WalletCallbacks extends CallbackFactory[WalletCallbacks] { onTransactionProcessed = CallbackHandler[Transaction, OnTransactionProcessed]( "onTransactionProcessed", - onTransactionProcessed), + onTransactionProcessed + ), onTransactionBroadcast = CallbackHandler[Transaction, OnTransactionBroadcast]( "onTransactionBroadcast", - onTransactionBroadcast), + onTransactionBroadcast + ), onReservedUtxos = CallbackHandler[Vector[SpendingInfoDb], OnReservedUtxos]( "onReservedUtxos", - onReservedUtxos), + onReservedUtxos + ), onNewAddressGenerated = CallbackHandler[BitcoinAddress, OnNewAddressGenerated]( "onNewAddressGenerated", - onNewAddressGenerated), + onNewAddressGenerated + ), onBlockProcessed = CallbackHandler[Block, OnBlockProcessed]( "onBlockProcessed", onBlockProcessed ), - onRescanComplete = - CallbackHandler[String, OnRescanComplete]("onRescanComplete", - onRescanComplete), - onFeeRateChanged = - CallbackHandler[FeeUnit, OnFeeRateChanged]("onFeeRateChanged", - onFeeRateChanged) + onRescanComplete = CallbackHandler[String, OnRescanComplete]( + "onRescanComplete", + onRescanComplete + ), + onFeeRateChanged = CallbackHandler[FeeUnit, OnFeeRateChanged]( + "onFeeRateChanged", + onFeeRateChanged + ) ) } } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala b/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala index 3277df7857..98d9178b33 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala @@ -39,14 +39,16 @@ import scala.concurrent.duration.{ import scala.concurrent.{Await, ExecutionContext, Future} /** Configuration for the Bitcoin-S wallet - * @param directory The data directory of the wallet - * @param conf Optional sequence of configuration overrides + * @param directory + * The data directory of the wallet + * @param conf + * Optional sequence of configuration overrides */ case class WalletAppConfig( baseDatadir: Path, configOverrides: Vector[Config], - kmConfOpt: Option[KeyManagerAppConfig] = None)(implicit - val system: ActorSystem) + kmConfOpt: Option[KeyManagerAppConfig] = None +)(implicit val system: ActorSystem) extends DbAppConfig with WalletDbManagement with JdbcProfileComponent[WalletAppConfig] @@ -61,7 +63,8 @@ case class WalletAppConfig( override protected[bitcoins] type ConfigType = WalletAppConfig override protected[bitcoins] def newConfigOfType( - configs: Vector[Config]): WalletAppConfig = + configs: Vector[Config] + ): WalletAppConfig = WalletAppConfig(baseDatadir, configs) override def appConfig: WalletAppConfig = this @@ -73,7 +76,9 @@ case class WalletAppConfig( Executors.newScheduledThreadPool( 1, AsyncUtil.getNewThreadFactory( - s"bitcoin-s-wallet-scheduler-${System.currentTimeMillis()}")) + s"bitcoin-s-wallet-scheduler-${System.currentTimeMillis()}" + ) + ) } private lazy val rescanThreadFactory: ThreadFactory = @@ -81,8 +86,10 @@ case class WalletAppConfig( /** Threads for rescanning the wallet */ private[wallet] lazy val rescanThreadPool: ExecutorService = - Executors.newFixedThreadPool(Runtime.getRuntime.availableProcessors(), - rescanThreadFactory) + Executors.newFixedThreadPool( + Runtime.getRuntime.availableProcessors(), + rescanThreadFactory + ) override lazy val callbackFactory: WalletCallbacks.type = WalletCallbacks @@ -112,8 +119,10 @@ case class WalletAppConfig( lazy val defaultAccount: HDAccount = { val purpose = defaultAccountKind - HDAccount(coin = HDCoin(purpose, HDCoinType.fromNetwork(network)), - index = 0) + HDAccount( + coin = HDCoin(purpose, HDCoinType.fromNetwork(network)), + index = 0 + ) } lazy val bloomFalsePositiveRate: Double = @@ -127,15 +136,19 @@ case class WalletAppConfig( lazy val requiredConfirmations: Int = { val confs = config.getInt("bitcoin-s.wallet.requiredConfirmations") - require(confs >= 1, - s"requiredConfirmations cannot be less than 1, got: $confs") + require( + confs >= 1, + s"requiredConfirmations cannot be less than 1, got: $confs" + ) confs } lazy val longTermFeeRate: SatoshisPerVirtualByte = { val feeRate = config.getInt("bitcoin-s.wallet.longTermFeeRate") - require(feeRate >= 0, - s"longTermFeeRate cannot be less than 0, got: $feeRate") + require( + feeRate >= 0, + s"longTermFeeRate cannot be less than 0, got: $feeRate" + ) SatoshisPerVirtualByte.fromLong(feeRate) } @@ -187,8 +200,10 @@ case class WalletAppConfig( override lazy val schemaName: Option[String] = { driver match { case PostgreSQL => - val schema = PostgresUtil.getSchemaName(moduleName = moduleName, - walletName = walletName) + val schema = PostgresUtil.getSchemaName( + moduleName = moduleName, + walletName = walletName + ) Some(schema) case SQLite => None @@ -209,7 +224,8 @@ case class WalletAppConfig( isExists <- seedExists() _ <- { logger.info( - s"Starting wallet with xpub=${masterXpub} walletName=${walletName}") + s"Starting wallet with xpub=${masterXpub} walletName=${walletName}" + ) if (!isExists) { masterXPubDAO .create(masterXpub) @@ -221,7 +237,7 @@ case class WalletAppConfig( } yield { logger.debug(s"Initializing wallet setup") if (isHikariLoggingEnabled) { - //.get is safe because hikari logging is enabled + // .get is safe because hikari logging is enabled startHikariLogger(hikariLoggingInterval.get) } logger.info(s"Applied $numMigrations to the wallet project") @@ -241,9 +257,9 @@ case class WalletAppConfig( stopCallbacksF.flatMap { _ => clearCallbacks() stopRebroadcastTxsScheduler() - //this eagerly shuts down all scheduled tasks on the scheduler - //in the future, we should actually cancel all things that are scheduled - //manually, and then shutdown the scheduler + // this eagerly shuts down all scheduled tasks on the scheduler + // in the future, we should actually cancel all things that are scheduled + // manually, and then shutdown the scheduler scheduler.shutdownNow() rescanThreadPool.shutdownNow() super.stop() @@ -257,7 +273,8 @@ case class WalletAppConfig( def kmParams: KeyManagerParams = KeyManagerParams(kmConf.seedPath, defaultAccountKind, network) - /** How much elements we can have in [[org.bitcoins.wallet.internal.AddressHandling.addressRequestQueue]] + /** How much elements we can have in + * [[org.bitcoins.wallet.internal.AddressHandling.addressRequestQueue]] * before we throw an exception */ def addressQueueSize: Int = { @@ -268,7 +285,8 @@ case class WalletAppConfig( } } - /** How long we wait while generating an address in [[org.bitcoins.wallet.internal.AddressHandling.addressRequestQueue]] + /** How long we wait while generating an address in + * [[org.bitcoins.wallet.internal.AddressHandling.addressRequestQueue]] * before we timeout */ def addressQueueTimeout: Duration = { @@ -282,13 +300,12 @@ case class WalletAppConfig( } /** Checks if the following exist - * 1. A seed exists - * 2. wallet exists - * 3. The account exists + * 1. A seed exists 2. wallet exists 3. The account exists */ def hasWallet()(implicit walletConf: WalletAppConfig, - ec: ExecutionContext): Future[Boolean] = { + ec: ExecutionContext + ): Future[Boolean] = { if (kmConf.seedExists()) { val hdCoin = walletConf.defaultAccount.coin val walletDB = walletConf.dbPath resolve walletConf.dbName @@ -309,20 +326,23 @@ case class WalletAppConfig( def createHDWallet( nodeApi: NodeApi, chainQueryApi: ChainQueryApi, - feeRateApi: FeeRateApi)(implicit system: ActorSystem): Future[Wallet] = { - WalletAppConfig.createHDWallet(nodeApi = nodeApi, - chainQueryApi = chainQueryApi, - feeRateApi = feeRateApi)(this, system) + feeRateApi: FeeRateApi + )(implicit system: ActorSystem): Future[Wallet] = { + WalletAppConfig.createHDWallet( + nodeApi = nodeApi, + chainQueryApi = chainQueryApi, + feeRateApi = feeRateApi + )(this, system) } - private[this] var rebroadcastTransactionsCancelOpt: Option[ - ScheduledFuture[_]] = None + private[this] var rebroadcastTransactionsCancelOpt + : Option[ScheduledFuture[_]] = None /** Starts the wallet's rebroadcast transaction scheduler */ def startRebroadcastTxsScheduler(wallet: Wallet): Unit = synchronized { rebroadcastTransactionsCancelOpt match { case Some(_) => - //already scheduled, do nothing + // already scheduled, do nothing () case None => logger.info(s"Starting wallet rebroadcast task") @@ -330,10 +350,12 @@ case class WalletAppConfig( val interval = rebroadcastFrequency.toSeconds val initDelay = interval val future = - scheduler.scheduleAtFixedRate(RebroadcastTransactionsRunnable(wallet), - initDelay, - interval, - TimeUnit.SECONDS) + scheduler.scheduleAtFixedRate( + RebroadcastTransactionsRunnable(wallet), + initDelay, + interval, + TimeUnit.SECONDS + ) rebroadcastTransactionsCancelOpt = Some(future) () } @@ -354,8 +376,8 @@ case class WalletAppConfig( } } - /** The creation time of the mnemonic seed - * If we cannot decrypt the seed because of invalid passwords, we return None + /** The creation time of the mnemonic seed If we cannot decrypt the seed + * because of invalid passwords, we return None */ def creationTime: Instant = { kmConf.creationTime @@ -371,20 +393,23 @@ object WalletAppConfig val moduleName: String = "wallet" - /** Constructs a wallet configuration from the default Bitcoin-S - * data directory and given list of configuration overrides. + /** Constructs a wallet configuration from the default Bitcoin-S data + * directory and given list of configuration overrides. */ override def fromDatadir(datadir: Path, confs: Vector[Config])(implicit - system: ActorSystem): WalletAppConfig = + system: ActorSystem + ): WalletAppConfig = WalletAppConfig(datadir, confs) /** Creates a wallet based on the given [[WalletAppConfig]] */ def createHDWallet( nodeApi: NodeApi, chainQueryApi: ChainQueryApi, - feeRateApi: FeeRateApi)(implicit + feeRateApi: FeeRateApi + )(implicit walletConf: WalletAppConfig, - system: ActorSystem): Future[Wallet] = { + system: ActorSystem + ): Future[Wallet] = { import system.dispatcher walletConf.hasWallet().flatMap { walletExists => val bip39PasswordOpt = walletConf.bip39PasswordOpt @@ -399,15 +424,17 @@ object WalletAppConfig val unInitializedWallet = Wallet(nodeApi, chainQueryApi, feeRateApi) - Wallet.initialize(wallet = unInitializedWallet, - bip39PasswordOpt = bip39PasswordOpt) + Wallet.initialize( + wallet = unInitializedWallet, + bip39PasswordOpt = bip39PasswordOpt + ) } } } case class RebroadcastTransactionsRunnable(wallet: Wallet)(implicit - ec: ExecutionContext) - extends Runnable { + ec: ExecutionContext + ) extends Runnable { override def run(): Unit = { val f = for { @@ -416,7 +443,8 @@ object WalletAppConfig _ = { if (txs.size > 1) logger.info( - s"Rebroadcasting ${txs.size} transactions, txids=${txs.map(_.txIdBE)}") + s"Rebroadcasting ${txs.size} transactions, txids=${txs.map(_.txIdBE)}" + ) } _ <- wallet.nodeApi.broadcastTransactions(txs) diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala index 3f22dd00cb..f29a769648 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala @@ -13,8 +13,8 @@ import org.bitcoins.wallet.Wallet import scala.concurrent.Future -/** Provides functionality related enumerating accounts. Account - * creation does not happen here, as that requires an unlocked wallet. +/** Provides functionality related enumerating accounts. Account creation does + * not happen here, as that requires an unlocked wallet. */ private[wallet] trait AccountHandling { self: Wallet => @@ -26,7 +26,9 @@ private[wallet] trait AccountHandling { self: Wallet => account.getOrElse( throw new RuntimeException( s"Could not find account with ${DEFAULT_HD_COIN.purpose.constant} " + - s"purpose field and ${DEFAULT_HD_COIN.coinType.toInt} coin field")) + s"purpose field and ${DEFAULT_HD_COIN.coinType.toInt} coin field" + ) + ) /** @inheritdoc */ override def getDefaultAccount(): Future[AccountDb] = { @@ -46,7 +48,8 @@ private[wallet] trait AccountHandling { self: Wallet => /** @inheritdoc */ override def getDefaultAccountForType( - addressType: AddressType): Future[AccountDb] = { + addressType: AddressType + ): Future[AccountDb] = { val hdCoin = addressType match { case Legacy => HDCoin(HDPurposes.Legacy, DEFAULT_HD_COIN_TYPE) case NestedSegWit => HDCoin(HDPurposes.NestedSegWit, DEFAULT_HD_COIN_TYPE) @@ -63,8 +66,8 @@ private[wallet] trait AccountHandling { self: Wallet => HDCoin(walletConfig.defaultAccountKind, coinType) } - /** The default HD coin type for this wallet, derived from - * the network we're on + /** The default HD coin type for this wallet, derived from the network we're + * on */ protected[wallet] lazy val DEFAULT_HD_COIN_TYPE: HDCoinType = { chainParams match { diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/AddressHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/AddressHandling.scala index c9362fdad0..66e2f1c03c 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/AddressHandling.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/AddressHandling.scala @@ -25,15 +25,16 @@ import slick.dbio.{DBIOAction, Effect, NoStream} import scala.concurrent.Future import scala.util.{Failure, Success} -/** Provides functionality related to addresses. This includes - * enumeratng and creating them, primarily. +/** Provides functionality related to addresses. This includes enumeratng and + * creating them, primarily. */ private[wallet] trait AddressHandling extends WalletLogger { self: Wallet => def contains( address: BitcoinAddress, - accountOpt: Option[HDAccount]): Future[Boolean] = { + accountOpt: Option[HDAccount] + ): Future[Boolean] = { val possibleAddressesF = accountOpt match { case Some(account) => listAddresses(account) @@ -69,7 +70,8 @@ private[wallet] trait AddressHandling extends WalletLogger { } override def listSpentAddresses( - account: HDAccount): Future[Vector[AddressDb]] = { + account: HDAccount + ): Future[Vector[AddressDb]] = { val spentAddressesF = addressDAO.getSpentAddresses spentAddressesF.map { spentAddresses => @@ -77,13 +79,14 @@ private[wallet] trait AddressHandling extends WalletLogger { } } - override def listFundedAddresses(): Future[ - Vector[(AddressDb, CurrencyUnit)]] = { + override def listFundedAddresses() + : Future[Vector[(AddressDb, CurrencyUnit)]] = { addressDAO.getFundedAddresses } override def listFundedAddresses( - account: HDAccount): Future[Vector[(AddressDb, CurrencyUnit)]] = { + account: HDAccount + ): Future[Vector[(AddressDb, CurrencyUnit)]] = { val spentAddressesF = addressDAO.getFundedAddresses spentAddressesF.map { spentAddresses => @@ -97,7 +100,8 @@ private[wallet] trait AddressHandling extends WalletLogger { } override def listUnusedAddresses( - account: HDAccount): Future[Vector[AddressDb]] = { + account: HDAccount + ): Future[Vector[AddressDb]] = { val unusedAddressesF = addressDAO.getUnusedAddresses unusedAddressesF.map { unusedAddresses => @@ -110,7 +114,8 @@ private[wallet] trait AddressHandling extends WalletLogger { scriptPubKeyDAO.findAll() override def watchScriptPubKey( - scriptPubKey: ScriptPubKey): Future[ScriptPubKeyDb] = + scriptPubKey: ScriptPubKey + ): Future[ScriptPubKeyDb] = scriptPubKeyDAO.createIfNotExists(ScriptPubKeyDb(scriptPubKey)) /** Enumerates the public keys in this wallet */ @@ -121,11 +126,12 @@ private[wallet] trait AddressHandling extends WalletLogger { protected[wallet] def listSPKs(): Future[Vector[ScriptPubKey]] = addressDAO.findAllSPKs() - /** Given a transaction, returns the outputs (with their corresponding outpoints) - * that pay to this wallet + /** Given a transaction, returns the outputs (with their corresponding + * outpoints) that pay to this wallet */ - def findOurOuts(transaction: Transaction): Future[ - Vector[(TransactionOutput, TransactionOutPoint)]] = + def findOurOuts( + transaction: Transaction + ): Future[Vector[(TransactionOutput, TransactionOutPoint)]] = for { spks <- listSPKs() } yield transaction.outputs.zipWithIndex.collect { @@ -135,7 +141,8 @@ private[wallet] trait AddressHandling extends WalletLogger { private def getNewAddressDbAction( account: AccountDb, - chainType: HDChainType): DBIOAction[AddressDb, NoStream, Effect.Read] = { + chainType: HDChainType + ): DBIOAction[AddressDb, NoStream, Effect.Read] = { logger.debug(s"Getting new $chainType adddress for ${account.hdAccount}") val lastAddrOptA = chainType match { @@ -150,7 +157,8 @@ private[wallet] trait AddressHandling extends WalletLogger { case Some(addr) => val next = addr.path.next logger.debug( - s"Found previous address at path=${addr.path}, next=$next") + s"Found previous address at path=${addr.path}, next=$next" + ) next case None => val address = account.hdAccount @@ -167,7 +175,8 @@ private[wallet] trait AddressHandling extends WalletLogger { case Some(value) => value case None => throw new RuntimeException( - s"Could not diff ${account.hdAccount} and $addrPath") + s"Could not diff ${account.hdAccount} and $addrPath" + ) } val pubkey = account.xpub.deriveChildPubKey(pathDiff) match { @@ -180,28 +189,32 @@ private[wallet] trait AddressHandling extends WalletLogger { AddressDbHelper .getSegwitAddress(pubkey, segwitPath, networkParameters) case legacyPath: LegacyHDPath => - AddressDbHelper.getLegacyAddress(pubkey, - legacyPath, - networkParameters) + AddressDbHelper.getLegacyAddress( + pubkey, + legacyPath, + networkParameters + ) case nestedPath: NestedSegWitHDPath => - AddressDbHelper.getNestedSegwitAddress(pubkey, - nestedPath, - networkParameters) + AddressDbHelper.getNestedSegwitAddress( + pubkey, + nestedPath, + networkParameters + ) } } } - /** Derives a new address in the wallet for the - * given account and chain type (change/external). - * After deriving the address it inserts it into our - * table of addresses. + /** Derives a new address in the wallet for the given account and chain type + * (change/external). After deriving the address it inserts it into our table + * of addresses. * - * This method is called with the approriate params - * from the public facing methods `getNewChangeAddress` - * and `getNewAddress`. + * This method is called with the approriate params from the public facing + * methods `getNewChangeAddress` and `getNewAddress`. * - * @param account Account to generate address from - * @param chainType What chain do we generate from? Internal change vs. external + * @param account + * Account to generate address from + * @param chainType + * What chain do we generate from? Internal change vs. external */ private def getNewAddressDb( account: AccountDb, @@ -213,20 +226,24 @@ private[wallet] trait AddressHandling extends WalletLogger { private def getNewAddressHelperAction( account: AccountDb, - chainType: HDChainType): DBIOAction[ + chainType: HDChainType + ): DBIOAction[ BitcoinAddress, NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + Effect.Read with Effect.Write with Effect.Transactional + ] = { logger.debug(s"Processing $account $chainType in our address request queue") val resultA: DBIOAction[ BitcoinAddress, NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = for { + Effect.Read with Effect.Write with Effect.Transactional + ] = for { addressDb <- getNewAddressDbAction(account, chainType) writtenAddressDb <- addressDAO.createAction(addressDb) } yield { logger.info( - s"Generated new address=${addressDb.address} path=${addressDb.path} isChange=${addressDb.isChange}") + s"Generated new address=${addressDb.address} path=${addressDb.path} isChange=${addressDb.isChange}" + ) writtenAddressDb.address } @@ -241,9 +258,9 @@ private[wallet] trait AddressHandling extends WalletLogger { callbackExecuted } - /** Queues a request to generate an address and returns a Future that will - * be completed when the request is processed in the queue. If the queue - * is full it throws an exception. + /** Queues a request to generate an address and returns a Future that will be + * completed when the request is processed in the queue. If the queue is full + * it throws an exception. * @throws IllegalStateException */ private def getNewAddressHelper( @@ -256,35 +273,42 @@ private[wallet] trait AddressHandling extends WalletLogger { def getNextAvailableIndex( accountDb: AccountDb, - chainType: HDChainType): Future[Int] = { + chainType: HDChainType + ): Future[Int] = { getNewAddressDb(accountDb, chainType).map(_.path.path.last.index) } def getNewAddressAction(account: HDAccount): DBIOAction[ BitcoinAddress, NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + Effect.Read with Effect.Write with Effect.Transactional + ] = { val accountDbOptA = findAccountAction(account) accountDbOptA.flatMap { case Some(accountDb) => getNewAddressAction(accountDb) case None => DBIOAction.failed( new RuntimeException( - s"No account found for given hdaccount=${account}")) + s"No account found for given hdaccount=${account}" + ) + ) } } def getNewChangeAddressAction(account: HDAccount): DBIOAction[ BitcoinAddress, NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + Effect.Read with Effect.Write with Effect.Transactional + ] = { val accountDbOptA = findAccountAction(account) accountDbOptA.flatMap { case Some(accountDb) => getNewChangeAddressAction(accountDb) case None => DBIOAction.failed( new RuntimeException( - s"No account found for given hdaccount=${account}")) + s"No account found for given hdaccount=${account}" + ) + ) } } @@ -295,21 +319,25 @@ private[wallet] trait AddressHandling extends WalletLogger { case None => Future.failed( new RuntimeException( - s"No account found for given hdaccount=${account}")) + s"No account found for given hdaccount=${account}" + ) + ) } } def getNewAddressAction(account: AccountDb): DBIOAction[ BitcoinAddress, NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + Effect.Read with Effect.Write with Effect.Transactional + ] = { getNewAddressHelperAction(account, HDChainType.External) } def getNewChangeAddressAction(account: AccountDb): DBIOAction[ BitcoinAddress, NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + Effect.Read with Effect.Write with Effect.Transactional + ] = { getNewAddressHelperAction(account, HDChainType.Change) } @@ -324,7 +352,8 @@ private[wallet] trait AddressHandling extends WalletLogger { /** @inheritdoc */ override def getNewAddress( - tags: Vector[AddressTag]): Future[BitcoinAddress] = { + tags: Vector[AddressTag] + ): Future[BitcoinAddress] = { getNewAddress(walletConfig.defaultAddressType, tags) } @@ -332,7 +361,8 @@ private[wallet] trait AddressHandling extends WalletLogger { def getAddress( account: AccountDb, chainType: HDChainType, - addressIndex: Int): Future[AddressDb] = { + addressIndex: Int + ): Future[AddressDb] = { val coinType = account.hdAccount.coin.coinType val accountIndex = account.hdAccount.index @@ -347,7 +377,8 @@ private[wallet] trait AddressHandling extends WalletLogger { case invalid: HDPurpose => throw new IllegalArgumentException( - s"No HD Path type for HDPurpose of $invalid") + s"No HD Path type for HDPurpose of $invalid" + ) } val pathDiff = @@ -355,7 +386,8 @@ private[wallet] trait AddressHandling extends WalletLogger { case Some(value) => value case None => throw new IllegalArgumentException( - s"Could not diff ${account.hdAccount} and $path") + s"Could not diff ${account.hdAccount} and $path" + ) } val pubkey = account.xpub.deriveChildPubKey(pathDiff) match { @@ -368,28 +400,33 @@ private[wallet] trait AddressHandling extends WalletLogger { AddressDbHelper.getSegwitAddress( pubkey, SegWitHDPath(coinType, accountIndex, chainType, addressIndex), - networkParameters) + networkParameters + ) case HDPurposes.NestedSegWit => AddressDbHelper.getNestedSegwitAddress( pubkey, NestedSegWitHDPath(coinType, accountIndex, chainType, addressIndex), - networkParameters) + networkParameters + ) case HDPurposes.Legacy => AddressDbHelper.getLegacyAddress( pubkey, LegacyHDPath(coinType, accountIndex, chainType, addressIndex), - networkParameters) + networkParameters + ) case invalid: HDPurpose => throw new IllegalArgumentException( - s"No HD Path type for HDPurpose of $invalid") + s"No HD Path type for HDPurpose of $invalid" + ) } logger.debug(s"Writing $addressDb to database") addressDAO.upsert(addressDb).map { written => logger.debug( - s"Got $chainType address ${written.address} at key path ${written.path} with pubkey ${written.ecPublicKey}") + s"Got $chainType address ${written.address} at key path ${written.path} with pubkey ${written.ecPublicKey}" + ) written } } @@ -422,10 +459,9 @@ private[wallet] trait AddressHandling extends WalletLogger { } yield address } - def findAccountAction(account: HDAccount): DBIOAction[ - Option[AccountDb], - NoStream, - Effect.Read] = { + def findAccountAction( + account: HDAccount + ): DBIOAction[Option[AccountDb], NoStream, Effect.Read] = { accountDAO.findByAccountAction(account) } @@ -435,7 +471,8 @@ private[wallet] trait AddressHandling extends WalletLogger { /** @inheritdoc */ override def getNewAddress( - addressType: AddressType): Future[BitcoinAddress] = { + addressType: AddressType + ): Future[BitcoinAddress] = { for { account <- getDefaultAccountForType(addressType) address <- getNewAddressHelper(account, HDChainType.External) @@ -445,7 +482,8 @@ private[wallet] trait AddressHandling extends WalletLogger { /** @inheritdoc */ override def getNewAddress( addressType: AddressType, - tags: Vector[AddressTag]): Future[BitcoinAddress] = { + tags: Vector[AddressTag] + ): Future[BitcoinAddress] = { for { account <- getDefaultAccountForType(addressType) address <- getNewAddressHelper(account, HDChainType.External) @@ -457,7 +495,8 @@ private[wallet] trait AddressHandling extends WalletLogger { /** Generates a new change address */ override def getNewChangeAddress( - account: AccountDb): Future[BitcoinAddress] = { + account: AccountDb + ): Future[BitcoinAddress] = { getNewAddressHelper(account, HDChainType.Change) } @@ -467,26 +506,30 @@ private[wallet] trait AddressHandling extends WalletLogger { case Some(accountDb) => getNewChangeAddress(accountDb) case None => Future.failed( - new RuntimeException( - s"No account found for given hdaccount=$account")) + new RuntimeException(s"No account found for given hdaccount=$account") + ) } } /** @inheritdoc */ override def getAddressInfo( - address: BitcoinAddress): Future[Option[AddressInfo]] = { + address: BitcoinAddress + ): Future[Option[AddressInfo]] = { addressDAO.findAddress(address).map { addressOpt => addressOpt.map { address => - wallet.AddressInfo(pubkey = address.ecPublicKey, - network = address.address.networkParameters, - path = address.path) + wallet.AddressInfo( + pubkey = address.ecPublicKey, + network = address.address.networkParameters, + path = address.path + ) } } } override def tagAddress( address: BitcoinAddress, - tag: AddressTag): Future[AddressTagDb] = { + tag: AddressTag + ): Future[AddressTagDb] = { val addressTagDb = AddressTagDb(address, tag) val f = addressTagDAO.create(addressTagDb) f @@ -498,7 +541,8 @@ private[wallet] trait AddressHandling extends WalletLogger { override def getAddressTags( address: BitcoinAddress, - tagType: AddressTagType): Future[Vector[AddressTagDb]] = { + tagType: AddressTagType + ): Future[Vector[AddressTagDb]] = { addressTagDAO.findByAddressAndTag(address, tagType) } @@ -515,19 +559,22 @@ private[wallet] trait AddressHandling extends WalletLogger { } override def dropAddressTagType( - addressTagType: AddressTagType): Future[Int] = { + addressTagType: AddressTagType + ): Future[Int] = { addressTagDAO.dropByTagType(addressTagType) } override def dropAddressTagType( address: BitcoinAddress, - addressTagType: AddressTagType): Future[Int] = { + addressTagType: AddressTagType + ): Future[Int] = { addressTagDAO.dropByAddressAndTag(address, addressTagType) } override def dropAddressTagName( address: BitcoinAddress, - addressTagName: AddressTagName): Future[Int] = { + addressTagName: AddressTagName + ): Future[Int] = { addressTagDAO.dropByAddressAndName(address, addressTagName) } } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/AddressRequest.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/AddressRequest.scala index 053b807b24..e0b8de9a32 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/AddressRequest.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/AddressRequest.scala @@ -8,4 +8,5 @@ import scala.concurrent.Promise case class AddressRequest( accountDb: AccountDb, chainType: HDChainType, - promise: Promise[AddressDb]) + promise: Promise[AddressDb] +) diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/FundTransactionHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/FundTransactionHandling.scala index 85c778a88d..24135c5d40 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/FundTransactionHandling.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/FundTransactionHandling.scala @@ -19,15 +19,17 @@ trait FundTransactionHandling extends WalletLogger { self: Wallet => destinations: Vector[TransactionOutput], feeRate: FeeUnit, fromTagOpt: Option[AddressTag], - markAsReserved: Boolean): Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { + markAsReserved: Boolean + ): Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { for { account <- getDefaultAccount() - funded <- fundRawTransaction(destinations = destinations, - feeRate = feeRate, - fromAccount = account, - fromTagOpt = fromTagOpt, - markAsReserved = markAsReserved) + funded <- fundRawTransaction( + destinations = destinations, + feeRate = feeRate, + fromAccount = account, + fromTagOpt = fromTagOpt, + markAsReserved = markAsReserved + ) } yield funded } @@ -36,13 +38,15 @@ trait FundTransactionHandling extends WalletLogger { self: Wallet => feeRate: FeeUnit, fromAccount: AccountDb, fromTagOpt: Option[AddressTag] = None, - markAsReserved: Boolean = false): Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { - fundRawTransactionInternal(destinations = destinations, - feeRate = feeRate, - fromAccount = fromAccount, - fromTagOpt = fromTagOpt, - markAsReserved = markAsReserved) + markAsReserved: Boolean = false + ): Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { + fundRawTransactionInternal( + destinations = destinations, + feeRate = feeRate, + fromAccount = fromAccount, + fromTagOpt = fromTagOpt, + markAsReserved = markAsReserved + ) } /** Funds an unsigned transaction from the specified account */ @@ -50,17 +54,20 @@ trait FundTransactionHandling extends WalletLogger { self: Wallet => destinations: Vector[TransactionOutput], feeRate: FeeUnit, fromAccount: AccountDb, - markAsReserved: Boolean): Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { - fundRawTransaction(destinations = destinations, - feeRate = feeRate, - fromAccount = fromAccount, - fromTagOpt = None, - markAsReserved = markAsReserved) + markAsReserved: Boolean + ): Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { + fundRawTransaction( + destinations = destinations, + feeRate = feeRate, + fromAccount = fromAccount, + fromTagOpt = None, + markAsReserved = markAsReserved + ) } - /** This returns a [[RawTxBuilder]] that can be used to generate an unsigned transaction with [[RawTxBuilder.result()]] - * which can be signed with the returned [[ScriptSignatureParams]]. + /** This returns a [[RawTxBuilder]] that can be used to generate an unsigned + * transaction with [[RawTxBuilder.result()]] which can be signed with the + * returned [[ScriptSignatureParams]]. * * Utxos are funded with the given coin selection algorithm */ @@ -70,14 +77,16 @@ trait FundTransactionHandling extends WalletLogger { self: Wallet => fromAccount: AccountDb, coinSelectionAlgo: CoinSelectionAlgo = CoinSelectionAlgo.LeastWaste, fromTagOpt: Option[AddressTag], - markAsReserved: Boolean): Future[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { - val action = fundRawTransactionInternalAction(destinations, - feeRate, - fromAccount, - coinSelectionAlgo, - fromTagOpt, - markAsReserved) + markAsReserved: Boolean + ): Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = { + val action = fundRawTransactionInternalAction( + destinations, + feeRate, + fromAccount, + coinSelectionAlgo, + fromTagOpt, + markAsReserved + ) for { txHelper <- safeDatabase.run(action) @@ -91,14 +100,18 @@ trait FundTransactionHandling extends WalletLogger { self: Wallet => fromAccount: AccountDb, coinSelectionAlgo: CoinSelectionAlgo = CoinSelectionAlgo.LeastWaste, fromTagOpt: Option[AddressTag], - markAsReserved: Boolean): DBIOAction[ - FundRawTxHelper[ShufflingNonInteractiveFinalizer], - NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + markAsReserved: Boolean + ): DBIOAction[FundRawTxHelper[ + ShufflingNonInteractiveFinalizer + ], + NoStream, + Effect.Read with Effect.Write with Effect.Transactional] = { val amts = destinations.map(_.value) - //need to allow 0 for OP_RETURN outputs - require(amts.forall(_.satoshis.toBigInt >= 0), - s"Cannot fund a transaction for a negative amount, got=$amts") + // need to allow 0 for OP_RETURN outputs + require( + amts.forall(_.satoshis.toBigInt >= 0), + s"Cannot fund a transaction for a negative amount, got=$amts" + ) val amt = amts.sum logger.info(s"Attempting to fund a tx for amt=$amt with feeRate=$feeRate") val utxosA = @@ -106,12 +119,15 @@ trait FundTransactionHandling extends WalletLogger { self: Wallet => utxos <- fromTagOpt match { case None => spendingInfoDAO.findAllUnspentForAccountAction( - fromAccount.hdAccount) + fromAccount.hdAccount + ) case Some(tag) => spendingInfoDAO.findAllUnspentForTagAction(tag).map { utxos => utxos.filter(utxo => - HDAccount.isSameAccount(bip32Path = utxo.privKeyPath, - account = fromAccount.hdAccount)) + HDAccount.isSameAccount( + bip32Path = utxo.privKeyPath, + account = fromAccount.hdAccount + )) } } utxoWithTxs <- DBIO.sequence { @@ -124,7 +140,8 @@ trait FundTransactionHandling extends WalletLogger { self: Wallet => // Need to remove immature coinbase inputs immatureCoinbases = utxoWithTxs.filter( - _._1.state == TxoState.ImmatureCoinbase) + _._1.state == TxoState.ImmatureCoinbase + ) } yield utxoWithTxs.filter(utxo => !immatureCoinbases.exists(_._1 == utxo._1)) @@ -171,15 +188,19 @@ trait FundTransactionHandling extends WalletLogger { self: Wallet => } val txBuilder = - ShufflingNonInteractiveFinalizer.txBuilderFrom(destinations, - utxoSpendingInfos, - feeRate, - change.scriptPubKey) + ShufflingNonInteractiveFinalizer.txBuilderFrom( + destinations, + utxoSpendingInfos, + feeRate, + change.scriptPubKey + ) - val fundTxHelper = FundRawTxHelper(txBuilderWithFinalizer = txBuilder, - scriptSigParams = utxoSpendingInfos, - feeRate = feeRate, - reservedUTXOsCallbackF = callbackF) + val fundTxHelper = FundRawTxHelper( + txBuilderWithFinalizer = txBuilder, + scriptSigParams = utxoSpendingInfos, + feeRate = feeRate, + reservedUTXOsCallbackF = callbackF + ) fundTxHelper } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/RescanHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/RescanHandling.scala index 46a61c5b28..c467f4cde7 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/RescanHandling.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/RescanHandling.scala @@ -37,15 +37,18 @@ private[wallet] trait RescanHandling extends WalletLogger { endOpt: Option[BlockStamp], addressBatchSize: Int, useCreationTime: Boolean, - force: Boolean)(implicit ec: ExecutionContext): Future[RescanState] = { + force: Boolean + )(implicit ec: ExecutionContext): Future[RescanState] = { for { account <- getDefaultAccount() - state <- rescanNeutrinoWallet(account.hdAccount, - startOpt, - endOpt, - addressBatchSize, - useCreationTime, - force) + state <- rescanNeutrinoWallet( + account.hdAccount, + startOpt, + endOpt, + addressBatchSize, + useCreationTime, + force + ) } yield state } @@ -56,23 +59,30 @@ private[wallet] trait RescanHandling extends WalletLogger { endOpt: Option[BlockStamp], addressBatchSize: Int, useCreationTime: Boolean = true, - force: Boolean = false): Future[RescanState] = { + force: Boolean = false + ): Future[RescanState] = { for { doRescan <- if (force) stateDescriptorDAO.updateRescanning(true).map(_.rescanning) else - stateDescriptorDAO.compareAndSetRescanning(expectedValue = false, - newValue = true) + stateDescriptorDAO.compareAndSetRescanning( + expectedValue = false, + newValue = true + ) rescanState <- if (doRescan) { logger.info( - s"Starting rescanning the wallet=${walletConfig.walletName} from ${startOpt} to ${endOpt} useCreationTime=$useCreationTime") + s"Starting rescanning the wallet=${walletConfig.walletName} from ${startOpt} to ${endOpt} useCreationTime=$useCreationTime" + ) val startTime = System.currentTimeMillis() val resF: Future[RescanState] = for { start <- (startOpt, useCreationTime) match { case (Some(_), true) => - Future.failed(new IllegalArgumentException( - "Cannot define a starting block and use the wallet creation time")) + Future.failed( + new IllegalArgumentException( + "Cannot define a starting block and use the wallet creation time" + ) + ) case (Some(value), false) => Future.successful(Some(value)) case (None, true) => @@ -81,16 +91,18 @@ private[wallet] trait RescanHandling extends WalletLogger { Future.successful(None) } _ <- clearUtxos(account) - state <- doNeutrinoRescan(account = account, - startOpt = start, - endOpt = endOpt, - addressBatchSize = addressBatchSize, - forceGenerateSpks = false) - //purposefully don't map on this Future as it won't be completed until - //the rescan is completely done. + state <- doNeutrinoRescan( + account = account, + startOpt = start, + endOpt = endOpt, + addressBatchSize = addressBatchSize, + forceGenerateSpks = false + ) + // purposefully don't map on this Future as it won't be completed until + // the rescan is completely done. _ = RescanState.awaitRescanComplete(state).map { _ => - logger.info( - s"Rescan is complete, resetting rescan state to false") + logger + .info(s"Rescan is complete, resetting rescan state to false") val f = for { _ <- stateDescriptorDAO.updateRescanning(false) _ <- walletCallbacks @@ -104,23 +116,24 @@ private[wallet] trait RescanHandling extends WalletLogger { state } - //register callbacks for resetting rescan flag in case of failure + // register callbacks for resetting rescan flag in case of failure val _ = handleRescanFailure(resF) resF.map { case r: RescanState.RescanStarted => r.entireRescanDoneF.map(_ => logger.info(s"Finished rescanning the wallet. It took ${System - .currentTimeMillis() - startTime}ms")) + .currentTimeMillis() - startTime}ms")) case RescanState.RescanDone | RescanState.RescanAlreadyStarted | RescanState.RescanNotNeeded => - //nothing to log + // nothing to log } resF } else { logger.warn( - s"Rescan already started for wallet=${walletConfig.walletName}, ignoring request to start another one") + s"Rescan already started for wallet=${walletConfig.walletName}, ignoring request to start another one" + ) Future.successful(RescanState.RescanAlreadyStarted) } @@ -129,10 +142,13 @@ private[wallet] trait RescanHandling extends WalletLogger { } } - /** Register callbacks to reset rescan flag in the database if there is a rescan failure */ + /** Register callbacks to reset rescan flag in the database if there is a + * rescan failure + */ private def handleRescanFailure( - rescanStateF: Future[RescanState]): Future[Unit] = { - //handle the case where there is a top level rescan failure when _starting_ the rescan + rescanStateF: Future[RescanState] + ): Future[Unit] = { + // handle the case where there is a top level rescan failure when _starting_ the rescan rescanStateF.recoverWith { case err: Throwable => logger.error(s"Failed to rescan wallet=${walletConfig.walletName}", err) stateDescriptorDAO @@ -140,17 +156,18 @@ private[wallet] trait RescanHandling extends WalletLogger { .flatMap(_ => Future.failed(err)) } - //handle the case where the rescan fails while the rescan is in progress + // handle the case where the rescan fails while the rescan is in progress for { rescanState <- rescanStateF _ <- RescanState.awaitRescanDone(rescanState).recoverWith { case RescanTerminatedEarly => logger.info( - s"Rescan terminated early, don't reset isRescanning flag as new wallet is likely being loaded") + s"Rescan terminated early, don't reset isRescanning flag as new wallet is likely being loaded" + ) Future.unit case err: Throwable => - logger.error(s"Failed to rescan wallet=${walletConfig.walletName}", - err) + logger + .error(s"Failed to rescan wallet=${walletConfig.walletName}", err) stateDescriptorDAO .updateRescanning(false) .flatMap(_ => Future.failed(err)) @@ -170,18 +187,21 @@ private[wallet] trait RescanHandling extends WalletLogger { range: Range, parallelism: Int, filterBatchSize: Int, - forceGenerateSpks: Boolean): RescanState.RescanStarted = { - val scriptsF = generateScriptPubKeys(account = account, - addressBatchSize = addressBatchSize, - forceGenerateSpks = forceGenerateSpks) - //by completing the promise returned by this sink - //we will be able to arbitrarily terminate the stream - //see: https://doc.akka.io/docs/akka/current/stream/operators/Source/maybe.html + forceGenerateSpks: Boolean + ): RescanState.RescanStarted = { + val scriptsF = generateScriptPubKeys( + account = account, + addressBatchSize = addressBatchSize, + forceGenerateSpks = forceGenerateSpks + ) + // by completing the promise returned by this sink + // we will be able to arbitrarily terminate the stream + // see: https://doc.akka.io/docs/akka/current/stream/operators/Source/maybe.html val maybe = Source.maybe[Int] - //combine the Source.maybe with the Source providing filter heights - //this is needed so we can arbitrarily kill the stream with - //the promise returned by Source.maybe + // combine the Source.maybe with the Source providing filter heights + // this is needed so we can arbitrarily kill the stream with + // the promise returned by Source.maybe val combine: Source[Int, Promise[Option[Int]]] = { Source.combineMat(maybe, Source(range))(Merge(_))(Keep.left) } @@ -193,13 +213,13 @@ private[wallet] trait RescanHandling extends WalletLogger { case (vec: Vector[Int], int: Int) => vec.:+(int) } - //this promise is completed after we scan the last filter - //in the rescanSink + // this promise is completed after we scan the last filter + // in the rescanSink val rescanCompletePromise: Promise[Unit] = Promise() - //fetches filters, matches filters against our wallet, and then request blocks - //for the wallet to process. This sink takes as input filter heights - //to fetch for rescanning. + // fetches filters, matches filters against our wallet, and then request blocks + // for the wallet to process. This sink takes as input filter heights + // to fetch for rescanning. val rescanSink: Sink[Int, Future[Seq[Vector[BlockMatchingResponse]]]] = { Flow[Int] .batch[Vector[Int]](filterBatchSize, seed)(aggregate) @@ -208,7 +228,8 @@ private[wallet] trait RescanHandling extends WalletLogger { val f = scriptsF.flatMap { scripts => searchFiltersForMatches(scripts, filterResponse, parallelism)( - ExecutionContext.fromExecutor(walletConfig.rescanThreadPool)) + ExecutionContext.fromExecutor(walletConfig.rescanThreadPool) + ) } val heightRange = filterResponse.map(_.blockHeight) @@ -216,51 +237,58 @@ private[wallet] trait RescanHandling extends WalletLogger { f.onComplete { case Success(_) => if (heightRange.lastOption == range.lastOption) { - //complete the stream if we processed the last filter + // complete the stream if we processed the last filter rescanCompletePromise.success(()) } - case Failure(_) => //do nothing, the stream will fail on its own + case Failure(_) => // do nothing, the stream will fail on its own } f } .toMat(Sink.seq)(Keep.right) } - //the materialized values of the two streams - //completeRescanEarly allows us to safely complete the rescan early - //matchingBlocksF is materialized when the stream is complete. This is all blocks our wallet matched + // the materialized values of the two streams + // completeRescanEarly allows us to safely complete the rescan early + // matchingBlocksF is materialized when the stream is complete. This is all blocks our wallet matched val (completeRescanEarlyP, matchingBlocksF) = combine.toMat(rescanSink)(Keep.both).run() val recursiveRescanP: Promise[RescanState] = Promise() - //if we have seen the last filter, complete the rescanEarlyP so we are consistent + // if we have seen the last filter, complete the rescanEarlyP so we are consistent rescanCompletePromise.future.map { _ => completeRescanEarlyP.success(None) } val flatten = matchingBlocksF.map(_.flatten.toVector) - //return RescanStarted with access to the ability to complete the rescan early - //via the completeRescanEarlyP promise. + // return RescanStarted with access to the ability to complete the rescan early + // via the completeRescanEarlyP promise. RescanState.RescanStarted(completeRescanEarlyP, flatten, recursiveRescanP) } - /** Iterates over the block filters in order to find filters that match to the given addresses + /** Iterates over the block filters in order to find filters that match to the + * given addresses * - * I queries the filter database for [[batchSize]] filters a time - * and tries to run [[GolombFilter.matchesAny]] for each filter. + * I queries the filter database for [[batchSize]] filters a time and tries + * to run [[GolombFilter.matchesAny]] for each filter. * - * It tries to match the filters in parallel using [[parallelismLevel]] threads. - * For best results use it with a separate execution context. + * It tries to match the filters in parallel using [[parallelismLevel]] + * threads. For best results use it with a separate execution context. * - * @param scripts list of [[ScriptPubKey]]'s to watch - * @param startOpt start point (if empty it starts with the genesis block) - * @param endOpt end point (if empty it ends with the best tip) - * @param batchSize number of filters that can be matched in one batch - * @param parallelismLevel max number of threads required to perform matching - * (default [[Runtime.getRuntime.availableProcessors()]]) - * @return a list of matching block hashes + * @param scripts + * list of [[ScriptPubKey]]'s to watch + * @param startOpt + * start point (if empty it starts with the genesis block) + * @param endOpt + * end point (if empty it ends with the best tip) + * @param batchSize + * number of filters that can be matched in one batch + * @param parallelismLevel + * max number of threads required to perform matching (default + * [[Runtime.getRuntime.availableProcessors()]]) + * @return + * a list of matching block hashes */ private def getMatchingBlocks( startOpt: Option[BlockStamp], @@ -268,22 +296,26 @@ private[wallet] trait RescanHandling extends WalletLogger { addressBatchSize: Int, account: HDAccount, forceGenerateSpks: Boolean, - parallelismLevel: Int = Runtime.getRuntime.availableProcessors())(implicit - ec: ExecutionContext): Future[RescanState.RescanStarted] = { + parallelismLevel: Int = Runtime.getRuntime.availableProcessors() + )(implicit ec: ExecutionContext): Future[RescanState.RescanStarted] = { require(addressBatchSize > 0, "batch size must be greater than zero") require(parallelismLevel > 0, "parallelism level must be greater than zero") for { startHeight <- startOpt.fold(Future.successful(0))( - chainQueryApi.getHeightByBlockStamp) + chainQueryApi.getHeightByBlockStamp + ) _ = if (startHeight < 0) throw InvalidBlockRange(s"Start position cannot negative") endHeight <- endOpt.fold(chainQueryApi.getFilterCount())( - chainQueryApi.getHeightByBlockStamp) + chainQueryApi.getHeightByBlockStamp + ) _ = if (startHeight > endHeight) throw InvalidBlockRange( - s"End position cannot precede start: $startHeight:$endHeight") + s"End position cannot precede start: $startHeight:$endHeight" + ) _ = logger.info( - s"Beginning to search for matches between ${startHeight}:${endHeight}") + s"Beginning to search for matches between ${startHeight}:${endHeight}" + ) range = startHeight.to(endHeight) rescanStarted = buildRescanFlow( @@ -307,38 +339,44 @@ private[wallet] trait RescanHandling extends WalletLogger { startOpt: Option[BlockStamp], endOpt: Option[BlockStamp], addressBatchSize: Int, - forceGenerateSpks: Boolean): Future[RescanState] = { + forceGenerateSpks: Boolean + ): Future[RescanState] = { for { - inProgress <- matchBlocks(endOpt = endOpt, - startOpt = startOpt, - account = account, - addressBatchSize = addressBatchSize, - forceGenerateSpks) - _ = recursiveRescan(prevState = inProgress, - startOpt = startOpt, - endOpt = endOpt, - addressBatchSize = addressBatchSize, - account = account) + inProgress <- matchBlocks( + endOpt = endOpt, + startOpt = startOpt, + account = account, + addressBatchSize = addressBatchSize, + forceGenerateSpks + ) + _ = recursiveRescan( + prevState = inProgress, + startOpt = startOpt, + endOpt = endOpt, + addressBatchSize = addressBatchSize, + account = account + ) } yield { inProgress } } - /** Used to call a recursive rescan after the previous rescan is complete. - * The [[prevState]] parameter is what represents the previous rescan. - * We wait for this rescan to complete, and then check if we need to - * do another rescan + /** Used to call a recursive rescan after the previous rescan is complete. The + * [[prevState]] parameter is what represents the previous rescan. We wait + * for this rescan to complete, and then check if we need to do another + * rescan */ private def recursiveRescan( prevState: RescanState.RescanStarted, startOpt: Option[BlockStamp], endOpt: Option[BlockStamp], addressBatchSize: Int, - account: HDAccount): Future[Unit] = { + account: HDAccount + ): Future[Unit] = { val awaitPreviousRescanF = RescanState.awaitSingleRescanDone(rescanState = prevState) for { - _ <- awaitPreviousRescanF //this is where the deadlock occurs + _ <- awaitPreviousRescanF // this is where the deadlock occurs externalGap <- calcAddressGap(HDChainType.External, account) changeGap <- calcAddressGap(HDChainType.Change, account) _ <- { @@ -346,18 +384,22 @@ private[wallet] trait RescanHandling extends WalletLogger { externalGap >= walletConfig.addressGapLimit && changeGap >= walletConfig.addressGapLimit ) { logger.info( - s"Did not find any funds within the last ${walletConfig.addressGapLimit} addresses. Stopping our rescan.") + s"Did not find any funds within the last ${walletConfig.addressGapLimit} addresses. Stopping our rescan." + ) prevState.recursiveRescanP.success(RescanState.RescanNotNeeded) Future.unit } else { logger.info( s"Attempting rescan again with fresh pool of addresses as we had a " + - s"match within our address gap limit of ${walletConfig.addressGapLimit} externalGap=$externalGap changeGap=$changeGap") - val recursiveF = doNeutrinoRescan(account = account, - startOpt = startOpt, - endOpt = endOpt, - addressBatchSize = addressBatchSize, - forceGenerateSpks = true) + s"match within our address gap limit of ${walletConfig.addressGapLimit} externalGap=$externalGap changeGap=$changeGap" + ) + val recursiveF = doNeutrinoRescan( + account = account, + startOpt = startOpt, + endOpt = endOpt, + addressBatchSize = addressBatchSize, + forceGenerateSpks = true + ) recursiveF.map(r => prevState.recursiveRescanP.success(r)) } } @@ -368,14 +410,15 @@ private[wallet] trait RescanHandling extends WalletLogger { private def calcAddressGap( chainType: HDChainType, - account: HDAccount): Future[Int] = { + account: HDAccount + ): Future[Int] = { for { addressDbs <- addressDAO.findAllForAccount(account) addressGap <- addressDbs - //make sure all addressDb are of the correct chainType - //and they are sorted according to their index so we can - //calculate the gap accurately + // make sure all addressDb are of the correct chainType + // and they are sorted according to their index so we can + // calculate the gap accurately .filter(_.accountChain == chainType) .sortBy(_.addressIndex) .foldLeft(Future.successful(0)) { (prevNF, addressDb) => @@ -394,7 +437,8 @@ private[wallet] trait RescanHandling extends WalletLogger { } private def downloadAndProcessBlocks( - blocks: Vector[DoubleSha256DigestBE]): Future[Unit] = { + blocks: Vector[DoubleSha256DigestBE] + ): Future[Unit] = { logger.debug(s"Requesting ${blocks.size} block(s)") blocks.foldLeft(Future.unit) { (prevF, blockHash) => val completedF = subscribeForBlockProcessingCompletionSignal(blockHash) @@ -411,14 +455,16 @@ private[wallet] trait RescanHandling extends WalletLogger { startOpt: Option[BlockStamp], account: HDAccount, addressBatchSize: Int, - forceGenerateSpks: Boolean): Future[RescanState.RescanStarted] = { + forceGenerateSpks: Boolean + ): Future[RescanState.RescanStarted] = { val rescanStateF = for { - rescanState <- getMatchingBlocks(startOpt = startOpt, - endOpt = endOpt, - addressBatchSize = addressBatchSize, - account = account, - forceGenerateSpks = forceGenerateSpks)( - ExecutionContext.fromExecutor(walletConfig.rescanThreadPool)) + rescanState <- getMatchingBlocks( + startOpt = startOpt, + endOpt = endOpt, + addressBatchSize = addressBatchSize, + account = account, + forceGenerateSpks = forceGenerateSpks + )(ExecutionContext.fromExecutor(walletConfig.rescanThreadPool)) } yield { rescanState } @@ -428,12 +474,16 @@ private[wallet] trait RescanHandling extends WalletLogger { private def generateAddressesForRescanAction( account: HDAccount, - addressBatchSize: Int): DBIOAction[ - Vector[BitcoinAddress], - NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + addressBatchSize: Int + ): DBIOAction[Vector[ + BitcoinAddress + ], + NoStream, + Effect.Read with Effect.Write with Effect.Transactional] = { val receiveAddressesA: DBIOAction[ - Vector[BitcoinAddress], + Vector[ + BitcoinAddress + ], NoStream, Effect.Read with Effect.Write with Effect.Transactional] = { DBIOAction.sequence { @@ -443,7 +493,9 @@ private[wallet] trait RescanHandling extends WalletLogger { }.map(_.toVector) val changeAddressesA: DBIOAction[ - Vector[BitcoinAddress], + Vector[ + BitcoinAddress + ], NoStream, Effect.Read with Effect.Write with Effect.Transactional] = { DBIOAction.sequence { @@ -458,26 +510,31 @@ private[wallet] trait RescanHandling extends WalletLogger { } yield receiveAddresses ++ changeAddresses } - /** If forceGeneratSpks is true or addressCount == 0 we generate a new pool of scriptpubkeys */ + /** If forceGeneratSpks is true or addressCount == 0 we generate a new pool of + * scriptpubkeys + */ private def generateScriptPubKeysAction( account: HDAccount, addressBatchSize: Int, - forceGenerateSpks: Boolean): DBIOAction[ - Vector[ScriptPubKey], - NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + forceGenerateSpks: Boolean + ): DBIOAction[Vector[ + ScriptPubKey + ], + NoStream, + Effect.Read with Effect.Write with Effect.Transactional] = { val addressCountA = addressDAO.countAction for { addressCount <- addressCountA addresses <- { if (forceGenerateSpks || addressCount == 0) { logger.info( - s"Generating $addressBatchSize fresh addresses for the rescan") + s"Generating $addressBatchSize fresh addresses for the rescan" + ) generateAddressesForRescanAction(account, addressBatchSize) } else { - //we don't want to continously generate addresses - //if our wallet already has them, so just use what is in the - //database already + // we don't want to continously generate addresses + // if our wallet already has them, so just use what is in the + // database already addressDAO.findAllAddressesAction().map(_.map(_.address)) } } @@ -491,43 +548,48 @@ private[wallet] trait RescanHandling extends WalletLogger { } } - /** Given a range of filter heights, we fetch the filters associated with those heights and emit them downstream */ - private val fetchFiltersFlow: Flow[ - Vector[Int], - Vector[ChainQueryApi.FilterResponse], - NotUsed] = { - //parallelism as 1 here because `getFiltersBetweenHeights` - //fetches filters in parallel. We can run into our max open requests - //allowed by akka if we have parallelism more than 1 here + /** Given a range of filter heights, we fetch the filters associated with + * those heights and emit them downstream + */ + private val fetchFiltersFlow + : Flow[Vector[Int], Vector[ChainQueryApi.FilterResponse], NotUsed] = { + // parallelism as 1 here because `getFiltersBetweenHeights` + // fetches filters in parallel. We can run into our max open requests + // allowed by akka if we have parallelism more than 1 here Flow[Vector[Int]].mapAsync(1) { case range: Vector[Int] => val startHeight = range.head val endHeight = range.last logger.debug( - s"Searching filters from start=$startHeight to end=$endHeight") - chainQueryApi.getFiltersBetweenHeights(startHeight = startHeight, - endHeight = endHeight) + s"Searching filters from start=$startHeight to end=$endHeight" + ) + chainQueryApi.getFiltersBetweenHeights( + startHeight = startHeight, + endHeight = endHeight + ) } } def generateScriptPubKeys( account: HDAccount, addressBatchSize: Int, - forceGenerateSpks: Boolean): Future[Vector[ScriptPubKey]] = { + forceGenerateSpks: Boolean + ): Future[Vector[ScriptPubKey]] = { val action = generateScriptPubKeysAction( account = account, addressBatchSize = addressBatchSize, - forceGenerateSpks = forceGenerateSpks) + forceGenerateSpks = forceGenerateSpks + ) safeDatabase.run(action) } - /** Searches the given block filters against the given scriptPubKeys for matches. - * If there is a match, request the full block to search + /** Searches the given block filters against the given scriptPubKeys for + * matches. If there is a match, request the full block to search */ private def searchFiltersForMatches( scripts: Vector[ScriptPubKey], filtersResponse: Vector[ChainQueryApi.FilterResponse], - parallelismLevel: Int)(implicit - ec: ExecutionContext): Future[Vector[BlockMatchingResponse]] = { + parallelismLevel: Int + )(implicit ec: ExecutionContext): Future[Vector[BlockMatchingResponse]] = { val startHeightOpt = filtersResponse.headOption.map(_.blockHeight) val endHeightOpt = filtersResponse.lastOption.map(_.blockHeight) for { @@ -535,7 +597,8 @@ private[wallet] trait RescanHandling extends WalletLogger { _ <- downloadAndProcessBlocks(filtered.map(_.blockHash)) } yield { logger.debug( - s"Found ${filtered.length} matches from start=$startHeightOpt to end=$endHeightOpt") + s"Found ${filtered.length} matches from start=$startHeightOpt to end=$endHeightOpt" + ) filtered } } @@ -543,8 +606,8 @@ private[wallet] trait RescanHandling extends WalletLogger { private[wallet] def findMatches( filters: Vector[FilterResponse], scripts: Vector[ScriptPubKey], - parallelismLevel: Int)(implicit - ec: ExecutionContext): Future[Vector[BlockMatchingResponse]] = { + parallelismLevel: Int + )(implicit ec: ExecutionContext): Future[Vector[BlockMatchingResponse]] = { if (filters.isEmpty) { logger.info("No Filters to check against") Future.successful(Vector.empty) @@ -569,8 +632,10 @@ private[wallet] trait RescanHandling extends WalletLogger { val matcher = SimpleFilterMatcher(filter.compactFilter) if (matcher.matchesAny(bytes)) { logger.info(s"Found a match in block ${filter.blockHeight}") - blocks :+ BlockMatchingResponse(filter.blockHash, - filter.blockHeight) + blocks :+ BlockMatchingResponse( + filter.blockHash, + filter.blockHeight + ) } else { blocks } @@ -581,8 +646,9 @@ private[wallet] trait RescanHandling extends WalletLogger { } } - /** Calculates group size to split a filter vector into [[parallelismLevel]] groups. - * It's needed to limit number of threads required to run the matching + /** Calculates group size to split a filter vector into [[parallelismLevel]] + * groups. It's needed to limit number of threads required to run the + * matching */ private def calcGroupSize(vectorSize: Int, parallelismLevel: Int): Int = { if (vectorSize / parallelismLevel * parallelismLevel < vectorSize) diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/TransactionProcessing.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/TransactionProcessing.scala index 1982c7035f..689be2c417 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/TransactionProcessing.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/TransactionProcessing.scala @@ -22,10 +22,9 @@ import org.bitcoins.wallet._ import scala.concurrent.{Future, Promise} import scala.util.{Failure, Success, Try} -/** Provides functionality for processing transactions. This - * includes importing UTXOs spent to our wallet, updating - * confirmation counts and marking UTXOs as spent when - * spending from our wallet +/** Provides functionality for processing transactions. This includes importing + * UTXOs spent to our wallet, updating confirmation counts and marking UTXOs as + * spent when spending from our wallet */ private[bitcoins] trait TransactionProcessing extends WalletLogger { self: Wallet => @@ -53,7 +52,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { } yield { if (result.updatedIncoming.nonEmpty || result.updatedOutgoing.nonEmpty) { logger.info( - s"Finished processing of transaction=${transaction.txIdBE.hex}. Relevant incomingTXOs=${result.updatedIncoming.length}, outgoingTXOs=${result.updatedOutgoing.length}") + s"Finished processing of transaction=${transaction.txIdBE.hex}. Relevant incomingTXOs=${result.updatedIncoming.length}, outgoingTXOs=${result.updatedOutgoing.length}" + ) } this @@ -66,7 +66,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { val heightF = chainQueryApi.getBlockHeight(block.blockHeader.hashBE) heightF.foreach { heightOpt => logger.debug( - s"Processing block=${block.blockHeader.hash.flip.hex} heightOpt=$heightOpt") + s"Processing block=${block.blockHeader.hash.flip.hex} heightOpt=$heightOpt" + ) } heightF.flatMap { @@ -77,9 +78,9 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { if (!isEmpty) { processBlockCachedUtxos(block) } else { - //do nothing if the wallet is empty as an optimization - //this is for users first downloading bitcoin-s - //and syncing their node + // do nothing if the wallet is empty as an optimization + // this is for users first downloading bitcoin-s + // and syncing their node Future.successful(this) } } @@ -100,56 +101,60 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { f.foreach { _ => val stop = TimeUtil.currentEpochMs logger.info( - s"Finished processing of block=${block.blockHeader.hash.flip.hex}. It took ${stop - start}ms") + s"Finished processing of block=${block.blockHeader.hash.flip.hex}. It took ${stop - start}ms" + ) } f.failed.foreach(e => logger.error( s"Error processing of block=${block.blockHeader.hash.flip.hex}.", - e)) + e + )) f case None => logger.warn( - s"Could not find blockheight for blockHash=${block.blockHeader.hashBE.hex}, skipping processing in wallet") + s"Could not find blockheight for blockHash=${block.blockHeader.hashBE.hex}, skipping processing in wallet" + ) Future.successful(this) } } - /** Helper method to process a block. This fetches all of our relevent spending info dbs - * up front rather than fetching them every time [[processTransaction]] is called. This - * significantly improves performance on rescans or IBD with an existing wallet + /** Helper method to process a block. This fetches all of our relevent + * spending info dbs up front rather than fetching them every time + * [[processTransaction]] is called. This significantly improves performance + * on rescans or IBD with an existing wallet */ private def processBlockCachedUtxos(block: Block): Future[Wallet] = { - //fetch all received spending info dbs relevant to txs in this block to improve performance + // fetch all received spending info dbs relevant to txs in this block to improve performance val receivedSpendingInfoDbsF = spendingInfoDAO .findTxs(block.transactions.toVector) val cachedReceivedOptF = receivedSpendingInfoDbsF - .map(Some(_)) //reduce allocations by creating Some here + .map(Some(_)) // reduce allocations by creating Some here - //fetch all spending infoDbs for this block to improve performance + // fetch all spending infoDbs for this block to improve performance val spentSpendingInfoDbsF = spendingInfoDAO.findOutputsBeingSpent(block.transactions.toVector) val blockHashOpt = Some(block.blockHeader.hash.flip) - //fetch all outputs we may have received in this block in advance - //as an optimization + // fetch all outputs we may have received in this block in advance + // as an optimization val relevantReceivedOutputsForBlockF = getRelevantOutputsForBlock(block) val resultF: Future[Future[Wallet]] = for { - //map on these first so we don't have to call - //.map everytime we iterate through a tx - //which is costly (thread overhead) + // map on these first so we don't have to call + // .map everytime we iterate through a tx + // which is costly (thread overhead) receivedSpendingInfoDbsOpt <- cachedReceivedOptF spentSpendingInfoDbs <- spentSpendingInfoDbsF relevantReceivedOutputsForBlock <- relevantReceivedOutputsForBlockF } yield { - //we need to keep a cache of spentSpendingInfoDb - //for the case where we receive & then spend that - //same utxo in the same block + // we need to keep a cache of spentSpendingInfoDb + // for the case where we receive & then spend that + // same utxo in the same block var cachedSpentOpt: Option[Vector[SpendingInfoDb]] = { Some(spentSpendingInfoDbs) } @@ -172,16 +177,17 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { ) } _ = { - //need to look if a received utxo is spent in the same block - //if so, we need to update our cachedSpentF + // need to look if a received utxo is spent in the same block + // if so, we need to update our cachedSpentF val spentInSameBlock: Vector[SpendingInfoDb] = { processTxResult.updatedIncoming.filter { spendingInfoDb => blockInputs.exists( - _.previousOutput == spendingInfoDb.outPoint) + _.previousOutput == spendingInfoDb.outPoint + ) } } - //add it to the cache + // add it to the cache val newCachedSpentOpt = { cachedSpentOpt match { case Some(spentSpendingInfo) => @@ -204,7 +210,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { } override def findTransaction( - txId: DoubleSha256DigestBE): Future[Option[TransactionDb]] = { + txId: DoubleSha256DigestBE + ): Future[Option[TransactionDb]] = { transactionDAO.findByTxId(txId) } @@ -216,16 +223,15 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { protected def insertTransaction( tx: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE]): Future[TransactionDb] = { + blockHashOpt: Option[DoubleSha256DigestBE] + ): Future[TransactionDb] = { safeDatabase.run(insertTransactionAction(tx, blockHashOpt)) } protected def insertTransactionAction( tx: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE]): DBIOAction[ - TransactionDb, - NoStream, - Effect.Write with Effect.Read] = { + blockHashOpt: Option[DoubleSha256DigestBE] + ): DBIOAction[TransactionDb, NoStream, Effect.Write with Effect.Read] = { val txDb = TransactionDbHelper.fromTransaction(tx, blockHashOpt) transactionDAO.upsertAction(txDb) } @@ -235,22 +241,23 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { feeRate: FeeUnit, inputAmount: CurrencyUnit, sentAmount: CurrencyUnit, - blockHashOpt: Option[DoubleSha256DigestBE]): Future[ - (TransactionDb, OutgoingTransactionDb)] = { + blockHashOpt: Option[DoubleSha256DigestBE] + ): Future[(TransactionDb, OutgoingTransactionDb)] = { val outgoingDb = - OutgoingTransactionDb.fromTransaction(transaction, - inputAmount, - sentAmount, - feeRate.calc(transaction)) + OutgoingTransactionDb.fromTransaction( + transaction, + inputAmount, + sentAmount, + feeRate.calc(transaction) + ) for { txDb <- insertTransaction(transaction, blockHashOpt) written <- outgoingTxDAO.upsert(outgoingDb) } yield (txDb, written) } - /** Processes TXs originating from our wallet. - * This is called right after we've signed a TX, - * updating our UTXO state. + /** Processes TXs originating from our wallet. This is called right after + * we've signed a TX, updating our UTXO state. */ override def processOurTransaction( transaction: Transaction, @@ -258,32 +265,39 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { inputAmount: CurrencyUnit, sentAmount: CurrencyUnit, blockHashOpt: Option[DoubleSha256DigestBE], - newTags: Vector[AddressTag]): Future[ProcessTxResult] = { + newTags: Vector[AddressTag] + ): Future[ProcessTxResult] = { logger.info( s"Processing TX from our wallet, transaction=${transaction.txIdBE.hex} with blockHash=${blockHashOpt - .map(_.hex)}") + .map(_.hex)}" + ) val relevantOutputsF = getRelevantOutputs(transaction) for { (txDb, _) <- - insertOutgoingTransaction(transaction, - feeRate, - inputAmount, - sentAmount, - blockHashOpt) + insertOutgoingTransaction( + transaction, + feeRate, + inputAmount, + sentAmount, + blockHashOpt + ) relevantOutputs <- relevantOutputsF - result <- processTransactionImpl(transaction = txDb.transaction, - blockHashOpt = blockHashOpt, - newTags = newTags, - receivedSpendingInfoDbsOpt = None, - spentSpendingInfoDbsOpt = None, - relevantOutputs) + result <- processTransactionImpl( + transaction = txDb.transaction, + blockHashOpt = blockHashOpt, + newTags = newTags, + receivedSpendingInfoDbsOpt = None, + spentSpendingInfoDbsOpt = None, + relevantOutputs + ) } yield { val txid = txDb.transaction.txIdBE val changeOutputs = result.updatedIncoming.length val spentOutputs = result.updatedOutgoing.length logger.info( - s"Processing of internal transaction=${txid.hex} resulted in changeOutputs=$changeOutputs and spentUTXOs=$spentOutputs") + s"Processing of internal transaction=${txid.hex} resulted in changeOutputs=$changeOutputs and spentUTXOs=$spentOutputs" + ) result } } @@ -295,7 +309,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { Map.empty[DoubleSha256DigestBE, Promise[DoubleSha256DigestBE]] private[wallet] def subscribeForBlockProcessingCompletionSignal( - blockHash: DoubleSha256DigestBE): Future[DoubleSha256DigestBE] = + blockHash: DoubleSha256DigestBE + ): Future[DoubleSha256DigestBE] = synchronized { blockProcessingSignals.get(blockHash) match { case Some(existingSignal) => existingSignal.future @@ -309,10 +324,12 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { private def signalBlockProcessingCompletion( blockHash: DoubleSha256DigestBE, - failure: Try[_]): Unit = + failure: Try[_] + ): Unit = synchronized { logger.debug( - s"Updating wallet signal completion for ${blockHash.flip.hex}") + s"Updating wallet signal completion for ${blockHash.flip.hex}" + ) blockProcessingSignals.get(blockHash).foreach { signal => blockProcessingSignals = blockProcessingSignals.filterNot(_._1 == blockHash) @@ -325,10 +342,14 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { } /** Processes received utxos that are contained in the given transaction - * @param transaction the transaction that we are receiving utxos from - * @param blockHashOpt the block hash that contains this tx - * @param spendingInfoDbs the spending info dbs that are relevant for this transaction - * @param newTags tags associated with this tx + * @param transaction + * the transaction that we are receiving utxos from + * @param blockHashOpt + * the block hash that contains this tx + * @param spendingInfoDbs + * the spending info dbs that are relevant for this transaction + * @param newTags + * tags associated with this tx * @return */ protected def processReceivedUtxos( @@ -336,12 +357,12 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { blockHashOpt: Option[DoubleSha256DigestBE], spendingInfoDbs: Vector[SpendingInfoDb], newTags: Vector[AddressTag], - relevantReceivedOutputs: Vector[OutputWithIndex]): Future[ - Vector[SpendingInfoDb]] = { + relevantReceivedOutputs: Vector[OutputWithIndex] + ): Future[Vector[SpendingInfoDb]] = { if (spendingInfoDbs.isEmpty && relevantReceivedOutputs.isEmpty) { - //as an optimization if we don't have any relevant utxos - //and any relevant outputs that match scripts in our wallet - //we can just return now + // as an optimization if we don't have any relevant utxos + // and any relevant outputs that match scripts in our wallet + // we can just return now Future.successful(Vector.empty) } else { val newOutputs = relevantReceivedOutputs.filterNot { output => @@ -361,14 +382,14 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { } } - /** Searches for outputs on the given transaction that are - * being spent from our wallet + /** Searches for outputs on the given transaction that are being spent from + * our wallet */ protected def processSpentUtxos( transaction: Transaction, outputsBeingSpent: Vector[SpendingInfoDb], - blockHashOpt: Option[DoubleSha256DigestBE]): Future[ - Vector[SpendingInfoDb]] = { + blockHashOpt: Option[DoubleSha256DigestBE] + ): Future[Vector[SpendingInfoDb]] = { for { _ <- { if (outputsBeingSpent.nonEmpty) @@ -376,16 +397,16 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { else Future.unit } toBeUpdated = outputsBeingSpent.flatMap( - markAsSpent(_, transaction.txIdBE)) + markAsSpent(_, transaction.txIdBE) + ) processed <- updateUtxoSpentConfirmedStates(toBeUpdated) } yield { processed } } - /** Does the grunt work of processing a TX. - * This is called by either the internal or public TX - * processing method, which logs and transforms the + /** Does the grunt work of processing a TX. This is called by either the + * internal or public TX processing method, which logs and transforms the * output fittingly. */ private[internal] def processTransactionImpl( @@ -394,20 +415,21 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { newTags: Vector[AddressTag], receivedSpendingInfoDbsOpt: Option[Vector[SpendingInfoDb]], spentSpendingInfoDbsOpt: Option[Vector[SpendingInfoDb]], - relevantReceivedOutputs: Vector[OutputWithIndex]): Future[ - ProcessTxResult] = { + relevantReceivedOutputs: Vector[OutputWithIndex] + ): Future[ProcessTxResult] = { logger.debug( s"Processing transaction=${transaction.txIdBE.hex} with blockHash=${blockHashOpt - .map(_.hex)}") + .map(_.hex)}" + ) val receivedSpendingInfoDbsF: Future[Vector[SpendingInfoDb]] = { receivedSpendingInfoDbsOpt match { case Some(received) => - //spending info dbs are cached, so fetch the one relevant for this tx + // spending info dbs are cached, so fetch the one relevant for this tx val filtered = received.filter(_.txid == transaction.txIdBE) Future.successful(filtered) case None => - //no caching, just fetch from the database + // no caching, just fetch from the database spendingInfoDAO.findTx(transaction) } @@ -416,13 +438,13 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { val spentSpendingInfoDbsF: Future[Vector[SpendingInfoDb]] = { spentSpendingInfoDbsOpt match { case Some(spent) => - //spending info dbs are cached, so filter for outpoints related to this tx + // spending info dbs are cached, so filter for outpoints related to this tx val filtered = spent.filter { s => transaction.inputs.exists(_.previousOutput == s.outPoint) } Future.successful(filtered) case None => - //no caching, just fetch from db + // no caching, just fetch from db spendingInfoDAO.findOutputsBeingSpent(transaction) } } @@ -440,18 +462,22 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { _ = if (incoming.nonEmpty) { logger.info( s"Finished processing ${incoming.length} received outputs, balance=${incoming - .map(_.output.value) - .sum} it took=${TimeUtil.currentEpochMs - receivedStart}ms") + .map(_.output.value) + .sum} it took=${TimeUtil.currentEpochMs - receivedStart}ms" + ) } spentSpendingInfoDbs <- spentSpendingInfoDbsF spentStart = TimeUtil.currentEpochMs - outgoing <- processSpentUtxos(transaction = transaction, - outputsBeingSpent = spentSpendingInfoDbs, - blockHashOpt = blockHashOpt) + outgoing <- processSpentUtxos( + transaction = transaction, + outputsBeingSpent = spentSpendingInfoDbs, + blockHashOpt = blockHashOpt + ) _ = if (outgoing.nonEmpty) { logger.info( - s"Finished processing ${outgoing.length} spent outputs, it took=${TimeUtil.currentEpochMs - spentStart}ms") + s"Finished processing ${outgoing.length} spent outputs, it took=${TimeUtil.currentEpochMs - spentStart}ms" + ) } _ <- // only notify about our transactions @@ -465,7 +491,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { processTxF.failed.foreach { case err => logger.error( s"Failed to process transaction=${transaction.txIdBE.hex} blockHash=${blockHashOpt}", - err) + err + ) } processTxF } @@ -473,11 +500,13 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { /** If the given UTXO is marked as unspent and returns it so it can be updated * Otherwise returns None. * - * If the utxo is transitioning into an invalid state it throws ane exception. + * If the utxo is transitioning into an invalid state it throws ane + * exception. */ private def markAsSpent( out: SpendingInfoDb, - spendingTxId: DoubleSha256DigestBE): Option[SpendingInfoDb] = { + spendingTxId: DoubleSha256DigestBE + ): Option[SpendingInfoDb] = { out.state match { case ConfirmedReceived | PendingConfirmationsReceived | BroadcastReceived => @@ -486,7 +515,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { .copyWithSpendingTxId(spendingTxId) .copyWithState(state = BroadcastSpent) logger.debug( - s"Marked utxo=${updated.toHumanReadableString} as state=${updated.state}") + s"Marked utxo=${updated.toHumanReadableString} as state=${updated.state}" + ) Some(updated) case TxoState.Reserved => val updated = @@ -499,54 +529,60 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { logger.warn( s"Updating the spendingTxId of a transaction that is already spent, " + s"old state=${TxoState.BroadcastSpent} old spendingTxId=${out.spendingTxIdOpt - .map(_.hex)} new spendingTxId=${spendingTxId.hex}") + .map(_.hex)} new spendingTxId=${spendingTxId.hex}" + ) } val updated = out.copyWithSpendingTxId(spendingTxId) Some(updated) case TxoState.ImmatureCoinbase => throw new RuntimeException( - s"Attempting to spend an ImmatureCoinbase ${out.outPoint.hex}, this should not be possible until it is confirmed.") + s"Attempting to spend an ImmatureCoinbase ${out.outPoint.hex}, this should not be possible until it is confirmed." + ) case TxoState.ConfirmedSpent | TxoState.PendingConfirmationsSpent => if (!out.spendingTxIdOpt.contains(spendingTxId)) { throw new RuntimeException( - s"Attempted to mark an already spent utxo ${out.outPoint.hex} with a new spending tx ${spendingTxId.hex}") + s"Attempted to mark an already spent utxo ${out.outPoint.hex} with a new spending tx ${spendingTxId.hex}" + ) } else { - //do not want to update again + // do not want to update again None } } } - /** Inserts the UTXO at the given index into our DB, swallowing the - * error if any (this is because we're operating on data we've - * already verified). + /** Inserts the UTXO at the given index into our DB, swallowing the error if + * any (this is because we're operating on data we've already verified). */ private def processReceivedUtxo( transaction: Transaction, index: Int, blockHashOpt: Option[DoubleSha256DigestBE], - addressDb: AddressDb): Future[SpendingInfoDb] = { + addressDb: AddressDb + ): Future[SpendingInfoDb] = { val output = transaction.outputs(index) val outPoint = TransactionOutPoint(transaction.txId, UInt32(index)) // insert the UTXO into the DB - val utxoF = writeUtxo(tx = transaction, - blockHashOpt = blockHashOpt, - output = output, - outPoint = outPoint, - addressDb = addressDb) + val utxoF = writeUtxo( + tx = transaction, + blockHashOpt = blockHashOpt, + output = output, + outPoint = outPoint, + addressDb = addressDb + ) utxoF } - /** Processes an incoming transaction that already exists in our wallet. - * If the incoming transaction has more confirmations than what we - * have in the DB, we update the TX + /** Processes an incoming transaction that already exists in our wallet. If + * the incoming transaction has more confirmations than what we have in the + * DB, we update the TX */ private def processExistingReceivedTxo( transaction: Transaction, blockHashOpt: Option[DoubleSha256DigestBE], - foundTxo: SpendingInfoDb): Future[SpendingInfoDb] = { + foundTxo: SpendingInfoDb + ): Future[SpendingInfoDb] = { if (foundTxo.txid != transaction.txIdBE) { val errMsg = Seq( @@ -559,7 +595,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { blockHashOpt match { case Some(blockHash) => logger.debug( - s"Updating block_hash of txo=${transaction.txIdBE.hex}, new block hash=${blockHash.hex}") + s"Updating block_hash of txo=${transaction.txIdBE.hex}, new block hash=${blockHash.hex}" + ) val updateTxDbF = insertTransaction(transaction, blockHashOpt) @@ -568,7 +605,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { updateUtxoReceiveConfirmedStates(foundTxo).flatMap { case Some(txo) => logger.debug( - s"Updated block_hash of txo=${txo.txid.hex} new block hash=${blockHash.hex}") + s"Updated block_hash of txo=${txo.txid.hex} new block hash=${blockHash.hex}" + ) Future.successful(txo) case None => // State was not updated so we need to update it so it's block hash is in the database @@ -576,7 +614,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { }) case None => logger.debug( - s"Skipping further processing of transaction=${transaction.txIdBE.hex}, already processed.") + s"Skipping further processing of transaction=${transaction.txIdBE.hex}, already processed." + ) Future.successful(foundTxo) } } @@ -586,8 +625,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { private def addReceivedUTXOs( outputsWithIndex: Seq[OutputWithIndex], transaction: Transaction, - blockHashOpt: Option[DoubleSha256DigestBE]): Future[ - Seq[SpendingInfoDb]] = { + blockHashOpt: Option[DoubleSha256DigestBE] + ): Future[Seq[SpendingInfoDb]] = { val spks = outputsWithIndex.map(_.output.scriptPubKey).toVector @@ -596,7 +635,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { } yield { if (addressDbs.isEmpty) { logger.warn( - s"Found zero addresses in the database to match an output we have a script for, txid=${transaction.txIdBE.hex} outputs=$outputsWithIndex") + s"Found zero addresses in the database to match an output we have a script for, txid=${transaction.txIdBE.hex} outputs=$outputsWithIndex" + ) } matchAddressDbWithOutputs(addressDbs, outputsWithIndex.toVector) } @@ -619,13 +659,15 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { nested.flatten } - /** Matches address dbs with outputs, drops addressDb/outputs that do not have matches */ + /** Matches address dbs with outputs, drops addressDb/outputs that do not have + * matches + */ private def matchAddressDbWithOutputs( addressDbs: Vector[AddressDb], - outputsWithIndex: Vector[OutputWithIndex]): Vector[ - (AddressDb, OutputWithIndex)] = { + outputsWithIndex: Vector[OutputWithIndex] + ): Vector[(AddressDb, OutputWithIndex)] = { val addressDbsWithOutputsOpt = outputsWithIndex.map { out => - //find address associated with spk + // find address associated with spk val addressDbOpt = addressDbs.find(_.scriptPubKey == out.output.scriptPubKey) addressDbOpt match { @@ -636,7 +678,7 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { Some((addressDb, out)) } } - //get rid of outputs we couldn't match to an address + // get rid of outputs we couldn't match to an address val result = addressDbsWithOutputsOpt.flatten result } @@ -644,10 +686,12 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { private[wallet] def insertIncomingTransaction( transaction: Transaction, incomingAmount: CurrencyUnit, - blockHashOpt: Option[DoubleSha256DigestBE]): DBIOAction[ + blockHashOpt: Option[DoubleSha256DigestBE] + ): DBIOAction[ (TransactionDb, IncomingTransactionDb), NoStream, - Effect.Read with Effect.Write] = { + Effect.Read with Effect.Write + ] = { val incomingDb = IncomingTransactionDb(transaction.txIdBE, incomingAmount) for { txDb <- insertTransactionAction(transaction, blockHashOpt) @@ -655,9 +699,12 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { } yield (txDb, written) } - /** Filters outputs on tx so that only relevant outputs to our wallet are included */ + /** Filters outputs on tx so that only relevant outputs to our wallet are + * included + */ private def getRelevantOutputs( - transaction: Transaction): Future[Vector[OutputWithIndex]] = { + transaction: Transaction + ): Future[Vector[OutputWithIndex]] = { val spks = transaction.outputs.map(_.scriptPubKey) scriptPubKeyDAO.findScriptPubKeys(spks.toVector).map { addrs => matchReceivedTx(addrs, transaction) @@ -666,7 +713,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { private def matchReceivedTx( addrs: Vector[ScriptPubKeyDb], - transaction: Transaction): Vector[OutputWithIndex] = { + transaction: Transaction + ): Vector[OutputWithIndex] = { val withIndex = transaction.outputs.zipWithIndex withIndex.collect { @@ -675,8 +723,9 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { }.toVector } - private def getRelevantOutputsForBlock(block: Block): Future[ - Map[DoubleSha256DigestBE, Vector[OutputWithIndex]]] = { + private def getRelevantOutputsForBlock( + block: Block + ): Future[Map[DoubleSha256DigestBE, Vector[OutputWithIndex]]] = { val spksInBlock: Vector[ScriptPubKey] = block.transactions .flatMap(tx => tx.outputs.map(o => o.scriptPubKey)) .toVector @@ -684,7 +733,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { spksInDbF.map { addrs => block.transactions.foldLeft( - Map.empty[DoubleSha256DigestBE, Vector[OutputWithIndex]]) { (acc, tx) => + Map.empty[DoubleSha256DigestBE, Vector[OutputWithIndex]] + ) { (acc, tx) => acc.updated(tx.txIdBE, matchReceivedTx(addrs, tx)) } } @@ -692,18 +742,20 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { /** Processes an incoming transaction that's new to us * - * @return A list of inserted transaction outputs + * @return + * A list of inserted transaction outputs */ private def processNewReceivedTx( transaction: Transaction, blockHashOpt: Option[DoubleSha256DigestBE], newTags: Vector[AddressTag], - relevantReceivedOutputs: Vector[OutputWithIndex]): Future[ - Seq[SpendingInfoDb]] = { + relevantReceivedOutputs: Vector[OutputWithIndex] + ): Future[Seq[SpendingInfoDb]] = { if (relevantReceivedOutputs.isEmpty) { logger.trace( - s"Found no outputs relevant to us in transaction${transaction.txIdBE.hex}") + s"Found no outputs relevant to us in transaction${transaction.txIdBE.hex}" + ) Future.successful(Vector.empty) } else { @@ -712,7 +764,7 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { relevantReceivedOutputs.contains(OutputWithIndex(o._1, o._2))) if (filteredOutputs.isEmpty) { - //no relevant outputs in this tx, return early + // no relevant outputs in this tx, return early Future.successful(Vector.empty) } else { val relevantReceivedOutputsForTx: Vector[OutputWithIndex] = { @@ -738,9 +790,11 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { val txDbA = for { ourOutputs <- ourOutputsA totalIncoming = ourOutputs.map(_.output.value).sum - incomingTx <- insertIncomingTransaction(transaction, - totalIncoming, - blockHashOpt) + incomingTx <- insertIncomingTransaction( + transaction, + totalIncoming, + blockHashOpt + ) } yield incomingTx val prevTagsDbA = for { @@ -777,8 +831,8 @@ private[bitcoins] trait TransactionProcessing extends WalletLogger { } } - private[wallet] def getTransactionsToBroadcast: Future[ - Vector[Transaction]] = { + private[wallet] def getTransactionsToBroadcast + : Future[Vector[Transaction]] = { for { mempoolUtxos <- spendingInfoDAO.findAllInMempool txIds = mempoolUtxos.map { utxo => diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/UtxoHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/UtxoHandling.scala index d42af66d47..b80256805b 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/internal/UtxoHandling.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/UtxoHandling.scala @@ -14,10 +14,9 @@ import org.bitcoins.wallet.{Wallet, WalletLogger} import scala.concurrent.Future -/** Provides functionality related to handling UTXOs in our wallet. - * The most notable examples of functionality here are enumerating - * UTXOs in the wallet and importing a UTXO into the wallet for later - * spending. +/** Provides functionality related to handling UTXOs in our wallet. The most + * notable examples of functionality here are enumerating UTXOs in the wallet + * and importing a UTXO into the wallet for later spending. */ private[wallet] trait UtxoHandling extends WalletLogger { self: Wallet => @@ -33,13 +32,15 @@ private[wallet] trait UtxoHandling extends WalletLogger { } override def listUtxos( - hdAccount: HDAccount): Future[Vector[SpendingInfoDb]] = { + hdAccount: HDAccount + ): Future[Vector[SpendingInfoDb]] = { spendingInfoDAO.findAllUnspentForAccount(hdAccount) } /** Returns all the utxos originating from the given outpoints */ - def listUtxos(outPoints: Vector[TransactionOutPoint]): Future[ - Vector[SpendingInfoDb]] = { + def listUtxos( + outPoints: Vector[TransactionOutPoint] + ): Future[Vector[SpendingInfoDb]] = { spendingInfoDAO .findAllSpendingInfos() .map(_.filter(spendingInfo => outPoints.contains(spendingInfo.outPoint))) @@ -51,11 +52,12 @@ private[wallet] trait UtxoHandling extends WalletLogger { override def listUtxos( hdAccount: HDAccount, - tag: AddressTag): Future[Vector[SpendingInfoDb]] = { + tag: AddressTag + ): Future[Vector[SpendingInfoDb]] = { spendingInfoDAO.findAllUnspentForTag(tag).map { utxos => utxos.filter(utxo => - HDAccount.isSameAccount(bip32Path = utxo.privKeyPath, - account = hdAccount)) + HDAccount + .isSameAccount(bip32Path = utxo.privKeyPath, account = hdAccount)) } } @@ -65,44 +67,49 @@ private[wallet] trait UtxoHandling extends WalletLogger { override def listUtxos( hdAccount: HDAccount, - state: TxoState): Future[Vector[SpendingInfoDb]] = { + state: TxoState + ): Future[Vector[SpendingInfoDb]] = { spendingInfoDAO.findByTxoState(state).map { utxos => utxos.filter(utxo => - HDAccount.isSameAccount(bip32Path = utxo.privKeyPath, - account = hdAccount)) + HDAccount + .isSameAccount(bip32Path = utxo.privKeyPath, account = hdAccount)) } } private[wallet] def updateUtxoSpentConfirmedStates( - txo: SpendingInfoDb): Future[Option[SpendingInfoDb]] = { + txo: SpendingInfoDb + ): Future[Option[SpendingInfoDb]] = { updateUtxoSpentConfirmedStates(Vector(txo)).map(_.headOption) } private[wallet] def updateUtxoSpentConfirmedStates( - txos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = { + txos: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] = { updateUtxoStates(txos, UtxoHandling.updateSpentTxoWithConfs) } private[wallet] def updateUtxoReceiveConfirmedStates( - txo: SpendingInfoDb): Future[Option[SpendingInfoDb]] = { + txo: SpendingInfoDb + ): Future[Option[SpendingInfoDb]] = { updateUtxoReceiveConfirmedStates(Vector(txo)) .map(_.headOption) } private[wallet] def updateUtxoReceiveConfirmedStates( - txos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = { + txos: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] = { updateUtxoStates(txos, UtxoHandling.updateReceivedTxoWithConfs) } - /** Returns a map of the SpendingInfoDbs with their relevant block. - * If the block hash is None, then it is a mempool transaction. - * The relevant block is determined by if the utxo has been spent or not. - * If it has been spent it uses the block that included the spending transaction, - * otherwise it uses the block that included the receiving transaction. + /** Returns a map of the SpendingInfoDbs with their relevant block. If the + * block hash is None, then it is a mempool transaction. The relevant block + * is determined by if the utxo has been spent or not. If it has been spent + * it uses the block that included the spending transaction, otherwise it + * uses the block that included the receiving transaction. */ private[wallet] def getDbsByRelevantBlock( - spendingInfoDbs: Vector[SpendingInfoDb]): Future[ - Map[Option[DoubleSha256DigestBE], Vector[SpendingInfoDb]]] = { + spendingInfoDbs: Vector[SpendingInfoDb] + ): Future[Map[Option[DoubleSha256DigestBE], Vector[SpendingInfoDb]]] = { val txIds = spendingInfoDbs.map { db => db.spendingTxIdOpt match { @@ -131,24 +138,27 @@ private[wallet] trait UtxoHandling extends WalletLogger { } } - /** Updates all the given SpendingInfoDbs to the correct state - * based on how many confirmations they have received - * @param spendingInfoDbs the utxos we need to update - * @param fn the function used to transition the [[TxoState]] given a utxo and number of confirmations + /** Updates all the given SpendingInfoDbs to the correct state based on how + * many confirmations they have received + * @param spendingInfoDbs + * the utxos we need to update + * @param fn + * the function used to transition the [[TxoState]] given a utxo and number + * of confirmations */ private def updateUtxoStates( spendingInfoDbs: Vector[SpendingInfoDb], - fn: (SpendingInfoDb, Int, Int) => SpendingInfoDb): Future[ - Vector[SpendingInfoDb]] = { - val relevantBlocksF: Future[ - Map[Option[DoubleSha256DigestBE], Vector[SpendingInfoDb]]] = { + fn: (SpendingInfoDb, Int, Int) => SpendingInfoDb + ): Future[Vector[SpendingInfoDb]] = { + val relevantBlocksF + : Future[Map[Option[DoubleSha256DigestBE], Vector[SpendingInfoDb]]] = { getDbsByRelevantBlock(spendingInfoDbs) } - //fetch all confirmations for those blocks, do it in parallel - //as an optimzation, previously we would fetch sequentially - val blocksWithConfsF: Future[ - Map[Option[BlockHashWithConfs], Vector[SpendingInfoDb]]] = { + // fetch all confirmations for those blocks, do it in parallel + // as an optimzation, previously we would fetch sequentially + val blocksWithConfsF + : Future[Map[Option[BlockHashWithConfs], Vector[SpendingInfoDb]]] = { for { relevantBlocks <- relevantBlocksF blocksWithConfirmations <- getConfirmationsForBlocks(relevantBlocks) @@ -161,14 +171,16 @@ private[wallet] trait UtxoHandling extends WalletLogger { blockHashWithConfs.confirmationsOpt match { case None => logger.warn( - s"Given txos exist in block (${blockHashWithConfs.blockHash.hex}) that we do not have or that has been reorged! $txos") + s"Given txos exist in block (${blockHashWithConfs.blockHash.hex}) that we do not have or that has been reorged! $txos" + ) Vector.empty case Some(confs) => txos.map(fn(_, confs, walletConfig.requiredConfirmations)) } case (None, txos) => logger.debug( - s"Currently have ${txos.size} transactions in the mempool") + s"Currently have ${txos.size} transactions in the mempool" + ) txos }.toVector @@ -187,10 +199,8 @@ private[wallet] trait UtxoHandling extends WalletLogger { /** Fetches confirmations for the given blocks in parallel */ private def getConfirmationsForBlocks( - relevantBlocks: Map[ - Option[DoubleSha256DigestBE], - Vector[SpendingInfoDb]]): Future[ - Map[Option[BlockHashWithConfs], Vector[SpendingInfoDb]]] = { + relevantBlocks: Map[Option[DoubleSha256DigestBE], Vector[SpendingInfoDb]] + ): Future[Map[Option[BlockHashWithConfs], Vector[SpendingInfoDb]]] = { val resultF = Source(relevantBlocks) .mapAsync(FutureUtil.getParallelism) { @@ -210,13 +220,16 @@ private[wallet] trait UtxoHandling extends WalletLogger { resultF.map(_.toMap) } - /** Constructs a DB level representation of the given UTXO, and persist it to disk */ + /** Constructs a DB level representation of the given UTXO, and persist it to + * disk + */ protected def writeUtxo( tx: Transaction, blockHashOpt: Option[DoubleSha256DigestBE], output: TransactionOutput, outPoint: TransactionOutPoint, - addressDb: AddressDb): Future[SpendingInfoDb] = { + addressDb: AddressDb + ): Future[SpendingInfoDb] = { val confirmationsF: Future[Int] = blockHashOpt match { case Some(blockHash) => chainQueryApi @@ -226,10 +239,11 @@ private[wallet] trait UtxoHandling extends WalletLogger { confs case None => sys.error( - s"Could not find block with our chain data source, hash=${blockHash}") + s"Could not find block with our chain data source, hash=${blockHash}" + ) } case None => - Future.successful(0) //no confirmations on the tx + Future.successful(0) // no confirmations on the tx } val stateF: Future[TxoState] = confirmationsF.map { confs => @@ -239,8 +253,10 @@ private[wallet] trait UtxoHandling extends WalletLogger { ) { TxoState.ImmatureCoinbase } else { - UtxoHandling.getReceiveConfsState(confs, - walletConfig.requiredConfirmations) + UtxoHandling.getReceiveConfsState( + confs, + walletConfig.requiredConfirmations + ) } } @@ -256,11 +272,13 @@ private[wallet] trait UtxoHandling extends WalletLogger { spendingTxIdOpt = None ) case LegacyAddressDb(path, _, _, _, _) => - LegacySpendingInfo(state = state, - outPoint = outPoint, - output = output, - privKeyPath = path, - spendingTxIdOpt = None) + LegacySpendingInfo( + state = state, + outPoint = outPoint, + output = output, + privKeyPath = path, + spendingTxIdOpt = None + ) case nested: NestedSegWitAddressDb => NestedSegwitV0SpendingInfo( outPoint = outPoint, @@ -285,14 +303,16 @@ private[wallet] trait UtxoHandling extends WalletLogger { } yield { val writtenOut = written.outPoint logger.info( - s"Successfully inserted UTXO ${writtenOut.txIdBE.hex}:${writtenOut.vout.toInt} amt=${output.value} into DB") + s"Successfully inserted UTXO ${writtenOut.txIdBE.hex}:${writtenOut.vout.toInt} amt=${output.value} into DB" + ) logger.debug(s"UTXO details: ${written.output}") written } } override def markUTXOsAsReserved( - utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = { + utxos: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] = { for { (utxos, callbackF) <- safeDatabase.run(markUTXOsAsReservedAction(utxos)) _ <- callbackF @@ -300,10 +320,12 @@ private[wallet] trait UtxoHandling extends WalletLogger { } protected def markUTXOsAsReservedAction( - utxos: Vector[SpendingInfoDb]): DBIOAction[ + utxos: Vector[SpendingInfoDb] + ): DBIOAction[ (Vector[SpendingInfoDb], Future[Unit]), NoStream, - Effect.Read with Effect.Write] = { + Effect.Read with Effect.Write + ] = { val outPoints = utxos.map(_.outPoint) logger.info(s"Reserving utxos=$outPoints") val updated = utxos.map(_.copyWithState(TxoState.Reserved)) @@ -315,7 +337,8 @@ private[wallet] trait UtxoHandling extends WalletLogger { /** @inheritdoc */ override def markUTXOsAsReserved( - tx: Transaction): Future[Vector[SpendingInfoDb]] = { + tx: Transaction + ): Future[Vector[SpendingInfoDb]] = { for { utxos <- spendingInfoDAO.findOutputsBeingSpent(tx) reserved <- markUTXOsAsReserved(utxos) @@ -323,14 +346,17 @@ private[wallet] trait UtxoHandling extends WalletLogger { } override def unmarkUTXOsAsReserved( - utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = { + utxos: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] = { logger.info(s"Unreserving utxos ${utxos.map(_.outPoint)}") val updatedUtxosF = Future { - //make sure exception isn't thrown outside of a future to fix - //see: https://github.com/bitcoin-s/bitcoin-s/issues/3813 + // make sure exception isn't thrown outside of a future to fix + // see: https://github.com/bitcoin-s/bitcoin-s/issues/3813 val unreserved = utxos.filterNot(_.state == TxoState.Reserved) - require(unreserved.isEmpty, - s"Some utxos are not reserved, got $unreserved") + require( + unreserved.isEmpty, + s"Some utxos are not reserved, got $unreserved" + ) // unmark all utxos are reserved val updatedUtxos = utxos @@ -347,7 +373,8 @@ private[wallet] trait UtxoHandling extends WalletLogger { pendingConf = updatedUtxos.filterNot(utxo => updatedConfirmed.exists(_.outPoint == utxo.outPoint)) updated <- spendingInfoDAO.updateAllSpendingInfoDb( - pendingConf ++ updatedConfirmed) + pendingConf ++ updatedConfirmed + ) _ <- walletCallbacks.executeOnReservedUtxos(updated) } yield updated @@ -355,7 +382,8 @@ private[wallet] trait UtxoHandling extends WalletLogger { /** @inheritdoc */ override def unmarkUTXOsAsReserved( - tx: Transaction): Future[Vector[SpendingInfoDb]] = { + tx: Transaction + ): Future[Vector[SpendingInfoDb]] = { for { utxos <- spendingInfoDAO.findOutputsBeingSpent(tx) reserved = utxos.filter(_.state == TxoState.Reserved) @@ -378,13 +406,14 @@ private[wallet] trait UtxoHandling extends WalletLogger { object UtxoHandling { - /** Updates the SpendingInfoDb to the correct state based - * on the number of confirmations it has received + /** Updates the SpendingInfoDb to the correct state based on the number of + * confirmations it has received */ def updateReceivedTxoWithConfs( txo: SpendingInfoDb, confs: Int, - requiredConfirmations: Int): SpendingInfoDb = { + requiredConfirmations: Int + ): SpendingInfoDb = { txo.state match { case TxoState.ImmatureCoinbase => if (confs > Consensus.coinbaseMaturity) { @@ -398,7 +427,7 @@ object UtxoHandling { val state = getReceiveConfsState(confs, requiredConfirmations) txo.copyWithState(state) case TxoState.Reserved => - //do nothing if we have reserved the utxo + // do nothing if we have reserved the utxo txo case state: SpentState => sys.error(s"Cannot update spendingInfoDb in spent state=$state") @@ -406,15 +435,18 @@ object UtxoHandling { } } - /** Given a number of confirmations and the required confirmations for the wallet - * this method returns the appropriate [[ReceivedState]] for the number of confirmations + /** Given a number of confirmations and the required confirmations for the + * wallet this method returns the appropriate [[ReceivedState]] for the + * number of confirmations */ def getReceiveConfsState( confs: Int, - requireConfirmations: Int): ReceivedState = { + requireConfirmations: Int + ): ReceivedState = { if (confs < 0) { sys.error( - s"Cannot have negative confirmations, got=$confs. Did the block get reorged or exist?") + s"Cannot have negative confirmations, got=$confs. Did the block get reorged or exist?" + ) } else if (confs == 0) { TxoState.BroadcastReceived } else if (confs >= requireConfirmations) { @@ -427,11 +459,13 @@ object UtxoHandling { def updateSpentTxoWithConfs( txo: SpendingInfoDb, confs: Int, - requiredConfirmations: Int): SpendingInfoDb = { + requiredConfirmations: Int + ): SpendingInfoDb = { txo.state match { case TxoState.ImmatureCoinbase => sys.error( - s"Cannot update txo with received state=${TxoState.ImmatureCoinbase}") + s"Cannot update txo with received state=${TxoState.ImmatureCoinbase}" + ) case TxoState.Reserved | TxoState.PendingConfirmationsSpent | TxoState.ConfirmedSpent | TxoState.BroadcastSpent | TxoState.PendingConfirmationsReceived | TxoState.BroadcastReceived | diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/AccountDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/AccountDAO.scala index e3b7ce513d..5964bf5d36 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/AccountDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/AccountDAO.scala @@ -11,8 +11,8 @@ import scala.concurrent.{ExecutionContext, Future} case class AccountDAO()(implicit override val ec: ExecutionContext, - override val appConfig: WalletAppConfig) - extends CRUD[AccountDb, (HDCoin, Int)] + override val appConfig: WalletAppConfig +) extends CRUD[AccountDb, (HDCoin, Int)] with SlickUtil[AccountDb, (HDCoin, Int)] { import profile.api._ private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -24,7 +24,8 @@ case class AccountDAO()(implicit createAllNoAutoInc(ts, safeDatabase) override protected def findByPrimaryKeys( - ids: Vector[(HDCoin, Int)]): Query[AccountTable, AccountDb, Seq] = { + ids: Vector[(HDCoin, Int)] + ): Query[AccountTable, AccountDb, Seq] = { val queries = ids.map(findByPrimaryKey(_)) if (queries.isEmpty) { @@ -39,7 +40,8 @@ case class AccountDAO()(implicit } override def findByPrimaryKey( - id: (HDCoin, Int)): Query[AccountTable, AccountDb, Seq] = { + id: (HDCoin, Int) + ): Query[AccountTable, AccountDb, Seq] = { val (coin, index) = id table .filter(_.coinType === coin.coinType) @@ -48,14 +50,15 @@ case class AccountDAO()(implicit } override def findAll( - accounts: Vector[AccountDb]): Query[AccountTable, AccountDb, Seq] = + accounts: Vector[AccountDb] + ): Query[AccountTable, AccountDb, Seq] = findByPrimaryKeys( - accounts.map(acc => (acc.hdAccount.coin, acc.hdAccount.index))) + accounts.map(acc => (acc.hdAccount.coin, acc.hdAccount.index)) + ) - def findByAccountAction(account: HDAccount): DBIOAction[ - Option[AccountDb], - NoStream, - Effect.Read] = { + def findByAccountAction( + account: HDAccount + ): DBIOAction[Option[AccountDb], NoStream, Effect.Read] = { val q = table .filter(_.coinType === account.coin.coinType) .filter(_.purpose === account.purpose) @@ -67,9 +70,10 @@ case class AccountDAO()(implicit case Vector() => None case accounts: Vector[AccountDb] => - //yikes, we should not have more the one account per coin type/purpose + // yikes, we should not have more the one account per coin type/purpose throw new RuntimeException( - s"More than one account per account=${account}, got=${accounts}") + s"More than one account per account=${account}, got=${accounts}" + ) } } @@ -98,10 +102,13 @@ case class AccountDAO()(implicit private val toTuple: AccountDb => Option[AccountTuple] = account => Some( - (account.hdAccount.purpose, - account.xpub, - account.hdAccount.coin.coinType, - account.hdAccount.index)) + ( + account.hdAccount.purpose, + account.xpub, + account.hdAccount.coin.coinType, + account.hdAccount.index + ) + ) def * : ProvenShape[AccountDb] = (purpose, xpub, coinType, index).<>(fromTuple, toTuple) diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/AddressDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/AddressDAO.scala index 97124bb800..743bee3b64 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/AddressDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/AddressDAO.scala @@ -31,24 +31,26 @@ case class AddressDAO()(implicit override val table: profile.api.TableQuery[AddressTable] = TableQuery[AddressTable] - private lazy val spendingInfoTable: profile.api.TableQuery[ - SpendingInfoDAO#SpendingInfoTable] = { + private lazy val spendingInfoTable + : profile.api.TableQuery[SpendingInfoDAO#SpendingInfoTable] = { SpendingInfoDAO().table } - private lazy val spkTable: profile.api.TableQuery[ - ScriptPubKeyDAO#ScriptPubKeyTable] = { + private lazy val spkTable + : profile.api.TableQuery[ScriptPubKeyDAO#ScriptPubKeyTable] = { ScriptPubKeyDAO().table } override def createAll( - ts: Vector[AddressRecord]): Future[Vector[AddressRecord]] = + ts: Vector[AddressRecord] + ): Future[Vector[AddressRecord]] = createAllNoAutoInc(ts, safeDatabase) def createAction(addressDb: AddressDb): DBIOAction[ AddressDb, NoStream, - Effect.Read with Effect.Write with Effect.Transactional] = { + Effect.Read with Effect.Write with Effect.Transactional + ] = { val spkFind = spkTable.filter(_.scriptPubKey === addressDb.scriptPubKey).result val actions = for { @@ -60,7 +62,8 @@ case class AddressDAO()(implicit (for { newSpkId <- (spkTable returning spkTable.map(_.id)) += (ScriptPubKeyDb( - addressDb.scriptPubKey)) + addressDb.scriptPubKey + )) } yield { val record = AddressRecord.fromAddressDb(addressDb, newSpkId) table += record @@ -78,7 +81,8 @@ case class AddressDAO()(implicit case (Some(addr), Some(spk)) => addr.toAddressDb(spk.scriptPubKey) case _ => throw new SQLException( - s"Unexpected result: Cannot create either a address or a SPK record for $addressDb") + s"Unexpected result: Cannot create either a address or a SPK record for $addressDb" + ) } } @@ -96,14 +100,17 @@ case class AddressDAO()(implicit _ <- spkOpt match { case Some(foundSpk) => table.insertOrUpdate( - AddressRecord.fromAddressDb(addressDb, foundSpk.id.get)) + AddressRecord.fromAddressDb(addressDb, foundSpk.id.get) + ) case None => (for { newSpkId <- (spkTable returning spkTable.map(_.id)) += ScriptPubKeyDb( - addressDb.scriptPubKey) + addressDb.scriptPubKey + ) } yield table.insertOrUpdate( - AddressRecord.fromAddressDb(addressDb, newSpkId))).flatten + AddressRecord.fromAddressDb(addressDb, newSpkId) + )).flatten } addr <- table.filter(_.address === addressDb.address).result.headOption spk <- @@ -119,7 +126,8 @@ case class AddressDAO()(implicit case (Some(addr), Some(spk)) => addr.toAddressDb(spk.scriptPubKey) case _ => throw new SQLException( - s"Unexpected result: Cannot upsert either a address or a SPK record for $addressDb") + s"Unexpected result: Cannot upsert either a address or a SPK record for $addressDb" + ) } } @@ -133,20 +141,18 @@ case class AddressDAO()(implicit } /** Finds the rows that correlate to the given primary keys */ - override def findByPrimaryKeys(addresses: Vector[BitcoinAddress]): Query[ - AddressTable, - AddressRecord, - Seq] = + override def findByPrimaryKeys( + addresses: Vector[BitcoinAddress] + ): Query[AddressTable, AddressRecord, Seq] = table.filter(_.address.inSet(addresses)) override def findAll( - ts: Vector[AddressRecord]): Query[AddressTable, AddressRecord, Seq] = + ts: Vector[AddressRecord] + ): Query[AddressTable, AddressRecord, Seq] = findByPrimaryKeys(ts.map(_.address)) - def findAllAddressesAction(): DBIOAction[ - Vector[AddressDb], - NoStream, - Effect.Read] = { + def findAllAddressesAction() + : DBIOAction[Vector[AddressDb], NoStream, Effect.Read] = { val query = table .join(spkTable) .on(_.scriptPubKeyId === _.id) @@ -168,10 +174,9 @@ case class AddressDAO()(implicit safeDatabase.run(findAddressAction(addr)) } - def findAddressAction(addr: BitcoinAddress): DBIOAction[ - Option[AddressDb], - NoStream, - Effect.Read] = { + def findAddressAction( + addr: BitcoinAddress + ): DBIOAction[Option[AddressDb], NoStream, Effect.Read] = { table .join(spkTable) .on(_.scriptPubKeyId === _.id) @@ -187,14 +192,16 @@ case class AddressDAO()(implicit private def addressesForAccountQuery(accountIndex: Int): Query[ (AddressTable, ScriptPubKeyDAO#ScriptPubKeyTable), (AddressRecord, ScriptPubKeyDb), - Seq] = + Seq + ] = table .join(spkTable) .on(_.scriptPubKeyId === _.id) .filter(_._1.accountIndex === accountIndex) def findAllAddressDbForAccount( - account: HDAccount): Future[Vector[AddressDb]] = { + account: HDAccount + ): Future[Vector[AddressDb]] = { val query = table .join(spkTable) .on(_.scriptPubKeyId === _.id) @@ -215,10 +222,9 @@ case class AddressDAO()(implicit safeDatabase.runVec(action) } - def findAllForAccountAction(account: HDAccount): DBIOAction[ - Vector[AddressRecord], - NoStream, - Effect.Read] = { + def findAllForAccountAction( + account: HDAccount + ): DBIOAction[Vector[AddressRecord], NoStream, Effect.Read] = { val query = table .filter(_.purpose === account.purpose) .filter(_.accountIndex === account.index) @@ -226,10 +232,9 @@ case class AddressDAO()(implicit query.result.map(_.toVector) } - def findMostRecentChangeAction(hdAccount: HDAccount): DBIOAction[ - Option[AddressDb], - NoStream, - Effect.Read] = { + def findMostRecentChangeAction( + hdAccount: HDAccount + ): DBIOAction[Option[AddressDb], NoStream, Effect.Read] = { val action = findMostRecentForChain(hdAccount, HDChainType.Change) action.map(_.map { case (addrRec, spkRec) => @@ -315,14 +320,14 @@ case class AddressDAO()(implicit } def findByScriptPubKeys( - spks: Vector[ScriptPubKey]): Future[Vector[AddressDb]] = { + spks: Vector[ScriptPubKey] + ): Future[Vector[AddressDb]] = { safeDatabase.run(findByScriptPubKeysAction(spks)) } - def findByScriptPubKeysAction(spks: Vector[ScriptPubKey]): DBIOAction[ - Vector[AddressDb], - NoStream, - Effect.Read] = { + def findByScriptPubKeysAction( + spks: Vector[ScriptPubKey] + ): DBIOAction[Vector[AddressDb], NoStream, Effect.Read] = { table .join(spkTable) .on(_.scriptPubKeyId === _.id) @@ -335,10 +340,12 @@ case class AddressDAO()(implicit private def findMostRecentForChain( account: HDAccount, - chain: HDChainType): DBIOAction[ - Option[(AddressRecord, ScriptPubKeyDb)], - NoStream, - Effect.Read] = { + chain: HDChainType + ): DBIOAction[Option[ + (AddressRecord, ScriptPubKeyDb) + ], + NoStream, + Effect.Read] = { addressesForAccountQuery(account.index) .filter(_._1.purpose === account.purpose) .filter(_._1.accountCoin === account.coin.coinType) @@ -349,10 +356,9 @@ case class AddressDAO()(implicit .headOption } - def findMostRecentExternalAction(hdAccount: HDAccount): DBIOAction[ - Option[AddressDb], - NoStream, - Effect.Read] = { + def findMostRecentExternalAction( + hdAccount: HDAccount + ): DBIOAction[Option[AddressDb], NoStream, Effect.Read] = { val action = findMostRecentForChain(hdAccount, HDChainType.External) action.map(_.map { case (addrRec, spkRec) => addrRec.toAddressDb(spkRec.scriptPubKey) @@ -362,13 +368,14 @@ case class AddressDAO()(implicit /** Finds the most recent external address in the wallet, if any */ def findMostRecentExternal( - hdAccount: HDAccount): Future[Option[AddressDb]] = { + hdAccount: HDAccount + ): Future[Option[AddressDb]] = { val action = findMostRecentExternalAction(hdAccount) safeDatabase.run(action) } - /** todo: this needs design rework. - * todo: https://github.com/bitcoin-s/bitcoin-s-core/pull/391#discussion_r274188334 + /** todo: this needs design rework. todo: + * https://github.com/bitcoin-s/bitcoin-s-core/pull/391#discussion_r274188334 */ class AddressTable(tag: Tag) extends Table[AddressRecord](tag, schemaName, "addresses") { @@ -394,21 +401,25 @@ case class AddressDAO()(implicit def scriptWitness: Rep[Option[ScriptWitness]] = column("script_witness") override def * = - (purpose, - accountCoin, - accountIndex, - accountChainType, - addressIndex, - address, - ecPublicKey, - hashedPubKey, - scriptPubKeyId, - scriptWitness).<>((AddressRecord.apply _).tupled, AddressRecord.unapply) + ( + purpose, + accountCoin, + accountIndex, + accountChainType, + addressIndex, + address, + ecPublicKey, + hashedPubKey, + scriptPubKeyId, + scriptWitness + ).<>((AddressRecord.apply _).tupled, AddressRecord.unapply) def fk_scriptPubKeyId: ForeignKeyQuery[_, ScriptPubKeyDb] = { - foreignKey("fk_spk", - sourceColumns = scriptPubKeyId, - targetTableQuery = spkTable)(_.id) + foreignKey( + "fk_spk", + sourceColumns = scriptPubKeyId, + targetTableQuery = spkTable + )(_.id) } } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/AddressTagDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/AddressTagDAO.scala index 1aefb31af4..2447fa143d 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/AddressTagDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/AddressTagDAO.scala @@ -19,8 +19,8 @@ import scala.concurrent.{ExecutionContext, Future} case class AddressTagDAO()(implicit override val ec: ExecutionContext, - override val appConfig: WalletAppConfig) - extends CRUD[AddressTagDb, (BitcoinAddress, AddressTagType)] + override val appConfig: WalletAppConfig +) extends CRUD[AddressTagDb, (BitcoinAddress, AddressTagType)] with SlickUtil[AddressTagDb, (BitcoinAddress, AddressTagType)] { import profile.api._ private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -29,40 +29,38 @@ case class AddressTagDAO()(implicit override val table: profile.api.TableQuery[AddressTagTable] = TableQuery[AddressTagTable] - private lazy val spendingInfoTable: slick.lifted.TableQuery[ - SpendingInfoDAO#SpendingInfoTable] = { + private lazy val spendingInfoTable + : slick.lifted.TableQuery[SpendingInfoDAO#SpendingInfoTable] = { SpendingInfoDAO().table } - private lazy val addressTable: slick.lifted.TableQuery[ - AddressDAO#AddressTable] = { + private lazy val addressTable + : slick.lifted.TableQuery[AddressDAO#AddressTable] = { AddressDAO().table } - private lazy val spkTable: profile.api.TableQuery[ - ScriptPubKeyDAO#ScriptPubKeyTable] = { + private lazy val spkTable + : profile.api.TableQuery[ScriptPubKeyDAO#ScriptPubKeyTable] = { ScriptPubKeyDAO().table } override def createAll( - ts: Vector[AddressTagDb]): Future[Vector[AddressTagDb]] = + ts: Vector[AddressTagDb] + ): Future[Vector[AddressTagDb]] = createAllNoAutoInc(ts, safeDatabase) /** Finds the rows that correlate to the given primary keys */ override def findByPrimaryKeys( - ids: Vector[(BitcoinAddress, AddressTagType)]): Query[ - AddressTagTable, - AddressTagDb, - Seq] = { + ids: Vector[(BitcoinAddress, AddressTagType)] + ): Query[AddressTagTable, AddressTagDb, Seq] = { val addresses = ids.map(_._1) val tagTypes = ids.map(_._2) table.filter(t => t.address.inSet(addresses) && t.tagType.inSet(tagTypes)) } - override def findByPrimaryKey(id: (BitcoinAddress, AddressTagType)): Query[ - Table[AddressTagDb], - AddressTagDb, - Seq] = { + override def findByPrimaryKey( + id: (BitcoinAddress, AddressTagType) + ): Query[Table[AddressTagDb], AddressTagDb, Seq] = { val (address, tagType) = id table .filter(_.address === address) @@ -70,13 +68,13 @@ case class AddressTagDAO()(implicit } override def findAll( - ts: Vector[AddressTagDb]): Query[Table[AddressTagDb], AddressTagDb, Seq] = + ts: Vector[AddressTagDb] + ): Query[Table[AddressTagDb], AddressTagDb, Seq] = findByPrimaryKeys(ts.map(t => (t.address, t.tagType))) - def findByAddressAction(address: BitcoinAddress): DBIOAction[ - Vector[AddressTagDb], - NoStream, - Effect.Read] = { + def findByAddressAction( + address: BitcoinAddress + ): DBIOAction[Vector[AddressTagDb], NoStream, Effect.Read] = { table.filter(_.address === address).result.map(_.toVector) } @@ -86,7 +84,8 @@ case class AddressTagDAO()(implicit def findByAddressAndTag( address: BitcoinAddress, - tagType: AddressTagType): Future[Vector[AddressTagDb]] = { + tagType: AddressTagType + ): Future[Vector[AddressTagDb]] = { val query = table .filter(_.address === address) .filter(_.tagType === tagType) @@ -121,7 +120,8 @@ case class AddressTagDAO()(implicit def dropByAddressAndTag( address: BitcoinAddress, - tagType: AddressTagType): Future[Int] = { + tagType: AddressTagType + ): Future[Int] = { val query = table .filter(_.address === address) .filter(_.tagType === tagType) @@ -131,7 +131,8 @@ case class AddressTagDAO()(implicit def dropByAddressAndName( address: BitcoinAddress, - tagName: AddressTagName): Future[Int] = { + tagName: AddressTagName + ): Future[Int] = { val query = table .filter(_.address === address) .filter(_.tagName === tagName) @@ -139,10 +140,10 @@ case class AddressTagDAO()(implicit safeDatabase.run(query.delete) } - def findTxAction(tx: Transaction, network: NetworkParameters): DBIOAction[ - Vector[AddressTagDb], - NoStream, - Effect.Read] = { + def findTxAction( + tx: Transaction, + network: NetworkParameters + ): DBIOAction[Vector[AddressTagDb], NoStream, Effect.Read] = { val txIds = tx.inputs.map(_.previousOutput.txIdBE) val findUtxosA = { @@ -183,14 +184,14 @@ case class AddressTagDAO()(implicit def findTx( tx: Transaction, - network: NetworkParameters): Future[Vector[AddressTagDb]] = { + network: NetworkParameters + ): Future[Vector[AddressTagDb]] = { safeDatabase.run(findTxAction(tx, network)) } - def deleteByAddressesAction(addresses: Vector[BitcoinAddress]): DBIOAction[ - Int, - NoStream, - Effect.Write] = { + def deleteByAddressesAction( + addresses: Vector[BitcoinAddress] + ): DBIOAction[Int, NoStream, Effect.Write] = { table.filter(t => t.address.inSet(addresses)).delete } @@ -227,9 +228,11 @@ case class AddressTagDAO()(implicit /** All tags must have an associated address */ def fk_address = { - foreignKey("fk_address", - sourceColumns = address, - targetTableQuery = addressTable)(_.address) + foreignKey( + "fk_address", + sourceColumns = address, + targetTableQuery = addressTable + )(_.address) } } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/IncomingTransactionDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/IncomingTransactionDAO.scala index 151c786b43..200fd8bfd9 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/IncomingTransactionDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/IncomingTransactionDAO.scala @@ -10,23 +10,25 @@ import scala.concurrent.ExecutionContext case class IncomingTransactionDAO()(implicit override val ec: ExecutionContext, - override val appConfig: WalletAppConfig) - extends TxDAO[IncomingTransactionDb] { + override val appConfig: WalletAppConfig +) extends TxDAO[IncomingTransactionDb] { import profile.api._ override val table: profile.api.TableQuery[IncomingTransactionTable] = { TableQuery[IncomingTransactionTable] } - private lazy val txTable: profile.api.TableQuery[ - TransactionDAO#TransactionTable] = { + private lazy val txTable + : profile.api.TableQuery[TransactionDAO#TransactionTable] = { TransactionDAO().table } class IncomingTransactionTable(tag: Tag) - extends TxTable[IncomingTransactionDb](tag, - schemaName, - "wallet_incoming_txs") { + extends TxTable[IncomingTransactionDb]( + tag, + schemaName, + "wallet_incoming_txs" + ) { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) import mappers._ @@ -42,8 +44,9 @@ case class IncomingTransactionDAO()(implicit IncomingTransactionDb(txId, incomingAmount) } - private val toTuple: IncomingTransactionDb => Option[ - IncomingTransactionTuple] = tx => Some((tx.txIdBE, tx.incomingAmount)) + private val toTuple + : IncomingTransactionDb => Option[IncomingTransactionTuple] = tx => + Some((tx.txIdBE, tx.incomingAmount)) def * : ProvenShape[IncomingTransactionDb] = (txIdBE, incomingAmount).<>(fromTuple, toTuple) @@ -52,9 +55,11 @@ case class IncomingTransactionDAO()(implicit primaryKey("pk_in_tx", sourceColumns = txIdBE) def fk_underlying_tx: slick.lifted.ForeignKeyQuery[_, TransactionDb] = { - foreignKey("fk_underlying_tx", - sourceColumns = txIdBE, - targetTableQuery = txTable)(_.txIdBE) + foreignKey( + "fk_underlying_tx", + sourceColumns = txIdBE, + targetTableQuery = txTable + )(_.txIdBE) } } } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/OutgoingTransactionDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/OutgoingTransactionDAO.scala index bae9a709dc..9085de85e4 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/OutgoingTransactionDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/OutgoingTransactionDAO.scala @@ -11,8 +11,8 @@ import scala.concurrent.ExecutionContext case class OutgoingTransactionDAO()(implicit override val ec: ExecutionContext, - override val appConfig: WalletAppConfig) - extends TxDAO[OutgoingTransactionDb] { + override val appConfig: WalletAppConfig +) extends TxDAO[OutgoingTransactionDb] { import profile.api._ @@ -25,9 +25,11 @@ case class OutgoingTransactionDAO()(implicit } class OutgoingTransactionTable(tag: Tag) - extends TxTable[OutgoingTransactionDb](tag, - schemaName, - "wallet_outgoing_txs") { + extends TxTable[OutgoingTransactionDb]( + tag, + schemaName, + "wallet_outgoing_txs" + ) { private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) import mappers._ @@ -51,40 +53,49 @@ case class OutgoingTransactionDAO()(implicit CurrencyUnit, CurrencyUnit, CurrencyUnit, - SatoshisPerByte) + SatoshisPerByte + ) private val fromTuple: OutgoingTransactionTuple => OutgoingTransactionDb = { case (txId, inputAmount, sentAmount, actualFee, expectedFee, feeRate) => - OutgoingTransactionDb(txId, - inputAmount, - sentAmount, - actualFee, - expectedFee, - feeRate) + OutgoingTransactionDb( + txId, + inputAmount, + sentAmount, + actualFee, + expectedFee, + feeRate + ) } - private val toTuple: OutgoingTransactionDb => Option[ - OutgoingTransactionTuple] = tx => + private val toTuple + : OutgoingTransactionDb => Option[OutgoingTransactionTuple] = tx => Some( - (tx.txIdBE, - tx.inputAmount, - tx.sentAmount, - tx.actualFee, - tx.expectedFee, - tx.feeRate)) + ( + tx.txIdBE, + tx.inputAmount, + tx.sentAmount, + tx.actualFee, + tx.expectedFee, + tx.feeRate + ) + ) def * : ProvenShape[OutgoingTransactionDb] = (txIdBE, inputAmount, sentAmount, actualFee, expectedFee, feeRate).<>( fromTuple, - toTuple) + toTuple + ) def primaryKey: PrimaryKey = primaryKey("pk_out_tx", sourceColumns = txIdBE) def fk_underlying_tx: slick.lifted.ForeignKeyQuery[_, TransactionDb] = { - foreignKey("fk_underlying_tx", - sourceColumns = txIdBE, - targetTableQuery = txTable)(_.txIdBE) + foreignKey( + "fk_underlying_tx", + sourceColumns = txIdBE, + targetTableQuery = txTable + )(_.txIdBE) } } } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/ScriptPubKeyDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/ScriptPubKeyDAO.scala index ea724ddc48..68bc645aea 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/ScriptPubKeyDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/ScriptPubKeyDAO.scala @@ -21,7 +21,9 @@ case class ScriptPubKeyDAO()(implicit override val table: profile.api.TableQuery[ScriptPubKeyTable] = TableQuery[ScriptPubKeyTable] - /** Creates a new row in the database only if the given SPK (not ID) does not exists. */ + /** Creates a new row in the database only if the given SPK (not ID) does not + * exists. + */ def createIfNotExists(spkDb: ScriptPubKeyDb): Future[ScriptPubKeyDb] = { val spkFind = table.filter(_.scriptPubKey === spkDb.scriptPubKey).result val actions = for { @@ -47,12 +49,11 @@ case class ScriptPubKeyDAO()(implicit foundVecF.map(_.headOption) } - def findScriptPubKeysAction(spks: Vector[ScriptPubKey]): DBIOAction[ - Vector[ScriptPubKeyDb], - NoStream, - Effect.Read] = { + def findScriptPubKeysAction( + spks: Vector[ScriptPubKey] + ): DBIOAction[Vector[ScriptPubKeyDb], NoStream, Effect.Read] = { val hashes = spks.map(ScriptPubKeyDb.hash) - //group hashes to avoid https://github.com/bitcoin-s/bitcoin-s/issues/4220 + // group hashes to avoid https://github.com/bitcoin-s/bitcoin-s/issues/4220 val groupedHashes: Vector[Vector[Sha256Digest]] = hashes.grouped(1000).toVector val actions = @@ -60,9 +61,12 @@ case class ScriptPubKeyDAO()(implicit DBIO.sequence(actions).map(_.flatten.toVector) } - /** Searches for the given set of spks and returns the ones that exist in the db */ + /** Searches for the given set of spks and returns the ones that exist in the + * db + */ def findScriptPubKeys( - spks: Vector[ScriptPubKey]): Future[Vector[ScriptPubKeyDb]] = { + spks: Vector[ScriptPubKey] + ): Future[Vector[ScriptPubKeyDb]] = { val action = findScriptPubKeysAction(spks) safeDatabase.run(action) } @@ -83,17 +87,21 @@ case class ScriptPubKeyDAO()(implicit case (id, scriptPubKey, scriptType, hash) => require( scriptPubKey.scriptType == scriptType, - s"script type must match it script: `${scriptPubKey.scriptType}` != `${scriptType}` ") + s"script type must match it script: `${scriptPubKey.scriptType}` != `${scriptType}` " + ) ScriptPubKeyDb(scriptPubKey, hash, id) } private val toTuple: ScriptPubKeyDb => Option[ScriptPubKeyTuple] = { scriptPubKeyDb => Some( - (scriptPubKeyDb.id, - scriptPubKeyDb.scriptPubKey, - scriptPubKeyDb.scriptPubKey.scriptType, - scriptPubKeyDb.hash)) + ( + scriptPubKeyDb.id, + scriptPubKeyDb.scriptPubKey, + scriptPubKeyDb.scriptPubKey.scriptType, + scriptPubKeyDb.hash + ) + ) } override def * = diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/SpendingInfoDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/SpendingInfoDAO.scala index 553ce668d3..ca3bd2298a 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/SpendingInfoDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/SpendingInfoDAO.scala @@ -17,8 +17,8 @@ import scala.concurrent.{ExecutionContext, Future} case class SpendingInfoDAO()(implicit override val ec: ExecutionContext, - override val appConfig: WalletAppConfig) - extends CRUDAutoInc[UTXORecord] { + override val appConfig: WalletAppConfig +) extends CRUDAutoInc[UTXORecord] { import profile.api._ private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) import mappers._ @@ -27,23 +27,24 @@ case class SpendingInfoDAO()(implicit override val table: profile.api.TableQuery[SpendingInfoTable] = profile.api.TableQuery[SpendingInfoTable] - private lazy val addrTable: profile.api.TableQuery[ - AddressDAO#AddressTable] = { + private lazy val addrTable + : profile.api.TableQuery[AddressDAO#AddressTable] = { AddressDAO()(ec, appConfig).table } private lazy val txTable: profile.api.TableQuery[ - IncomingTransactionDAO#IncomingTransactionTable] = { + IncomingTransactionDAO#IncomingTransactionTable + ] = { IncomingTransactionDAO().table } - private lazy val tagTable: profile.api.TableQuery[ - AddressTagDAO#AddressTagTable] = { + private lazy val tagTable + : profile.api.TableQuery[AddressTagDAO#AddressTagTable] = { AddressTagDAO().table } - private lazy val spkTable: profile.api.TableQuery[ - ScriptPubKeyDAO#ScriptPubKeyTable] = { + private lazy val spkTable + : profile.api.TableQuery[ScriptPubKeyDAO#ScriptPubKeyTable] = { ScriptPubKeyDAO().table } @@ -63,13 +64,14 @@ case class SpendingInfoDAO()(implicit case (utxo, Some(spk)) => utxo.toSpendingInfoDb(spk.scriptPubKey) case _ => throw new SQLException( - s"Unexpected result: Cannot create either a UTXO or a SPK record for $si") + s"Unexpected result: Cannot create either a UTXO or a SPK record for $si" + ) } } - def createUnless(si: SpendingInfoDb)( - condition: (UTXORecord, UTXORecord) => Boolean): Future[ - SpendingInfoDb] = { + def createUnless( + si: SpendingInfoDb + )(condition: (UTXORecord, UTXORecord) => Boolean): Future[SpendingInfoDb] = { val actions = for { foundOpt <- table.filter(_.outPoint === si.outPoint).result.headOption cond <- foundOpt match { @@ -94,14 +96,14 @@ case class SpendingInfoDAO()(implicit case (utxo, Some(spk)) => utxo.toSpendingInfoDb(spk.scriptPubKey) case _ => throw new SQLException( - s"Unexpected result: Cannot create either a UTXO or a SPK record for $si") + s"Unexpected result: Cannot create either a UTXO or a SPK record for $si" + ) } } - private def insertAction(si: SpendingInfoDb): DBIOAction[ - UTXORecord, - NoStream, - Effect.Read with Effect.Write] = { + private def insertAction( + si: SpendingInfoDb + ): DBIOAction[UTXORecord, NoStream, Effect.Read with Effect.Write] = { val query = table.returning(table.map(_.id)).into((t, id) => t.copyWithId(id = id)) for { @@ -118,7 +120,8 @@ case class SpendingInfoDAO()(implicit (for { newSpkId <- (spkTable returning spkTable.map(_.id)) += (ScriptPubKeyDb( - si.output.scriptPubKey)) + si.output.scriptPubKey + )) } yield { val utxo = UTXORecord.fromSpendingInfoDb(si, newSpkId) query += utxo @@ -128,13 +131,15 @@ case class SpendingInfoDAO()(implicit } def upsertAllSpendingInfoDb( - ts: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = { + ts: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] = { FutureUtil.foldLeftAsync(Vector.empty[SpendingInfoDb], ts)((acc, si) => upsert(si).map(res => acc :+ res)) } def updateAllSpendingInfoDb( - ts: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = { + ts: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] = { FutureUtil.foldLeftAsync(Vector.empty[SpendingInfoDb], ts)((acc, si) => update(si).map(res => acc :+ res)) } @@ -154,7 +159,8 @@ case class SpendingInfoDAO()(implicit (for { newSpkId <- (spkTable returning spkTable.map(_.id)) += ScriptPubKeyDb( - si.output.scriptPubKey) + si.output.scriptPubKey + ) } yield { val utxo = UTXORecord.fromSpendingInfoDb(si, newSpkId) table.filter(_.id === utxo.id).update(utxo) @@ -173,7 +179,8 @@ case class SpendingInfoDAO()(implicit case (Some(utxo), Some(spk)) => utxo.toSpendingInfoDb(spk.scriptPubKey) case _ => throw new SQLException( - s"Unexpected result: Cannot update either a UTXO or a SPK record for $si") + s"Unexpected result: Cannot update either a UTXO or a SPK record for $si" + ) } } @@ -187,14 +194,17 @@ case class SpendingInfoDAO()(implicit _ <- spkOpt match { case Some(foundSpk) => table.insertOrUpdate( - UTXORecord.fromSpendingInfoDb(si, foundSpk.id.get)) + UTXORecord.fromSpendingInfoDb(si, foundSpk.id.get) + ) case None => (for { newSpkId <- (spkTable returning spkTable.map(_.id)) += ScriptPubKeyDb( - si.output.scriptPubKey) + si.output.scriptPubKey + ) } yield table.insertOrUpdate( - UTXORecord.fromSpendingInfoDb(si, newSpkId))).flatten + UTXORecord.fromSpendingInfoDb(si, newSpkId) + )).flatten } utxo <- table.filter(_.outPoint === si.outPoint).result.headOption spk <- @@ -209,7 +219,8 @@ case class SpendingInfoDAO()(implicit case (Some(utxo), Some(spk)) => utxo.toSpendingInfoDb(spk.scriptPubKey) case _ => throw new SQLException( - s"Unexpected result: Cannot upsert either a UTXO or a SPK record for $si") + s"Unexpected result: Cannot upsert either a UTXO or a SPK record for $si" + ) } } @@ -219,21 +230,21 @@ case class SpendingInfoDAO()(implicit } def deleteAction( - si: SpendingInfoDb): DBIOAction[Int, NoStream, Effect.Write] = { + si: SpendingInfoDb + ): DBIOAction[Int, NoStream, Effect.Write] = { deleteSpendingInfoDbAllAction(Vector(si)) } def deleteSpendingInfoDbAllAction( - sis: Vector[SpendingInfoDb]): DBIOAction[Int, NoStream, Effect.Write] = { + sis: Vector[SpendingInfoDb] + ): DBIOAction[Int, NoStream, Effect.Write] = { val ids = sis.map(_.id).flatten val query = table.filter(t => t.id.inSet(ids)) query.delete } - def findAllSpendingInfosAction(): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + def findAllSpendingInfosAction() + : DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { for { all <- findAllAction() utxos <- utxoToInfoAction(all) @@ -246,8 +257,7 @@ case class SpendingInfoDAO()(implicit utxos <- utxoToInfo(all) } yield utxos - /** Fetches all the received TXOs in our DB that are in - * the given TX + /** Fetches all the received TXOs in our DB that are in the given TX */ def findTx(tx: Transaction): Future[Vector[SpendingInfoDb]] = findTxs(Vector(tx)) @@ -258,22 +268,21 @@ case class SpendingInfoDAO()(implicit } /** Fetches all received txos in our db that are in the given txs */ - def findTxsAction(txs: Vector[Transaction]): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + def findTxsAction( + txs: Vector[Transaction] + ): DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { findOutputsReceivedAction(txs.map(_.txIdBE)) } - def findTxAction(tx: Transaction): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + def findTxAction( + tx: Transaction + ): DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { findTxsAction(Vector(tx)) } - private def _findOutputsBeingSpentQuery(txs: Vector[Transaction]): Vector[ - Query[SpendingInfoTable, UTXORecord, Seq]] = { + private def _findOutputsBeingSpentQuery( + txs: Vector[Transaction] + ): Vector[Query[SpendingInfoTable, UTXORecord, Seq]] = { val outPoints: Vector[TransactionOutPoint] = txs .flatMap(_.inputs) .map(_.previousOutput) @@ -287,44 +296,46 @@ case class SpendingInfoDAO()(implicit queries.toVector } - /** Finds all the outputs being spent in the given - * transaction + /** Finds all the outputs being spent in the given transaction */ def findOutputsBeingSpent(tx: Transaction): Future[Vector[SpendingInfoDb]] = { findOutputsBeingSpent(Vector(tx)) } private def findOutputsBeingSpentQuery( - txs: Vector[Transaction]): Vector[Query[ + txs: Vector[Transaction] + ): Vector[Query[ (SpendingInfoTable, ScriptPubKeyDAO#ScriptPubKeyTable), (UTXORecord, ScriptPubKeyDAO#ScriptPubKeyTable#TableElementType), - Seq]] = { + Seq + ]] = { _findOutputsBeingSpentQuery(txs).map { query => query.join(spkTable).on(_.scriptPubKeyId === _.id) } } def findOutputsBeingSpent( - txs: Vector[Transaction]): Future[Vector[SpendingInfoDb]] = { + txs: Vector[Transaction] + ): Future[Vector[SpendingInfoDb]] = { val action = findOutputsBeingSpentAction(txs) safeDatabase.run(action) } - def findOutputsBeingSpentAction(txs: Vector[Transaction]): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + def findOutputsBeingSpentAction( + txs: Vector[Transaction] + ): DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { val queries = findOutputsBeingSpentQuery(txs) - val actions: Vector[DBIOAction[ - Vector[(UTXORecord, ScriptPubKeyDb)], - NoStream, - Effect.Read]] = { + val actions: Vector[ + DBIOAction[Vector[(UTXORecord, ScriptPubKeyDb)], NoStream, Effect.Read] + ] = { queries.map(_.result.map(_.toVector)) } - val action: DBIOAction[ - Vector[(UTXORecord, ScriptPubKeyDb)], - NoStream, - Effect.Read] = DBIO.sequence(actions).map(_.flatten.toVector) + val action: DBIOAction[Vector[ + (UTXORecord, ScriptPubKeyDb) + ], + NoStream, + Effect.Read] = + DBIO.sequence(actions).map(_.flatten.toVector) action.map(_.map { case (utxo, spk) => utxo.toSpendingInfoDb(spk.scriptPubKey) @@ -333,8 +344,9 @@ case class SpendingInfoDAO()(implicit /** Given a TXID, fetches all incoming TXOs and the address the TXO pays to */ - def withAddress(txid: DoubleSha256DigestBE): Future[ - Vector[(SpendingInfoDb, AddressDb)]] = { + def withAddress( + txid: DoubleSha256DigestBE + ): Future[Vector[(SpendingInfoDb, AddressDb)]] = { def _withAddress: Future[Vector[(UTXORecord, AddressRecord)]] = { val query = { val filtered = table.filter(_.txid === txid) @@ -350,14 +362,16 @@ case class SpendingInfoDAO()(implicit addrSpks <- findScriptPubKeys(res.map(_._2.scriptPubKeyId)) } yield { res.map(r => - (r._1.toSpendingInfoDb(utxoSpks(r._1.scriptPubKeyId).scriptPubKey), - r._2.toAddressDb(addrSpks(r._2.scriptPubKeyId).scriptPubKey))) + ( + r._1.toSpendingInfoDb(utxoSpks(r._1.scriptPubKeyId).scriptPubKey), + r._2.toAddressDb(addrSpks(r._2.scriptPubKeyId).scriptPubKey) + )) } } - /** Fetches all the incoming TXOs in our DB that are in - * the transaction with the given TXID + /** Fetches all the incoming TXOs in our DB that are in the transaction with + * the given TXID */ def findDbsForTx(txid: DoubleSha256DigestBE): Future[Vector[UTXORecord]] = { val query = table.filter(_.txid === txid) @@ -369,14 +383,12 @@ case class SpendingInfoDAO()(implicit .join(spkTable) .on(_.scriptPubKeyId === _.id) - /** Fetches all the incoming TXOs in our DB that are in - * the transaction with the given TXID + /** Fetches all the incoming TXOs in our DB that are in the transaction with + * the given TXID */ def findOutputsReceivedAction( - txids: Vector[DoubleSha256DigestBE]): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + txids: Vector[DoubleSha256DigestBE] + ): DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { spkJoinQuery .filter(_._1.state.inSet(TxoState.receivedStates)) .filter(_._1.txid.inSet(txids)) @@ -388,16 +400,18 @@ case class SpendingInfoDAO()(implicit .map(_.toVector) } - /** Fetches all the incoming TXOs in our DB that are in - * the transaction with the given TXID + /** Fetches all the incoming TXOs in our DB that are in the transaction with + * the given TXID */ def findOutputsReceived( - txids: Vector[DoubleSha256DigestBE]): Future[Vector[SpendingInfoDb]] = { + txids: Vector[DoubleSha256DigestBE] + ): Future[Vector[SpendingInfoDb]] = { safeDatabase.run(findOutputsReceivedAction(txids)) } def findByScriptPubKey( - scriptPubKey: ScriptPubKey): Future[Vector[SpendingInfoDb]] = { + scriptPubKey: ScriptPubKey + ): Future[Vector[SpendingInfoDb]] = { val filtered = spkJoinQuery.filter(_._2.scriptPubKey === scriptPubKey) safeDatabase .runVec(filtered.result) @@ -413,31 +427,30 @@ case class SpendingInfoDAO()(implicit } /** Enumerates all unspent TX outputs in the wallet with the state - * [[TxoState.PendingConfirmationsReceived]] or [[TxoState.ConfirmedReceived]] + * [[TxoState.PendingConfirmationsReceived]] or + * [[TxoState.ConfirmedReceived]] */ def _findAllUnspent(): Future[Vector[UTXORecord]] = { safeDatabase.run(_findAllUnspentAction()) } /** Enumerates all unspent TX outputs in the wallet with the state - * [[TxoState.PendingConfirmationsReceived]] or [[TxoState.ConfirmedReceived]] + * [[TxoState.PendingConfirmationsReceived]] or + * [[TxoState.ConfirmedReceived]] */ - def _findAllUnspentAction(): DBIOAction[ - Vector[UTXORecord], - NoStream, - Effect.Read] = _findByStateAction(TxoState.receivedStates.toVector) + def _findAllUnspentAction() + : DBIOAction[Vector[UTXORecord], NoStream, Effect.Read] = + _findByStateAction(TxoState.receivedStates.toVector) - def _findByStateAction(states: Vector[TxoState]): DBIOAction[ - Vector[UTXORecord], - NoStream, - Effect.Read] = { + def _findByStateAction( + states: Vector[TxoState] + ): DBIOAction[Vector[UTXORecord], NoStream, Effect.Read] = { table.filter(_.state.inSet(states)).result.map(_.toVector) } - def utxoToInfoAction(utxos: Vector[UTXORecord]): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + def utxoToInfoAction( + utxos: Vector[UTXORecord] + ): DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { for { spks <- findScriptPubKeysAction(utxos) } yield utxos.map(utxo => @@ -460,20 +473,17 @@ case class SpendingInfoDAO()(implicit safeDatabase.run(findAllUnspentAction()) } - def findAllUnspentAction(): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + def findAllUnspentAction() + : DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { for { utxos <- _findAllUnspentAction() infos <- utxoToInfoAction(utxos) } yield infos } - def getBalanceAction(accountOpt: Option[HDAccount] = None): DBIOAction[ - CurrencyUnit, - NoStream, - Effect.Read] = { + def getBalanceAction( + accountOpt: Option[HDAccount] = None + ): DBIOAction[CurrencyUnit, NoStream, Effect.Read] = { val account = accountOpt.getOrElse(appConfig.defaultAccount) for { utxos <- _findAllUnspentAction() @@ -482,8 +492,9 @@ case class SpendingInfoDAO()(implicit } yield forAccount.map(_.output.value).sum } - def getConfirmedBalanceAction(accountOpt: Option[HDAccount] = - None): DBIOAction[CurrencyUnit, NoStream, Effect.Read] = { + def getConfirmedBalanceAction( + accountOpt: Option[HDAccount] = None + ): DBIOAction[CurrencyUnit, NoStream, Effect.Read] = { val account = accountOpt.getOrElse(appConfig.defaultAccount) for { utxos <- _findByStateAction(Vector(TxoState.ConfirmedReceived)) @@ -492,8 +503,9 @@ case class SpendingInfoDAO()(implicit } yield forAccount.map(_.output.value).sum } - def getUnconfirmedBalanceAction(accountOpt: Option[HDAccount] = - None): DBIOAction[CurrencyUnit, NoStream, Effect.Read] = { + def getUnconfirmedBalanceAction( + accountOpt: Option[HDAccount] = None + ): DBIOAction[CurrencyUnit, NoStream, Effect.Read] = { val account = accountOpt.getOrElse(appConfig.defaultAccount) for { utxos <- _findByStateAction(TxoState.pendingReceivedStates.toVector) @@ -504,7 +516,8 @@ case class SpendingInfoDAO()(implicit private def filterUtxosByAccount( utxos: Vector[SpendingInfoDb], - hdAccount: HDAccount): Vector[SpendingInfoDb] = { + hdAccount: HDAccount + ): Vector[SpendingInfoDb] = { utxos.filter(utxo => HDAccount.isSameAccount(bip32Path = utxo.privKeyPath, account = hdAccount)) @@ -512,28 +525,28 @@ case class SpendingInfoDAO()(implicit /** Finds all utxos for a given account */ def findAllUnspentForAccount( - hdAccount: HDAccount): Future[Vector[SpendingInfoDb]] = { + hdAccount: HDAccount + ): Future[Vector[SpendingInfoDb]] = { val allUtxosF = findAllUnspent() allUtxosF.map(filterUtxosByAccount(_, hdAccount)) } - def findAllUnspentForAccountAction(hdAccount: HDAccount): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + def findAllUnspentForAccountAction( + hdAccount: HDAccount + ): DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { val allUtxosA = findAllUnspentAction() allUtxosA.map(filterUtxosByAccount(_, hdAccount)) } - def findAllForAccountAction(hdAccount: HDAccount): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + def findAllForAccountAction( + hdAccount: HDAccount + ): DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { findAllSpendingInfosAction().map(filterUtxosByAccount(_, hdAccount)) } def findAllForAccount( - hdAccount: HDAccount): Future[Vector[SpendingInfoDb]] = { + hdAccount: HDAccount + ): Future[Vector[SpendingInfoDb]] = { val action = findAllForAccountAction(hdAccount) safeDatabase.run(action) } @@ -553,7 +566,8 @@ case class SpendingInfoDAO()(implicit } /** Enumerates all TX outputs in the wallet with the state - * [[TxoState.PendingConfirmationsReceived]] or [[TxoState.PendingConfirmationsSpent]] + * [[TxoState.PendingConfirmationsReceived]] or + * [[TxoState.PendingConfirmationsSpent]] */ def findAllPendingConfirmation: Future[Vector[SpendingInfoDb]] = { val query = table @@ -593,13 +607,15 @@ case class SpendingInfoDAO()(implicit } def findByOutPoint( - outPoint: TransactionOutPoint): Future[Option[SpendingInfoDb]] = { + outPoint: TransactionOutPoint + ): Future[Option[SpendingInfoDb]] = { findByOutPoints(Vector(outPoint)).map(_.headOption) } /** Enumerates all TX outpoints in the wallet */ - def findByOutPoints(outPoints: Vector[TransactionOutPoint]): Future[ - Vector[SpendingInfoDb]] = { + def findByOutPoints( + outPoints: Vector[TransactionOutPoint] + ): Future[Vector[SpendingInfoDb]] = { val query = table .join(spkTable) .on(_.scriptPubKeyId === _.id) @@ -612,10 +628,9 @@ case class SpendingInfoDAO()(implicit }) } - def findAllUnspentForTagAction(tag: AddressTag): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read] = { + def findAllUnspentForTagAction( + tag: AddressTag + ): DBIOAction[Vector[SpendingInfoDb], NoStream, Effect.Read] = { table .join(spkTable) .on(_.scriptPubKeyId === _.id) @@ -637,25 +652,28 @@ case class SpendingInfoDAO()(implicit safeDatabase.run(findAllUnspentForTagAction(tag)) } - def markAsReservedAction(ts: Vector[SpendingInfoDb]): DBIOAction[ - Vector[SpendingInfoDb], - NoStream, - Effect.Read with Effect.Write] = { - //1. Check if any are reserved already - //2. if not, reserve them - //3. if they are reserved, throw an exception? + def markAsReservedAction( + ts: Vector[SpendingInfoDb]): DBIOAction[Vector[ + SpendingInfoDb + ], + NoStream, + Effect.Read with Effect.Write] = { + // 1. Check if any are reserved already + // 2. if not, reserve them + // 3. if they are reserved, throw an exception? val outPoints = ts.map(_.outPoint) table .filter(_.outPoint.inSet(outPoints)) .filter( _.state.inSet(TxoState.receivedStates) - ) //must be available to reserve + ) // must be available to reserve .map(_.state) .update(TxoState.Reserved) .flatMap { count => if (count != ts.length) { val exn = new RuntimeException( - s"Failed to reserve all utxos, expected=${ts.length} actual=$count") + s"Failed to reserve all utxos, expected=${ts.length} actual=$count" + ) DBIO.failed(exn) } else { DBIO.successful(count) @@ -665,20 +683,21 @@ case class SpendingInfoDAO()(implicit } def markAsReserved( - ts: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = { + ts: Vector[SpendingInfoDb] + ): Future[Vector[SpendingInfoDb]] = { safeDatabase.run(markAsReservedAction(ts)) } def hasDuplicates(): Future[Boolean] = FutureUtil.makeAsync { () => withStatement( - s"SELECT EXISTS (SELECT tx_outpoint, COUNT(*) FROM $fullTableName GROUP BY tx_outpoint HAVING COUNT(*) > 1)") { - st => - val rs = st.executeQuery() - try { - if (rs.next()) { - rs.getBoolean(1) - } else false - } finally rs.close() + s"SELECT EXISTS (SELECT tx_outpoint, COUNT(*) FROM $fullTableName GROUP BY tx_outpoint HAVING COUNT(*) > 1)" + ) { st => + val rs = st.executeQuery() + try { + if (rs.next()) { + rs.getBoolean(1) + } else false + } finally rs.close() } } @@ -706,10 +725,9 @@ case class SpendingInfoDAO()(implicit } } - private def findScriptPubKeysAction(ids: Seq[Long]): DBIOAction[ - Map[Long, ScriptPubKeyDb], - NoStream, - Effect.Read] = { + private def findScriptPubKeysAction( + ids: Seq[Long] + ): DBIOAction[Map[Long, ScriptPubKeyDb], NoStream, Effect.Read] = { val query = spkTable.filter(t => t.id.inSet(ids)) query.result.map { action => action.map { case spk => @@ -719,27 +737,29 @@ case class SpendingInfoDAO()(implicit } private def findScriptPubKeys( - ids: Seq[Long]): Future[Map[Long, ScriptPubKeyDb]] = { + ids: Seq[Long] + ): Future[Map[Long, ScriptPubKeyDb]] = { val action = findScriptPubKeysAction(ids) safeDatabase.run(action) } - private def findScriptPubKeysAction(utxos: Vector[UTXORecord]): DBIOAction[ - Map[Long, ScriptPubKeyDb], - NoStream, - Effect.Read] = { + private def findScriptPubKeysAction( + utxos: Vector[UTXORecord] + ): DBIOAction[Map[Long, ScriptPubKeyDb], NoStream, Effect.Read] = { val ids = utxos.map(_.scriptPubKeyId) findScriptPubKeysAction(ids) } private def findScriptPubKeysByUtxos( - utxos: Vector[UTXORecord]): Future[Map[Long, ScriptPubKeyDb]] = { + utxos: Vector[UTXORecord] + ): Future[Map[Long, ScriptPubKeyDb]] = { val action = findScriptPubKeysAction(utxos) safeDatabase.run(action) } private def findPublicKeyScriptsBySpendingInfoDb( - spendingInfoDbs: Seq[SpendingInfoDb]): Future[Map[ScriptPubKey, Long]] = { + spendingInfoDbs: Seq[SpendingInfoDb] + ): Future[Map[ScriptPubKey, Long]] = { val spks = spendingInfoDbs.map(_.output.scriptPubKey) val query = spkTable.filter(t => t.scriptPubKey.inSet(spks)) safeDatabase @@ -747,11 +767,10 @@ case class SpendingInfoDAO()(implicit .map(_.map(spk => (spk.scriptPubKey, spk.id.get)).toMap) } - /** This table stores the necessary information to spend - * a transaction output (TXO) at a later point in time. It - * also stores how many confirmations it has, whether - * or not it is spent (i.e. if it is a UTXO or not) and the - * TXID of the transaction that created this output. + /** This table stores the necessary information to spend a transaction output + * (TXO) at a later point in time. It also stores how many confirmations it + * has, whether or not it is spent (i.e. if it is a UTXO or not) and the TXID + * of the transaction that created this output. */ case class SpendingInfoTable(tag: Tag) extends TableAutoInc[UTXORecord](tag, schemaName, "txo_spending_info") { @@ -775,23 +794,27 @@ case class SpendingInfoDAO()(implicit def scriptWitnessOpt: Rep[Option[ScriptWitness]] = column("script_witness") def spendingTxIdOpt: Rep[Option[DoubleSha256DigestBE]] = column( - "spending_txid") + "spending_txid" + ) /** All UTXOs must have a SPK in the wallet that gets spent to */ def fk_scriptPubKeyId: slick.lifted.ForeignKeyQuery[_, ScriptPubKeyDb] = { val scriptPubKeyTable = spkTable - foreignKey("fk_scriptPubKeyId", - sourceColumns = scriptPubKeyId, - targetTableQuery = scriptPubKeyTable)(_.id) + foreignKey( + "fk_scriptPubKeyId", + sourceColumns = scriptPubKeyId, + targetTableQuery = scriptPubKeyTable + )(_.id) } /** All UTXOs must have a corresponding transaction in the wallet */ - def fk_incoming_txId: slick.lifted.ForeignKeyQuery[ - _, - IncomingTransactionDb] = { - foreignKey("fk_incoming_txId", - sourceColumns = txid, - targetTableQuery = txTable)(_.txIdBE) + def fk_incoming_txId + : slick.lifted.ForeignKeyQuery[_, IncomingTransactionDb] = { + foreignKey( + "fk_incoming_txId", + sourceColumns = txid, + targetTableQuery = txTable + )(_.txIdBE) } private val fromTuple: ( @@ -805,8 +828,11 @@ case class SpendingInfoDAO()(implicit Option[ScriptPubKey], Option[ScriptWitness], Option[DoubleSha256DigestBE], - Option[Long])) => UTXORecord = { - case (outpoint, + Option[Long] + ) + ) => UTXORecord = { + case ( + outpoint, _, state, scriptPubKeyId, @@ -815,16 +841,19 @@ case class SpendingInfoDAO()(implicit redeemScriptOpt, scriptWitOpt, spendingTxIdOpt, - idOpt) => - UTXORecord(outpoint, - state, - scriptPubKeyId, - value, - path, - redeemScriptOpt, - scriptWitOpt, - spendingTxIdOpt, - idOpt) + idOpt + ) => + UTXORecord( + outpoint, + state, + scriptPubKeyId, + value, + path, + redeemScriptOpt, + scriptWitOpt, + spendingTxIdOpt, + idOpt + ) } private val toTuple: UTXORecord => Option[ @@ -838,31 +867,38 @@ case class SpendingInfoDAO()(implicit Option[ScriptPubKey], Option[ScriptWitness], Option[DoubleSha256DigestBE], - Option[Long])] = { case utxo: UTXORecord => + Option[Long] + ) + ] = { case utxo: UTXORecord => Some( - (utxo.outpoint, - utxo.outpoint.txIdBE, - utxo.state, - utxo.scriptPubKeyId, - utxo.value, - utxo.path, - utxo.redeemScript, - utxo.scriptWitness, - utxo.spendingTxIdOpt, - utxo.id)) + ( + utxo.outpoint, + utxo.outpoint.txIdBE, + utxo.state, + utxo.scriptPubKeyId, + utxo.value, + utxo.path, + utxo.redeemScript, + utxo.scriptWitness, + utxo.spendingTxIdOpt, + utxo.id + ) + ) } override def * = { - (outPoint, - txid, - state, - scriptPubKeyId, - value, - privKeyPath, - redeemScriptOpt, - scriptWitnessOpt, - spendingTxIdOpt, - id.?).<>(fromTuple, toTuple) + ( + outPoint, + txid, + state, + scriptPubKeyId, + value, + privKeyPath, + redeemScriptOpt, + scriptWitnessOpt, + spendingTxIdOpt, + id.? + ).<>(fromTuple, toTuple) } } } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/TransactionDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/TransactionDAO.scala index 551649da64..5e509852d7 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/TransactionDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/TransactionDAO.scala @@ -18,8 +18,8 @@ trait TxCRUDComponent[DbEntryType <: TxDB] { abstract class TxTable[DbEntryType <: TxDB]( tag: profile.api.Tag, schemaName: Option[String], - tableName: String) - extends Table[DbEntryType](tag, schemaName, tableName) { + tableName: String + ) extends Table[DbEntryType](tag, schemaName, tableName) { def txIdBE: Rep[DoubleSha256DigestBE] } } @@ -41,39 +41,44 @@ trait TxDAO[DbEntryType <: TxDB] createAllNoAutoInc(ts, safeDatabase) override def findByPrimaryKeys( - txIdBEs: Vector[DoubleSha256DigestBE]): Query[DbTable, DbEntryType, Seq] = + txIdBEs: Vector[DoubleSha256DigestBE] + ): Query[DbTable, DbEntryType, Seq] = table.filter(_.txIdBE.inSet(txIdBEs)) override def findByPrimaryKey( - txIdBE: DoubleSha256DigestBE): Query[DbTable, DbEntryType, Seq] = { + txIdBE: DoubleSha256DigestBE + ): Query[DbTable, DbEntryType, Seq] = { table.filter(_.txIdBE === txIdBE) } override def findAll( - txs: Vector[DbEntryType]): Query[DbTable, DbEntryType, Seq] = + txs: Vector[DbEntryType] + ): Query[DbTable, DbEntryType, Seq] = findByPrimaryKeys(txs.map(_.txIdBE)) def findByOutPoint( - outPoint: TransactionOutPoint): Future[Option[DbEntryType]] = { + outPoint: TransactionOutPoint + ): Future[Option[DbEntryType]] = { findByTxId(outPoint.txId) } def findByOutPoints( - outPoints: Vector[TransactionOutPoint]): Future[Vector[DbEntryType]] = { + outPoints: Vector[TransactionOutPoint] + ): Future[Vector[DbEntryType]] = { findByTxIds(outPoints.map(_.txIdBE)) } def findByTxIds( - txIdBEs: Vector[DoubleSha256DigestBE]): Future[Vector[DbEntryType]] = { + txIdBEs: Vector[DoubleSha256DigestBE] + ): Future[Vector[DbEntryType]] = { val q = table.filter(_.txIdBE.inSet(txIdBEs)) safeDatabase.runVec(q.result) } - def findByTxIdAction(txIdBE: DoubleSha256DigestBE): DBIOAction[ - Option[DbEntryType], - NoStream, - Effect.Read] = { + def findByTxIdAction( + txIdBE: DoubleSha256DigestBE + ): DBIOAction[Option[DbEntryType], NoStream, Effect.Read] = { table .filter(_.txIdBE === txIdBE) .result @@ -85,7 +90,8 @@ trait TxDAO[DbEntryType <: TxDB] case txs: Vector[DbEntryType] => // yikes, we should not have more the one transaction per id throw new RuntimeException( - s"More than one transaction per id=${txIdBE.hex}, got=$txs") + s"More than one transaction per id=${txIdBE.hex}, got=$txs" + ) } } @@ -97,15 +103,16 @@ trait TxDAO[DbEntryType <: TxDB] findByTxId(txId.flip) def findByTxIdBEs( - txIdBEs: Vector[DoubleSha256DigestBE]): Future[Vector[DbEntryType]] = { + txIdBEs: Vector[DoubleSha256DigestBE] + ): Future[Vector[DbEntryType]] = { safeDatabase.run(findByPrimaryKeys(txIdBEs).result).map(_.toVector) } } case class TransactionDAO()(implicit override val ec: ExecutionContext, - override val appConfig: WalletAppConfig) - extends TxDAO[TransactionDb] { + override val appConfig: WalletAppConfig +) extends TxDAO[TransactionDb] { import profile.api._ private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -150,16 +157,18 @@ case class TransactionDAO()(implicit def blockHash: Rep[Option[DoubleSha256DigestBE]] = column("block_hash") def * : ProvenShape[TransactionDb] = - (txIdBE, - transaction, - unsignedTxIdBE, - unsignedTx, - wTxIdBEOpt, - totalOutput, - numInputs, - numOutputs, - locktime, - blockHash).<>(TransactionDb.tupled, TransactionDb.unapply) + ( + txIdBE, + transaction, + unsignedTxIdBE, + unsignedTx, + wTxIdBEOpt, + totalOutput, + numInputs, + numOutputs, + locktime, + blockHash + ).<>(TransactionDb.tupled, TransactionDb.unapply) def primaryKey: PrimaryKey = primaryKey("pk_tx", sourceColumns = txIdBE) diff --git a/wallet/src/main/scala/org/bitcoins/wallet/models/WalletStateDescriptorDAO.scala b/wallet/src/main/scala/org/bitcoins/wallet/models/WalletStateDescriptorDAO.scala index f62ad67576..4f927c257b 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/models/WalletStateDescriptorDAO.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/models/WalletStateDescriptorDAO.scala @@ -19,14 +19,15 @@ import scala.concurrent.{ExecutionContext, Future} case class WalletStateDescriptorDb( tpe: WalletStateDescriptorType, - descriptor: WalletStateDescriptor) { + descriptor: WalletStateDescriptor +) { require(descriptor.descriptorType == tpe) } case class WalletStateDescriptorDAO()(implicit override val ec: ExecutionContext, - override val appConfig: WalletAppConfig) - extends CRUD[WalletStateDescriptorDb, WalletStateDescriptorType] + override val appConfig: WalletAppConfig +) extends CRUD[WalletStateDescriptorDb, WalletStateDescriptorType] with SlickUtil[WalletStateDescriptorDb, WalletStateDescriptorType] { import profile.api._ private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile) @@ -35,28 +36,26 @@ case class WalletStateDescriptorDAO()(implicit override val table: profile.api.TableQuery[WalletStateDescriptorTable] = TableQuery[WalletStateDescriptorTable] - override def createAll(ts: Vector[WalletStateDescriptorDb]): Future[ - Vector[WalletStateDescriptorDb]] = + override def createAll( + ts: Vector[WalletStateDescriptorDb] + ): Future[Vector[WalletStateDescriptorDb]] = createAllNoAutoInc(ts, safeDatabase) - override def findByPrimaryKeys(ids: Vector[WalletStateDescriptorType]): Query[ - WalletStateDescriptorTable, - WalletStateDescriptorDb, - Seq] = { + override def findByPrimaryKeys( + ids: Vector[WalletStateDescriptorType] + ): Query[WalletStateDescriptorTable, WalletStateDescriptorDb, Seq] = { table.filter(_.tpe.inSet(ids)) } - override def findByPrimaryKey(id: WalletStateDescriptorType): Query[ - Table[WalletStateDescriptorDb], - WalletStateDescriptorDb, - Seq] = { + override def findByPrimaryKey( + id: WalletStateDescriptorType + ): Query[Table[WalletStateDescriptorDb], WalletStateDescriptorDb, Seq] = { table.filter(_.tpe === id) } - override def findAll(ts: Vector[WalletStateDescriptorDb]): Query[ - Table[WalletStateDescriptorDb], - WalletStateDescriptorDb, - Seq] = + override def findAll( + ts: Vector[WalletStateDescriptorDb] + ): Query[Table[WalletStateDescriptorDb], WalletStateDescriptorDb, Seq] = findByPrimaryKeys(ts.map(_.tpe)) def getSyncHeight(): Future[Option[SyncHeightDescriptor]] = { @@ -70,7 +69,8 @@ case class WalletStateDescriptorDAO()(implicit def updateSyncHeight( hash: DoubleSha256DigestBE, - height: Int): Future[WalletStateDescriptorDb] = { + height: Int + ): Future[WalletStateDescriptorDb] = { val tpe: WalletStateDescriptorType = SyncHeight val query = table.filter(_.tpe === tpe) val action = for { @@ -112,7 +112,8 @@ case class WalletStateDescriptorDAO()(implicit def compareAndSetRescanning( expectedValue: Boolean, - newValue: Boolean): Future[Boolean] = { + newValue: Boolean + ): Future[Boolean] = { val tpe: WalletStateDescriptorType = Rescan val query = table.filter(_.tpe === tpe) @@ -139,17 +140,21 @@ case class WalletStateDescriptorDAO()(implicit } class WalletStateDescriptorTable(t: Tag) - extends Table[WalletStateDescriptorDb](t, - schemaName, - "state_descriptors") { + extends Table[WalletStateDescriptorDb]( + t, + schemaName, + "state_descriptors" + ) { def tpe: Rep[WalletStateDescriptorType] = column("type", O.PrimaryKey) def descriptor: Rep[WalletStateDescriptor] = column("descriptor") override def * : ProvenShape[WalletStateDescriptorDb] = - (tpe, descriptor).<>(WalletStateDescriptorDb.tupled, - WalletStateDescriptorDb.unapply) + (tpe, descriptor).<>( + WalletStateDescriptorDb.tupled, + WalletStateDescriptorDb.unapply + ) } } diff --git a/wallet/src/main/scala/org/bitcoins/wallet/sync/WalletSync.scala b/wallet/src/main/scala/org/bitcoins/wallet/sync/WalletSync.scala index bb02e16ed6..9fdf66e43f 100644 --- a/wallet/src/main/scala/org/bitcoins/wallet/sync/WalletSync.scala +++ b/wallet/src/main/scala/org/bitcoins/wallet/sync/WalletSync.scala @@ -10,19 +10,19 @@ import scala.concurrent.{ExecutionContext, Future} trait WalletSync extends BitcoinSLogger { - /** Synchronizes the bitcoin-s' wallet by retrieving each block and then calling - * [[Wallet.processBlock()]] on the block retrieved + /** Synchronizes the bitcoin-s' wallet by retrieving each block and then + * calling [[Wallet.processBlock()]] on the block retrieved * - * WARNING: This should not be used on resource constrained devices - * as fetching full blocks will use a lot of bandwidth on live networks + * WARNING: This should not be used on resource constrained devices as + * fetching full blocks will use a lot of bandwidth on live networks */ def syncFullBlocks( wallet: WalletApi, getBlockHeaderFunc: DoubleSha256DigestBE => Future[BlockHeader], getBestBlockHashFunc: () => Future[DoubleSha256DigestBE], getBlockFunc: DoubleSha256DigestBE => Future[Block], - genesisBlockHashBE: DoubleSha256DigestBE)(implicit - ec: ExecutionContext): Future[WalletApi] = { + genesisBlockHashBE: DoubleSha256DigestBE + )(implicit ec: ExecutionContext): Future[WalletApi] = { val bestBlockHashF = getBestBlockHashFunc() val bestBlockHeaderF = for { bestBlockHash <- bestBlockHashF @@ -31,11 +31,13 @@ trait WalletSync extends BitcoinSLogger { val blocksToSyncF = for { bestHeader <- bestBlockHeaderF - blocksToSync <- getBlocksToSync(wallet = wallet, - currentTipBlockHashBE = bestHeader.hashBE, - accum = Vector.empty, - getBlock = getBlockFunc, - genesisBlockHashBE = genesisBlockHashBE) + blocksToSync <- getBlocksToSync( + wallet = wallet, + currentTipBlockHashBE = bestHeader.hashBE, + accum = Vector.empty, + getBlock = getBlockFunc, + genesisBlockHashBE = genesisBlockHashBE + ) } yield blocksToSync val syncedWalletF = for { @@ -49,14 +51,16 @@ trait WalletSync extends BitcoinSLogger { syncedWalletF } - /** Syncs the wallet by walking backwards from the currentTip until we reach our wallet's best blockHash */ + /** Syncs the wallet by walking backwards from the currentTip until we reach + * our wallet's best blockHash + */ private def getBlocksToSync( wallet: WalletApi, currentTipBlockHashBE: DoubleSha256DigestBE, accum: Vector[Block], getBlock: DoubleSha256DigestBE => Future[Block], - genesisBlockHashBE: DoubleSha256DigestBE)(implicit - ec: ExecutionContext): Future[Vector[Block]] = { + genesisBlockHashBE: DoubleSha256DigestBE + )(implicit ec: ExecutionContext): Future[Vector[Block]] = { val initSyncDescriptorOptF = wallet.getSyncDescriptorOpt() for { syncDescriptorOpt <- initSyncDescriptorOptF @@ -77,7 +81,7 @@ trait WalletSync extends BitcoinSLogger { blocks <- { currentBlockOpt match { case Some(currentBlock) => - //loop again as we need to keep syncing + // loop again as we need to keep syncing getBlocksToSync( wallet = wallet, currentTipBlockHashBE = @@ -87,7 +91,7 @@ trait WalletSync extends BitcoinSLogger { genesisBlockHashBE = genesisBlockHashBE ) case None => - //yay! Done syncing, return all blocks our wallet needs to be synced with + // yay! Done syncing, return all blocks our wallet needs to be synced with Future.successful(accum) } } diff --git a/wallet/src/main/scala/postgresql/wallet/migration/V15__compute_spk_hashes.scala b/wallet/src/main/scala/postgresql/wallet/migration/V15__compute_spk_hashes.scala index 239deb34c8..2b40536d87 100644 --- a/wallet/src/main/scala/postgresql/wallet/migration/V15__compute_spk_hashes.scala +++ b/wallet/src/main/scala/postgresql/wallet/migration/V15__compute_spk_hashes.scala @@ -10,14 +10,16 @@ class V15__compute_spk_hashes extends BaseJavaMigration { val selectStatement = context.getConnection.createStatement() try { val rows = selectStatement.executeQuery( - "SELECT id, script_pub_key FROM pub_key_scripts") + "SELECT id, script_pub_key FROM pub_key_scripts" + ) while (rows.next()) { val id = rows.getLong(1) val hex = rows.getString(2) val spk = ScriptPubKey(hex) val hash = ScriptPubKeyDb.hash(spk) val updateStatement = context.getConnection.prepareStatement( - "UPDATE pub_key_scripts SET hash=? WHERE id=?") + "UPDATE pub_key_scripts SET hash=? WHERE id=?" + ) updateStatement.setString(1, hash.hex) updateStatement.setLong(2, id) try { diff --git a/wallet/src/main/scala/sqlite/wallet/migration/V14__compute_spk_hashes.scala b/wallet/src/main/scala/sqlite/wallet/migration/V14__compute_spk_hashes.scala index 6a5ef39347..5e5a3cc0cb 100644 --- a/wallet/src/main/scala/sqlite/wallet/migration/V14__compute_spk_hashes.scala +++ b/wallet/src/main/scala/sqlite/wallet/migration/V14__compute_spk_hashes.scala @@ -10,14 +10,16 @@ class V14__compute_spk_hashes extends BaseJavaMigration { val selectStatement = context.getConnection.createStatement() try { val rows = selectStatement.executeQuery( - "SELECT id, script_pub_key FROM pub_key_scripts") + "SELECT id, script_pub_key FROM pub_key_scripts" + ) while (rows.next()) { val id = rows.getLong(1) val hex = rows.getString(2) val spk = ScriptPubKey(hex) val hash = ScriptPubKeyDb.hash(spk) val updateStatement = context.getConnection.prepareStatement( - "UPDATE pub_key_scripts SET hash=? WHERE id=?") + "UPDATE pub_key_scripts SET hash=? WHERE id=?" + ) updateStatement.setString(1, hash.hex) updateStatement.setLong(2, id) try { diff --git a/zmq/src/main/scala/org/bitcoins/zmq/ZMQNotification.scala b/zmq/src/main/scala/org/bitcoins/zmq/ZMQNotification.scala index a1223a713f..2c6b8f35cb 100644 --- a/zmq/src/main/scala/org/bitcoins/zmq/ZMQNotification.scala +++ b/zmq/src/main/scala/org/bitcoins/zmq/ZMQNotification.scala @@ -1,7 +1,7 @@ package org.bitcoins.zmq -/** Represents the various notifications we can subscribe - * to from a zmq publisher +/** Represents the various notifications we can subscribe to from a zmq + * publisher * [[https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md#usage]] */ sealed abstract class ZMQNotification { diff --git a/zmq/src/main/scala/org/bitcoins/zmq/ZMQSubscriber.scala b/zmq/src/main/scala/org/bitcoins/zmq/ZMQSubscriber.scala index b5c213bf87..913a2eaf4e 100644 --- a/zmq/src/main/scala/org/bitcoins/zmq/ZMQSubscriber.scala +++ b/zmq/src/main/scala/org/bitcoins/zmq/ZMQSubscriber.scala @@ -10,9 +10,9 @@ import scodec.bits.ByteVector import java.net.InetSocketAddress -/** This class is designed to consume a zmq stream from a cryptocurrency's daemon. - * An example of this is bitcoind. For information on how to setup your coin's conf - * file to be able to consume a zmq stream please see +/** This class is designed to consume a zmq stream from a cryptocurrency's + * daemon. An example of this is bitcoind. For information on how to setup your + * coin's conf file to be able to consume a zmq stream please see * [[https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md#usage]] * [[http://zguide.zeromq.org/java:psenvsub]] * @param socket @@ -26,8 +26,8 @@ class ZMQSubscriber( hashTxListener: Option[DoubleSha256DigestBE => Unit], hashBlockListener: Option[DoubleSha256DigestBE => Unit], rawTxListener: Option[Transaction => Unit], - rawBlockListener: Option[Block => Unit]) - extends BitcoinSLogger + rawBlockListener: Option[Block => Unit] +) extends BitcoinSLogger with StartStop[Unit] { private var isConnected = false @@ -58,7 +58,8 @@ class ZMQSubscriber( context.term() logger.error( s"Failed to terminate zmq context gracefully msg=${e.getMessage}", - e) + e + ) } } @@ -67,7 +68,7 @@ class ZMQSubscriber( private val subscriberThread = new Thread(SubscriberRunnable) subscriberThread.setName(s"ZMQSubscriber-thread-${System - .currentTimeMillis()}") + .currentTimeMillis()}") subscriberThread.setDaemon(true) override def start(): Unit = { @@ -110,9 +111,9 @@ class ZMQSubscriber( */ override def stop(): Unit = { logger.info(s"Stopping zmq") - //i think this could technically not work, because currently we are blocking - //on Zmsg.recvMsg in our while loop. If we don't get another message we won't - //be able toe evaluate the while loop again. Moving forward with this for now. + // i think this could technically not work, because currently we are blocking + // on Zmsg.recvMsg in our while loop. If we don't get another message we won't + // be able toe evaluate the while loop again. Moving forward with this for now. isConnected = false subscriber.close() context.term() @@ -120,8 +121,8 @@ class ZMQSubscriber( () } - /** Processes a message that we received the from the cryptocurrency daemon and then - * applies the appropriate listener to that message. + /** Processes a message that we received the from the cryptocurrency daemon + * and then applies the appropriate listener to that message. */ private def processMsg(topic: String, body: Array[Byte]): Unit = { val notification = ZMQNotification.fromString(topic) diff --git a/zmq/src/test/scala/org/bitcoins/zmq/ZMQSubscriberTest.scala b/zmq/src/test/scala/org/bitcoins/zmq/ZMQSubscriberTest.scala index 26514177df..57ef78f5ab 100644 --- a/zmq/src/test/scala/org/bitcoins/zmq/ZMQSubscriberTest.scala +++ b/zmq/src/test/scala/org/bitcoins/zmq/ZMQSubscriberTest.scala @@ -35,15 +35,15 @@ class ZMQSubscriberTest extends AsyncFlatSpec with BitcoinSLogger { } it must "connect to a regtest instance of a daemon and stream txs/blocks from it" in { - //note for this unit test to pass, you need to setup a bitcoind instance yourself - //and set the bitcoin.conf file to allow for - //zmq connections - //see: https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md + // note for this unit test to pass, you need to setup a bitcoind instance yourself + // and set the bitcoin.conf file to allow for + // zmq connections + // see: https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md val socket = new InetSocketAddress("127.0.0.1", 29000) val zmqSub = new ZMQSubscriber(socket, None, None, rawTxListener, rawBlockListener) - //stupid, doesn't test anything, for now. You need to look at log output to verify this is working + // stupid, doesn't test anything, for now. You need to look at log output to verify this is working // TODO: In the future this could use the testkit to verify the subscriber by calling generate(1) zmqSub.start() Thread.sleep(10000) // 10 seconds